/** * 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 } }, ], };