vue-todo/src/store.js

192 lines
4.8 KiB
JavaScript

/**
* Store.js - global app state.
*
* Part of the basebox sample TODO app.
* https://basebox.io
*/
import { reactive } from 'vue'
import {gqlRequest} from "./util/net";
export const store = reactive({
/** User display name of the currently logged-in user */
userDisplayName: "stranger",
/* Unique user id of the currently logged in user */
userId: "",
/** base URL of basebox broker host */
baseboxHost: import.meta.env.BASEBOX_HOST || "http://127.0.0.1:8080",
/** User as returned from oidc-client */
user: null,
/** Fatal error message, if any */
fatalError: "",
/* array of todo lists currently known */
lists: [],
/* known tasks */
tasks: [],
});
/**
* Return true if the user is logged in.
*/
export function loggedIn() {
return store.user !== null;
}
/**
* Clear session data.
*/
export function clearSession() {
store.user = null;
store.userDisplayName = "stranger";
}
/**
* Show an error.
*/
export function showError(message) {
store.fatalError = message;
}
/**
* Clear error.
*/
export function clearError() {
store.fatalError = "";
}
/**
* Remove a task from the store.
*
* This does not remove it from the database/server!
*/
export function removeTask(task) {
const idx = store.tasks.findIndex(item => item.id === task.id);
if (idx !== -1) {
store.tasks.splice(idx, 1);
}
}
/**
* Initialize data store and database.
*
* Must be called by the OAuth login completion handler as soon as session data is available.
*
* If this is the first run, we need to create the logged on user, since he/she is so far known
* only to the OpenID Connect server (Keycloak).
*
* Additionally, we also create the default list here and save everything in the store.
*
* @param user - the user as returned from oidc-client.
*/
export async function storeInit(user) {
/* save user session in the store */
store.user = user;
store.userDisplayName = user.profile.nickname || "Logged In Stranger";
/* The unique user ID is the 'sub' field from the ID token. */
store.userId = user.profile.sub;
/* Create user and default list.
* We cannot run these requests in parallel, since the user record must exist in the database
* before we can create the default list.
*/
try {
console.info("NOTE: If next request fails, it is probably because the user already exists. In this case, the error is ignored.");
await gqlRequest(`mutation {
createUser(
username: "${store.userId}",
name: "${store.userDisplayName}"
) {
username
}
}`);
} catch(e) {
const errStr = e.toString();
if (errStr.indexOf("already exists") === -1) {
/* this is an error */
const e = `Failed to create user: ${errStr}`;
console.error(e);
showError(e);
return;
}
}
/* Load user info, lists and todos. */
gqlRequest(`query {
getUser(username: "${store.userId}") {
name
lists {
id
title
}
tasks {
id
title
description
completed
list {
id
}
}
}
}`).then(data => {
store.lists = data.getUser.lists ? data.getUser.lists : [];
store.tasks = data.getUser.tasks ? data.getUser.tasks : [];
/* create default list if necessary */
if (store.lists.length === 0) {
console.info("No lists found for current user; creating default list.");
gqlRequest(`mutation {
createList(
title: "Default",
user: { username: "${store.userId}" }
) {
title
id
}
}`).then(data => {
/* Save new default list in store */
store.lists.push(data.createList);
});
}
/* fix for basebox bug: task.list is returned as an array of List objects, where we expect just a single object */
for (const task of store.tasks) {
if (Array.isArray(task.list)) {
task.list = task.list[0];
}
}
}).catch(err => {
const e = `Failed to load user/data: ${err.toString()}`;
console.error(e);
showError(e);
});
}
const testData = {
lists: [
{ id: 1, title: "Default"},
{ id: 2, title: "House" },
{ id: 3, title: "Car" },
{ id: 4, title: "Work" },
],
/* known tasks */
tasks: [
{ id: 1, completed: false, title: "Go to dentist", description: "Last time is way too long ago...", list: { id: 1 } },
{ id: 2, completed: true, title: "Change engine oil", description: "Use the good one", list: { id: 3 } },
{ id: 3, completed: false, title: "Clean windows", description: "Regualar stuff", list: { id: 1 } },
{ id: 4, completed: false, title: "Oil stove hinges", description: "They are stiff and screechy", list: { id: 2 } },
{ id: 5, completed: false, title: "Do more benchmarking", description: "Find out how fast this thing really is", list: { id: 4 } },
],
};