From ddf3fea3a8a0a84d3ce01b3aa7c0ffd2a276f8ab Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Thu, 29 Jun 2023 20:18:27 +0800 Subject: [PATCH 01/11] feat: Group and Admin Page Creation --- composables/group.ts | 114 +++++++++++++++- .../admin/add-rewards.vue} | 0 pages/dashboard/admin/groups.vue | 75 ++++++++++ pages/dashboard/admin/groups/[shortName].vue | 129 ++++++++++++++++++ pages/dashboard/admin/groups/index.vue | 99 ++++++++++++++ pages/dashboard/admin/index.vue | 68 +++++++++ pages/dashboard/admin/rewards.vue | 12 ++ pages/dashboard/index.vue | 12 ++ utils/api.ts | 7 + 9 files changed, 515 insertions(+), 1 deletion(-) rename pages/{dashboard.vue => dashboard/admin/add-rewards.vue} (100%) create mode 100644 pages/dashboard/admin/groups.vue create mode 100644 pages/dashboard/admin/groups/[shortName].vue create mode 100644 pages/dashboard/admin/groups/index.vue create mode 100644 pages/dashboard/admin/index.vue create mode 100644 pages/dashboard/admin/rewards.vue create mode 100644 pages/dashboard/index.vue diff --git a/composables/group.ts b/composables/group.ts index 540be26..d6fdc86 100644 --- a/composables/group.ts +++ b/composables/group.ts @@ -1,7 +1,119 @@ import { acceptHMRUpdate, defineStore } from 'pinia' export const useGroupStore = defineStore('group', () => { - return {} + const { $api } = useNuxtApp() + + const groups = ref([]) + + /** + * init populates the store with groups available in iNProve and does nothing + * if the user is unauthenticated. + * + * init should be called in any root level layout (example: layouts/app.vue) + */ + async function init(cookie?: string) { + try { + const res = await $api('/groups', { + headers: cookie + ? { + cookie, + } + : undefined, + }) + groups.value = res + } + catch (e) { + console.error('[composables/group.ts] failed to init store', e) + return parseError(e) + } + } + + /** + * create a new group + * + * @param name name of the group + * @param shortName short name of the group, must be alphanumeric (incl. dashes) + * @param description description of group + * @returns ValidationError | undefined + */ + async function create(name: string, shortName: string, description: string) { + try { + const res = await $api('/groups', { + method: 'POST', + body: { + name, + shortName, + description, + }, + }) + groups.value.push(res) + } + catch (e) { + console.error('[composables/groups.ts] failed to create group', e) + return parseError(e) + } + } + + /** + * update a group + * + * @param prevshortName short name of the previous group used to update all information + * @param name name of the group + * @param shortName short name of the group, must be alphanumeric (incl. dashes) + * @param description description of group + * @returns ValidationError | undefined + */ + async function update(prevshortName: string, name: string, shortName: string, description: string) { + try { + const res = await $api(`/groups/${prevshortName}`, { + method: 'PUT', + body: { + name, + shortName, + description, + }, + }) + const idx = groups.value.findIndex(i => i.shortName === prevshortName) + if (idx === -1) + throw new Error('invariant') + + groups.value[idx] = res + } + catch (e) { + console.error('[composables/groups.ts] failed to update group', e) + return parseError(e) + } + } + + /** + * delete a group + * please be careful, this also deletes all resources belonging to the group + * + * @param shortName short name of the group to delete + * @returns ValidationError | undefined + */ + async function del(shortName: string) { + try { + await $api(`/groups/${shortName}`, { + method: 'DELETE', + }) + + groups.value = groups.value.filter(groups => groups.shortName !== shortName) + } + catch (e) { + console.error('[composables/groups.ts] failed to delete group', e) + return parseError(e) + } + } + + return { + groups, + + init, + create, + update, + del, + } }) if (import.meta.hot) diff --git a/pages/dashboard.vue b/pages/dashboard/admin/add-rewards.vue similarity index 100% rename from pages/dashboard.vue rename to pages/dashboard/admin/add-rewards.vue diff --git a/pages/dashboard/admin/groups.vue b/pages/dashboard/admin/groups.vue new file mode 100644 index 0000000..f4bd9fa --- /dev/null +++ b/pages/dashboard/admin/groups.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue new file mode 100644 index 0000000..788fd43 --- /dev/null +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -0,0 +1,129 @@ + + + diff --git a/pages/dashboard/admin/groups/index.vue b/pages/dashboard/admin/groups/index.vue new file mode 100644 index 0000000..e435b6a --- /dev/null +++ b/pages/dashboard/admin/groups/index.vue @@ -0,0 +1,99 @@ + + + diff --git a/pages/dashboard/admin/index.vue b/pages/dashboard/admin/index.vue new file mode 100644 index 0000000..1b1f4f5 --- /dev/null +++ b/pages/dashboard/admin/index.vue @@ -0,0 +1,68 @@ + + + diff --git a/pages/dashboard/admin/rewards.vue b/pages/dashboard/admin/rewards.vue new file mode 100644 index 0000000..6ea2b49 --- /dev/null +++ b/pages/dashboard/admin/rewards.vue @@ -0,0 +1,12 @@ + + + diff --git a/pages/dashboard/index.vue b/pages/dashboard/index.vue new file mode 100644 index 0000000..6ea2b49 --- /dev/null +++ b/pages/dashboard/index.vue @@ -0,0 +1,12 @@ + + + diff --git a/utils/api.ts b/utils/api.ts index 03621eb..2360178 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -23,3 +23,10 @@ interface InstitutionInviteLink { } type InstitutionRoles = 'admin' | 'educator' | 'member' + +interface Group { + id: number + name: string + shortName: string + description: String +} From 0d27a79ddb591d59ac3b5368bd40e472b67b9c41 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:48:30 +0800 Subject: [PATCH 02/11] fix: admin group creation page error --- pages/dashboard/admin/groups/[shortName].vue | 16 ++++++++++------ utils/api.ts | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 788fd43..1c9c618 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -13,10 +13,12 @@ const router = useRouter() const toast = useToast() const group = useGroupStore() +const groupData = computed(() => group.groups.find(grp => grp.shortName === router.currentRoute.value.params.shortName)) + const initFormData = computed(() => { - const res = group.groups.find(grp => grp.shortName === router.currentRoute.value.params.shortName) - if (!res) { + if (!groupData.value) { return { + ogShortName: '', name: '', shortName: '', description: '', @@ -25,13 +27,15 @@ const initFormData = computed(() => { } } return { - ...res, + ogShortName: groupData.value.shortName, + ...groupData.value, isLoading: false, error: {}, } }) const formData = ref<{ + ogShortName: string name: string shortName: string description: string @@ -40,7 +44,7 @@ const formData = ref<{ }>(initFormData.value) async function update() { - const err = await group.update(router.currentRoute.value.params.shortName, formData.value.name, formData.value.shortName, formData.value.description) + const err = await group.update(formData.value.ogShortName, formData.value.name, formData.value.shortName, formData.value.description) if (err) { formData.value.error = err } @@ -50,12 +54,12 @@ async function update() { summary: 'Success', detail: 'Group updated', }) - navigateTo('/dashboard/admin/groups') + navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) } } async function del() { - const err = await group.del(formData.value.shortName) + const err = await group.del(formData.value.ogShortName) if (err) { formData.value.error = err } diff --git a/utils/api.ts b/utils/api.ts index 2360178..b40ea98 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -28,5 +28,5 @@ interface Group { id: number name: string shortName: string - description: String + description: string } From 0f07323c506b7f480608180fb61112af1687df4e Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:37:19 +0800 Subject: [PATCH 03/11] feat: Invite links for group --- composables/group.ts | 56 +++++- pages/dashboard/admin/groups/[shortName].vue | 196 +++++++++++++++---- utils/api.ts | 9 + 3 files changed, 227 insertions(+), 34 deletions(-) diff --git a/composables/group.ts b/composables/group.ts index d6fdc86..82dddf0 100644 --- a/composables/group.ts +++ b/composables/group.ts @@ -4,6 +4,7 @@ export const useGroupStore = defineStore('group', () => { const { $api } = useNuxtApp() const groups = ref([]) + const invites = ref>({}) /** * init populates the store with groups available in iNProve and does nothing @@ -57,13 +58,14 @@ export const useGroupStore = defineStore('group', () => { /** * update a group * + * @param prevName name of the previous group to display current information presented on the site * @param prevshortName short name of the previous group used to update all information * @param name name of the group * @param shortName short name of the group, must be alphanumeric (incl. dashes) * @param description description of group * @returns ValidationError | undefined */ - async function update(prevshortName: string, name: string, shortName: string, description: string) { + async function update(prevName: string, prevshortName: string, name: string, shortName: string, description: string) { try { const res = await $api(`/groups/${prevshortName}`, { method: 'PUT', @@ -106,13 +108,65 @@ export const useGroupStore = defineStore('group', () => { } } + /** + * loadInvites populates the invites value on demand for a given group + * + * @param shortName short name of the group + * @returns ValidationError | undefined + */ + async function loadInvites(shortName: string) { + try { + const res = await $api(`/groups/${shortName}/invites`) + invites.value[shortName] = res + } + catch (err) { + console.error('[composables/groups.ts] failed to load invites', err) + return parseError(err) + } + } + + async function createInvite(shortName: string, role: string) { + try { + const res = await $api(`/groups/${shortName}/invites`, { + method: 'POST', + body: { + role, + }, + }) + invites.value[shortName].push(res) + } + catch (e) { + console.error('[composables/groups.ts] failed to create invite', e) + return parseError(e) + } + } + + async function delInvite(shortName: string, code: string) { + try { + await $api(`/groups/${shortName}/invites/${code}`, { + method: 'DELETE', + }) + + invites.value[shortName] = invites.value[shortName].filter(v => v.code !== code) + } + catch (err) { + console.error('[composables/groups.ts] failed to create invite', err) + return parseError(err) + } + } + return { groups, + invites, init, create, update, del, + + loadInvites, + createInvite, + delInvite, } }) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 1c9c618..98adbbf 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -1,7 +1,15 @@ diff --git a/utils/api.ts b/utils/api.ts index b40ea98..7af6092 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -30,3 +30,12 @@ interface Group { shortName: string description: string } + +interface GroupInviteLink { + id: string + code: string + role: GroupRoles + group: Group +} + +type GroupRoles = 'owner' | 'educator' | 'member' From e3a8487d0d2a2789b67cd3dab66df5a86969c3d7 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:49:07 +0800 Subject: [PATCH 04/11] fix: Invite links for group --- pages/dashboard/admin/groups/[shortName].vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 98adbbf..dd2b7c2 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -120,11 +120,11 @@ const options = ref([ ]) async function createlink() { - if (!inviteFormData.role) + if (groupData.value === undefined || !inviteFormData.role) return inviteFormData.pending = true - const err = await group.createInvite(groupData, inviteFormData.role) + const err = await group.createInvite(groupData.value.shortName, inviteFormData.role) if (err) inviteFormData.error = err @@ -139,7 +139,10 @@ function copyLink(code: string) { async function delinvite(code: string) { inviteFormData.pendingDel = code - const err = await group.delInvite(groupData, code) + if (groupData.value === undefined) + return + + const err = await group.delInvite(groupData.value.shortName, code) if (err) inviteFormData.error = err From 642e87eedd8c45ddbd394657e12799a45048ca2f Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Wed, 5 Jul 2023 19:46:19 +0800 Subject: [PATCH 05/11] feat: Path change to use /{{ Institution Name }}/... --- composables/auth.ts | 34 +++++++++++++++++++ layouts/app.vue | 2 +- .../dashboard/index.vue | 0 .../manage}/add-rewards.vue | 0 .../manage}/groups.vue | 5 ++- .../manage}/groups/[shortName].vue | 5 +-- .../manage/groups/new.vue} | 3 +- .../manage}/index.vue | 6 ++-- .../manage}/rewards.vue | 0 pages/login.vue | 2 +- pages/s/[code].vue | 2 +- 11 files changed, 47 insertions(+), 12 deletions(-) rename pages/{ => @[[institution]]}/dashboard/index.vue (100%) rename pages/{dashboard/admin => @[[institution]]/manage}/add-rewards.vue (100%) rename pages/{dashboard/admin => @[[institution]]/manage}/groups.vue (92%) rename pages/{dashboard/admin => @[[institution]]/manage}/groups/[shortName].vue (97%) rename pages/{dashboard/admin/groups/index.vue => @[[institution]]/manage/groups/new.vue} (95%) rename pages/{dashboard/admin => @[[institution]]/manage}/index.vue (92%) rename pages/{dashboard/admin => @[[institution]]/manage}/rewards.vue (100%) diff --git a/composables/auth.ts b/composables/auth.ts index 43ef854..193bb60 100644 --- a/composables/auth.ts +++ b/composables/auth.ts @@ -11,6 +11,10 @@ export const useAuthStore = defineStore('auth', () => { const pointsAwardedResetTime = ref(new Date(Date.now())) const godMode = ref(false) + const institutionName = ref('') + const institutionShortName = ref('') + const institutionDescription = ref('') + const authenticated = computed(() => !!email.value) /** @@ -31,6 +35,24 @@ export const useAuthStore = defineStore('auth', () => { : undefined, }) populate(res) + await getuserinstitution(cookie) + } + catch (e) { + console.error('[composables/user.ts] failed to init store', e) + return parseError(e) + } + } + + async function getuserinstitution(cookie?: string) { + try { + const res = await $api('/auth/myinstitution', { + headers: cookie + ? { + cookie, + } + : undefined, + }) + populateInst(res) } catch (e) { console.error('[composables/user.ts] failed to init store', e) @@ -53,6 +75,7 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) + await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to login', e) @@ -83,6 +106,7 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) + await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to register', e) @@ -116,6 +140,12 @@ export const useAuthStore = defineStore('auth', () => { } } + function populateInst(data: Institution) { + institutionName.value = data.name + institutionShortName.value = data.shortName + institutionDescription.value = data.description + } + return { firstName, lastName, @@ -125,6 +155,10 @@ export const useAuthStore = defineStore('auth', () => { pointsAwardedResetTime, godMode, + institutionName, + institutionShortName, + institutionDescription, + authenticated, init, diff --git a/layouts/app.vue b/layouts/app.vue index b42072c..5e4835b 100644 --- a/layouts/app.vue +++ b/layouts/app.vue @@ -43,7 +43,7 @@ useAsyncData(async () => {
- + diff --git a/pages/dashboard/index.vue b/pages/@[[institution]]/dashboard/index.vue similarity index 100% rename from pages/dashboard/index.vue rename to pages/@[[institution]]/dashboard/index.vue diff --git a/pages/dashboard/admin/add-rewards.vue b/pages/@[[institution]]/manage/add-rewards.vue similarity index 100% rename from pages/dashboard/admin/add-rewards.vue rename to pages/@[[institution]]/manage/add-rewards.vue diff --git a/pages/dashboard/admin/groups.vue b/pages/@[[institution]]/manage/groups.vue similarity index 92% rename from pages/dashboard/admin/groups.vue rename to pages/@[[institution]]/manage/groups.vue index f4bd9fa..d5de713 100644 --- a/pages/dashboard/admin/groups.vue +++ b/pages/@[[institution]]/manage/groups.vue @@ -9,7 +9,6 @@ definePageMeta({ middleware: 'god-mode', }) -const router = useRouter() const group = useGroupStore() const headers = useRequestHeaders(['cookie']) useAsyncData(async () => { @@ -20,14 +19,14 @@ useAsyncData(async () => { const groupsMenu = computed(() => { const i: MenuItem[] = group.groups.map(grp => ({ label: `${grp.name} (${grp.shortName})`, - to: `/dashboard/admin/groups/${grp.shortName}`, + to: `${grp.shortName}`, })) i.push({ separator: true }) return i }) function toCreate() { - router.push('/dashboard/admin/groups') + navigateTo('new') } diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/@[[institution]]/manage/groups/[shortName].vue similarity index 97% rename from pages/dashboard/admin/groups/[shortName].vue rename to pages/@[[institution]]/manage/groups/[shortName].vue index dd2b7c2..da5d6b5 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/@[[institution]]/manage/groups/[shortName].vue @@ -20,6 +20,7 @@ definePageMeta({ const route = useRoute() const router = useRouter() const toast = useToast() +const auth = useAuthStore() const group = useGroupStore() onMounted(async () => { @@ -74,7 +75,7 @@ async function update() { summary: 'Success', detail: 'Group updated', }) - navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) } } @@ -89,7 +90,7 @@ async function del() { summary: 'Success', detail: 'Group deleted', }) - navigateTo('/dashboard/admin/groups') + navigateTo(`/@${auth.institutionShortName}/manage/groups`) } } diff --git a/pages/dashboard/admin/groups/index.vue b/pages/@[[institution]]/manage/groups/new.vue similarity index 95% rename from pages/dashboard/admin/groups/index.vue rename to pages/@[[institution]]/manage/groups/new.vue index e435b6a..1e6cb72 100644 --- a/pages/dashboard/admin/groups/index.vue +++ b/pages/@[[institution]]/manage/groups/new.vue @@ -11,6 +11,7 @@ definePageMeta({ const toast = useToast() +const auth = useAuthStore() const group = useGroupStore() const headers = useRequestHeaders(['cookie']) useAsyncData(async () => { @@ -45,7 +46,7 @@ async function create() { summary: 'Success', detail: 'Group created', }) - navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) } } diff --git a/pages/dashboard/admin/index.vue b/pages/@[[institution]]/manage/index.vue similarity index 92% rename from pages/dashboard/admin/index.vue rename to pages/@[[institution]]/manage/index.vue index 1b1f4f5..3320880 100644 --- a/pages/dashboard/admin/index.vue +++ b/pages/@[[institution]]/manage/index.vue @@ -22,15 +22,15 @@ interface AdminPages { const adminPages = [ { text: 'Manage Group', - link: '/dashboard/admin/groups', + link: 'manage/groups/new', }, { text: 'View available Pet Accessories and Vouchers', - link: '/dashboard/admin/rewards', + link: 'manage/rewards', }, { text: 'Modify Pet Accessories and Vouchers', - link: '/dashboard/admin/add-rewards', + link: 'manage/add-rewards', }, ] satisfies AdminPages[] diff --git a/pages/dashboard/admin/rewards.vue b/pages/@[[institution]]/manage/rewards.vue similarity index 100% rename from pages/dashboard/admin/rewards.vue rename to pages/@[[institution]]/manage/rewards.vue diff --git a/pages/login.vue b/pages/login.vue index e490bcb..4b99b05 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -28,7 +28,7 @@ async function login() { formData.isLoading = true const err = await auth.login(formData.email, formData.password) if (!err) - return navigateTo('/dashboard') + return navigateTo(`/@${auth.institutionShortName}/dashboard`) formData.error = err formData.isLoading = false } diff --git a/pages/s/[code].vue b/pages/s/[code].vue index 374328c..d2385f6 100644 --- a/pages/s/[code].vue +++ b/pages/s/[code].vue @@ -45,7 +45,7 @@ async function register() { formData.firstName, formData.lastName, formData.email, formData.password, ) if (!err) - return navigateTo('/dashboard') + return navigateTo(`/@${data.value?.institution.shortName}/dashboard`) formData.error = err formData.isLoading = false } From 455c6547cefbf986317e1e0e1b27e4ba9999da92 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Thu, 29 Jun 2023 20:18:27 +0800 Subject: [PATCH 06/11] feat: Group and Admin Page Creation --- composables/group.ts | 114 +++++++++++++++- .../admin/add-rewards.vue} | 0 pages/dashboard/admin/groups.vue | 75 ++++++++++ pages/dashboard/admin/groups/[shortName].vue | 129 ++++++++++++++++++ pages/dashboard/admin/groups/index.vue | 99 ++++++++++++++ pages/dashboard/admin/index.vue | 68 +++++++++ pages/dashboard/admin/rewards.vue | 12 ++ pages/dashboard/index.vue | 12 ++ utils/api.ts | 7 + 9 files changed, 515 insertions(+), 1 deletion(-) rename pages/{dashboard.vue => dashboard/admin/add-rewards.vue} (100%) create mode 100644 pages/dashboard/admin/groups.vue create mode 100644 pages/dashboard/admin/groups/[shortName].vue create mode 100644 pages/dashboard/admin/groups/index.vue create mode 100644 pages/dashboard/admin/index.vue create mode 100644 pages/dashboard/admin/rewards.vue create mode 100644 pages/dashboard/index.vue diff --git a/composables/group.ts b/composables/group.ts index 540be26..d6fdc86 100644 --- a/composables/group.ts +++ b/composables/group.ts @@ -1,7 +1,119 @@ import { acceptHMRUpdate, defineStore } from 'pinia' export const useGroupStore = defineStore('group', () => { - return {} + const { $api } = useNuxtApp() + + const groups = ref([]) + + /** + * init populates the store with groups available in iNProve and does nothing + * if the user is unauthenticated. + * + * init should be called in any root level layout (example: layouts/app.vue) + */ + async function init(cookie?: string) { + try { + const res = await $api('/groups', { + headers: cookie + ? { + cookie, + } + : undefined, + }) + groups.value = res + } + catch (e) { + console.error('[composables/group.ts] failed to init store', e) + return parseError(e) + } + } + + /** + * create a new group + * + * @param name name of the group + * @param shortName short name of the group, must be alphanumeric (incl. dashes) + * @param description description of group + * @returns ValidationError | undefined + */ + async function create(name: string, shortName: string, description: string) { + try { + const res = await $api('/groups', { + method: 'POST', + body: { + name, + shortName, + description, + }, + }) + groups.value.push(res) + } + catch (e) { + console.error('[composables/groups.ts] failed to create group', e) + return parseError(e) + } + } + + /** + * update a group + * + * @param prevshortName short name of the previous group used to update all information + * @param name name of the group + * @param shortName short name of the group, must be alphanumeric (incl. dashes) + * @param description description of group + * @returns ValidationError | undefined + */ + async function update(prevshortName: string, name: string, shortName: string, description: string) { + try { + const res = await $api(`/groups/${prevshortName}`, { + method: 'PUT', + body: { + name, + shortName, + description, + }, + }) + const idx = groups.value.findIndex(i => i.shortName === prevshortName) + if (idx === -1) + throw new Error('invariant') + + groups.value[idx] = res + } + catch (e) { + console.error('[composables/groups.ts] failed to update group', e) + return parseError(e) + } + } + + /** + * delete a group + * please be careful, this also deletes all resources belonging to the group + * + * @param shortName short name of the group to delete + * @returns ValidationError | undefined + */ + async function del(shortName: string) { + try { + await $api(`/groups/${shortName}`, { + method: 'DELETE', + }) + + groups.value = groups.value.filter(groups => groups.shortName !== shortName) + } + catch (e) { + console.error('[composables/groups.ts] failed to delete group', e) + return parseError(e) + } + } + + return { + groups, + + init, + create, + update, + del, + } }) if (import.meta.hot) diff --git a/pages/dashboard.vue b/pages/dashboard/admin/add-rewards.vue similarity index 100% rename from pages/dashboard.vue rename to pages/dashboard/admin/add-rewards.vue diff --git a/pages/dashboard/admin/groups.vue b/pages/dashboard/admin/groups.vue new file mode 100644 index 0000000..f4bd9fa --- /dev/null +++ b/pages/dashboard/admin/groups.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue new file mode 100644 index 0000000..788fd43 --- /dev/null +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -0,0 +1,129 @@ + + + diff --git a/pages/dashboard/admin/groups/index.vue b/pages/dashboard/admin/groups/index.vue new file mode 100644 index 0000000..e435b6a --- /dev/null +++ b/pages/dashboard/admin/groups/index.vue @@ -0,0 +1,99 @@ + + + diff --git a/pages/dashboard/admin/index.vue b/pages/dashboard/admin/index.vue new file mode 100644 index 0000000..1b1f4f5 --- /dev/null +++ b/pages/dashboard/admin/index.vue @@ -0,0 +1,68 @@ + + + diff --git a/pages/dashboard/admin/rewards.vue b/pages/dashboard/admin/rewards.vue new file mode 100644 index 0000000..6ea2b49 --- /dev/null +++ b/pages/dashboard/admin/rewards.vue @@ -0,0 +1,12 @@ + + + diff --git a/pages/dashboard/index.vue b/pages/dashboard/index.vue new file mode 100644 index 0000000..6ea2b49 --- /dev/null +++ b/pages/dashboard/index.vue @@ -0,0 +1,12 @@ + + + diff --git a/utils/api.ts b/utils/api.ts index 03621eb..2360178 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -23,3 +23,10 @@ interface InstitutionInviteLink { } type InstitutionRoles = 'admin' | 'educator' | 'member' + +interface Group { + id: number + name: string + shortName: string + description: String +} From 4f32b3645813feb86f9343c1e37d6f4b25357b79 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Thu, 29 Jun 2023 22:48:30 +0800 Subject: [PATCH 07/11] fix: admin group creation page error --- pages/dashboard/admin/groups/[shortName].vue | 16 ++++++++++------ utils/api.ts | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 788fd43..1c9c618 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -13,10 +13,12 @@ const router = useRouter() const toast = useToast() const group = useGroupStore() +const groupData = computed(() => group.groups.find(grp => grp.shortName === router.currentRoute.value.params.shortName)) + const initFormData = computed(() => { - const res = group.groups.find(grp => grp.shortName === router.currentRoute.value.params.shortName) - if (!res) { + if (!groupData.value) { return { + ogShortName: '', name: '', shortName: '', description: '', @@ -25,13 +27,15 @@ const initFormData = computed(() => { } } return { - ...res, + ogShortName: groupData.value.shortName, + ...groupData.value, isLoading: false, error: {}, } }) const formData = ref<{ + ogShortName: string name: string shortName: string description: string @@ -40,7 +44,7 @@ const formData = ref<{ }>(initFormData.value) async function update() { - const err = await group.update(router.currentRoute.value.params.shortName, formData.value.name, formData.value.shortName, formData.value.description) + const err = await group.update(formData.value.ogShortName, formData.value.name, formData.value.shortName, formData.value.description) if (err) { formData.value.error = err } @@ -50,12 +54,12 @@ async function update() { summary: 'Success', detail: 'Group updated', }) - navigateTo('/dashboard/admin/groups') + navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) } } async function del() { - const err = await group.del(formData.value.shortName) + const err = await group.del(formData.value.ogShortName) if (err) { formData.value.error = err } diff --git a/utils/api.ts b/utils/api.ts index 2360178..b40ea98 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -28,5 +28,5 @@ interface Group { id: number name: string shortName: string - description: String + description: string } From 44b805dd308b4398c18d65848b7ec4d0a37b1797 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Tue, 4 Jul 2023 14:37:19 +0800 Subject: [PATCH 08/11] feat: Invite links for group --- composables/group.ts | 56 +++++- pages/dashboard/admin/groups/[shortName].vue | 196 +++++++++++++++---- utils/api.ts | 9 + 3 files changed, 227 insertions(+), 34 deletions(-) diff --git a/composables/group.ts b/composables/group.ts index d6fdc86..82dddf0 100644 --- a/composables/group.ts +++ b/composables/group.ts @@ -4,6 +4,7 @@ export const useGroupStore = defineStore('group', () => { const { $api } = useNuxtApp() const groups = ref([]) + const invites = ref>({}) /** * init populates the store with groups available in iNProve and does nothing @@ -57,13 +58,14 @@ export const useGroupStore = defineStore('group', () => { /** * update a group * + * @param prevName name of the previous group to display current information presented on the site * @param prevshortName short name of the previous group used to update all information * @param name name of the group * @param shortName short name of the group, must be alphanumeric (incl. dashes) * @param description description of group * @returns ValidationError | undefined */ - async function update(prevshortName: string, name: string, shortName: string, description: string) { + async function update(prevName: string, prevshortName: string, name: string, shortName: string, description: string) { try { const res = await $api(`/groups/${prevshortName}`, { method: 'PUT', @@ -106,13 +108,65 @@ export const useGroupStore = defineStore('group', () => { } } + /** + * loadInvites populates the invites value on demand for a given group + * + * @param shortName short name of the group + * @returns ValidationError | undefined + */ + async function loadInvites(shortName: string) { + try { + const res = await $api(`/groups/${shortName}/invites`) + invites.value[shortName] = res + } + catch (err) { + console.error('[composables/groups.ts] failed to load invites', err) + return parseError(err) + } + } + + async function createInvite(shortName: string, role: string) { + try { + const res = await $api(`/groups/${shortName}/invites`, { + method: 'POST', + body: { + role, + }, + }) + invites.value[shortName].push(res) + } + catch (e) { + console.error('[composables/groups.ts] failed to create invite', e) + return parseError(e) + } + } + + async function delInvite(shortName: string, code: string) { + try { + await $api(`/groups/${shortName}/invites/${code}`, { + method: 'DELETE', + }) + + invites.value[shortName] = invites.value[shortName].filter(v => v.code !== code) + } + catch (err) { + console.error('[composables/groups.ts] failed to create invite', err) + return parseError(err) + } + } + return { groups, + invites, init, create, update, del, + + loadInvites, + createInvite, + delInvite, } }) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 1c9c618..98adbbf 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -1,7 +1,15 @@ diff --git a/utils/api.ts b/utils/api.ts index b40ea98..7af6092 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -30,3 +30,12 @@ interface Group { shortName: string description: string } + +interface GroupInviteLink { + id: string + code: string + role: GroupRoles + group: Group +} + +type GroupRoles = 'owner' | 'educator' | 'member' From d0fb9b54e443a954a418ce0916524c842888fabe Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:49:07 +0800 Subject: [PATCH 09/11] fix: Invite links for group --- pages/dashboard/admin/groups/[shortName].vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/dashboard/admin/groups/[shortName].vue index 98adbbf..dd2b7c2 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/dashboard/admin/groups/[shortName].vue @@ -120,11 +120,11 @@ const options = ref([ ]) async function createlink() { - if (!inviteFormData.role) + if (groupData.value === undefined || !inviteFormData.role) return inviteFormData.pending = true - const err = await group.createInvite(groupData, inviteFormData.role) + const err = await group.createInvite(groupData.value.shortName, inviteFormData.role) if (err) inviteFormData.error = err @@ -139,7 +139,10 @@ function copyLink(code: string) { async function delinvite(code: string) { inviteFormData.pendingDel = code - const err = await group.delInvite(groupData, code) + if (groupData.value === undefined) + return + + const err = await group.delInvite(groupData.value.shortName, code) if (err) inviteFormData.error = err From 2941fa833d7ef2d98f35a98681270e8861805046 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Wed, 5 Jul 2023 19:46:19 +0800 Subject: [PATCH 10/11] feat: Path change to use /{{ Institution Name }}/... --- composables/auth.ts | 34 +++++++++++++++++++ layouts/app.vue | 2 +- .../dashboard/index.vue | 0 .../manage}/add-rewards.vue | 0 .../manage}/groups.vue | 5 ++- .../manage}/groups/[shortName].vue | 5 +-- .../manage/groups/new.vue} | 3 +- .../manage}/index.vue | 6 ++-- .../manage}/rewards.vue | 0 pages/login.vue | 2 +- pages/s/[code].vue | 2 +- 11 files changed, 47 insertions(+), 12 deletions(-) rename pages/{ => @[[institution]]}/dashboard/index.vue (100%) rename pages/{dashboard/admin => @[[institution]]/manage}/add-rewards.vue (100%) rename pages/{dashboard/admin => @[[institution]]/manage}/groups.vue (92%) rename pages/{dashboard/admin => @[[institution]]/manage}/groups/[shortName].vue (97%) rename pages/{dashboard/admin/groups/index.vue => @[[institution]]/manage/groups/new.vue} (95%) rename pages/{dashboard/admin => @[[institution]]/manage}/index.vue (92%) rename pages/{dashboard/admin => @[[institution]]/manage}/rewards.vue (100%) diff --git a/composables/auth.ts b/composables/auth.ts index 43ef854..193bb60 100644 --- a/composables/auth.ts +++ b/composables/auth.ts @@ -11,6 +11,10 @@ export const useAuthStore = defineStore('auth', () => { const pointsAwardedResetTime = ref(new Date(Date.now())) const godMode = ref(false) + const institutionName = ref('') + const institutionShortName = ref('') + const institutionDescription = ref('') + const authenticated = computed(() => !!email.value) /** @@ -31,6 +35,24 @@ export const useAuthStore = defineStore('auth', () => { : undefined, }) populate(res) + await getuserinstitution(cookie) + } + catch (e) { + console.error('[composables/user.ts] failed to init store', e) + return parseError(e) + } + } + + async function getuserinstitution(cookie?: string) { + try { + const res = await $api('/auth/myinstitution', { + headers: cookie + ? { + cookie, + } + : undefined, + }) + populateInst(res) } catch (e) { console.error('[composables/user.ts] failed to init store', e) @@ -53,6 +75,7 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) + await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to login', e) @@ -83,6 +106,7 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) + await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to register', e) @@ -116,6 +140,12 @@ export const useAuthStore = defineStore('auth', () => { } } + function populateInst(data: Institution) { + institutionName.value = data.name + institutionShortName.value = data.shortName + institutionDescription.value = data.description + } + return { firstName, lastName, @@ -125,6 +155,10 @@ export const useAuthStore = defineStore('auth', () => { pointsAwardedResetTime, godMode, + institutionName, + institutionShortName, + institutionDescription, + authenticated, init, diff --git a/layouts/app.vue b/layouts/app.vue index da28633..43ae01f 100644 --- a/layouts/app.vue +++ b/layouts/app.vue @@ -41,7 +41,7 @@ useAsyncData(async () => {
- + diff --git a/pages/dashboard/index.vue b/pages/@[[institution]]/dashboard/index.vue similarity index 100% rename from pages/dashboard/index.vue rename to pages/@[[institution]]/dashboard/index.vue diff --git a/pages/dashboard/admin/add-rewards.vue b/pages/@[[institution]]/manage/add-rewards.vue similarity index 100% rename from pages/dashboard/admin/add-rewards.vue rename to pages/@[[institution]]/manage/add-rewards.vue diff --git a/pages/dashboard/admin/groups.vue b/pages/@[[institution]]/manage/groups.vue similarity index 92% rename from pages/dashboard/admin/groups.vue rename to pages/@[[institution]]/manage/groups.vue index f4bd9fa..d5de713 100644 --- a/pages/dashboard/admin/groups.vue +++ b/pages/@[[institution]]/manage/groups.vue @@ -9,7 +9,6 @@ definePageMeta({ middleware: 'god-mode', }) -const router = useRouter() const group = useGroupStore() const headers = useRequestHeaders(['cookie']) useAsyncData(async () => { @@ -20,14 +19,14 @@ useAsyncData(async () => { const groupsMenu = computed(() => { const i: MenuItem[] = group.groups.map(grp => ({ label: `${grp.name} (${grp.shortName})`, - to: `/dashboard/admin/groups/${grp.shortName}`, + to: `${grp.shortName}`, })) i.push({ separator: true }) return i }) function toCreate() { - router.push('/dashboard/admin/groups') + navigateTo('new') } diff --git a/pages/dashboard/admin/groups/[shortName].vue b/pages/@[[institution]]/manage/groups/[shortName].vue similarity index 97% rename from pages/dashboard/admin/groups/[shortName].vue rename to pages/@[[institution]]/manage/groups/[shortName].vue index dd2b7c2..da5d6b5 100644 --- a/pages/dashboard/admin/groups/[shortName].vue +++ b/pages/@[[institution]]/manage/groups/[shortName].vue @@ -20,6 +20,7 @@ definePageMeta({ const route = useRoute() const router = useRouter() const toast = useToast() +const auth = useAuthStore() const group = useGroupStore() onMounted(async () => { @@ -74,7 +75,7 @@ async function update() { summary: 'Success', detail: 'Group updated', }) - navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) } } @@ -89,7 +90,7 @@ async function del() { summary: 'Success', detail: 'Group deleted', }) - navigateTo('/dashboard/admin/groups') + navigateTo(`/@${auth.institutionShortName}/manage/groups`) } } diff --git a/pages/dashboard/admin/groups/index.vue b/pages/@[[institution]]/manage/groups/new.vue similarity index 95% rename from pages/dashboard/admin/groups/index.vue rename to pages/@[[institution]]/manage/groups/new.vue index e435b6a..1e6cb72 100644 --- a/pages/dashboard/admin/groups/index.vue +++ b/pages/@[[institution]]/manage/groups/new.vue @@ -11,6 +11,7 @@ definePageMeta({ const toast = useToast() +const auth = useAuthStore() const group = useGroupStore() const headers = useRequestHeaders(['cookie']) useAsyncData(async () => { @@ -45,7 +46,7 @@ async function create() { summary: 'Success', detail: 'Group created', }) - navigateTo(`/dashboard/admin/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) } } diff --git a/pages/dashboard/admin/index.vue b/pages/@[[institution]]/manage/index.vue similarity index 92% rename from pages/dashboard/admin/index.vue rename to pages/@[[institution]]/manage/index.vue index 1b1f4f5..3320880 100644 --- a/pages/dashboard/admin/index.vue +++ b/pages/@[[institution]]/manage/index.vue @@ -22,15 +22,15 @@ interface AdminPages { const adminPages = [ { text: 'Manage Group', - link: '/dashboard/admin/groups', + link: 'manage/groups/new', }, { text: 'View available Pet Accessories and Vouchers', - link: '/dashboard/admin/rewards', + link: 'manage/rewards', }, { text: 'Modify Pet Accessories and Vouchers', - link: '/dashboard/admin/add-rewards', + link: 'manage/add-rewards', }, ] satisfies AdminPages[] diff --git a/pages/dashboard/admin/rewards.vue b/pages/@[[institution]]/manage/rewards.vue similarity index 100% rename from pages/dashboard/admin/rewards.vue rename to pages/@[[institution]]/manage/rewards.vue diff --git a/pages/login.vue b/pages/login.vue index e490bcb..4b99b05 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -28,7 +28,7 @@ async function login() { formData.isLoading = true const err = await auth.login(formData.email, formData.password) if (!err) - return navigateTo('/dashboard') + return navigateTo(`/@${auth.institutionShortName}/dashboard`) formData.error = err formData.isLoading = false } diff --git a/pages/s/[code].vue b/pages/s/[code].vue index 374328c..d2385f6 100644 --- a/pages/s/[code].vue +++ b/pages/s/[code].vue @@ -45,7 +45,7 @@ async function register() { formData.firstName, formData.lastName, formData.email, formData.password, ) if (!err) - return navigateTo('/dashboard') + return navigateTo(`/@${data.value?.institution.shortName}/dashboard`) formData.error = err formData.isLoading = false } From bd24ee8e135da2df7eac7314e33a0862dbfdf942 Mon Sep 17 00:00:00 2001 From: C4RR0T02 <66990228+C4RR0T02@users.noreply.github.com> Date: Tue, 11 Jul 2023 12:25:14 +0800 Subject: [PATCH 11/11] fix: linking of pages --- composables/auth.ts | 88 +++++-------------- layouts/app.vue | 2 +- pages/@[[institution]]/dashboard/index.vue | 39 +++++++- .../manage/groups/[shortName].vue | 4 +- pages/@[[institution]]/manage/groups/new.vue | 2 +- pages/login.vue | 2 +- utils/api.ts | 1 + 7 files changed, 67 insertions(+), 71 deletions(-) diff --git a/composables/auth.ts b/composables/auth.ts index 193bb60..44ab508 100644 --- a/composables/auth.ts +++ b/composables/auth.ts @@ -3,19 +3,10 @@ import { acceptHMRUpdate, defineStore } from 'pinia' export const useAuthStore = defineStore('auth', () => { const { $api } = useNuxtApp() - const firstName = ref('') - const lastName = ref('') - const email = ref('') - const points = ref(0) - const pointsAwardedCount = ref(0) - const pointsAwardedResetTime = ref(new Date(Date.now())) - const godMode = ref(false) + const user = ref() + const institution = ref() - const institutionName = ref('') - const institutionShortName = ref('') - const institutionDescription = ref('') - - const authenticated = computed(() => !!email.value) + const authenticated = computed(() => !!user.value) /** * init populates the store with the current user data, and does nothing @@ -35,24 +26,6 @@ export const useAuthStore = defineStore('auth', () => { : undefined, }) populate(res) - await getuserinstitution(cookie) - } - catch (e) { - console.error('[composables/user.ts] failed to init store', e) - return parseError(e) - } - } - - async function getuserinstitution(cookie?: string) { - try { - const res = await $api('/auth/myinstitution', { - headers: cookie - ? { - cookie, - } - : undefined, - }) - populateInst(res) } catch (e) { console.error('[composables/user.ts] failed to init store', e) @@ -75,7 +48,6 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) - await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to login', e) @@ -106,7 +78,6 @@ export const useAuthStore = defineStore('auth', () => { }, }) populate(res) - await getuserinstitution() } catch (e) { console.error('[composables/user.ts] failed to register', e) @@ -119,45 +90,34 @@ export const useAuthStore = defineStore('auth', () => { * @param data data to populate the store with */ function populate(data: User) { - firstName.value = data.firstName - lastName.value = data.lastName - email.value = data.email + user.value = { + ...data, - if (data.godMode) - godMode.value = data.godMode + } + institution.value = data.institution - if (data.points) - points.value = data.points + // firstName.value = data.firstName + // lastName.value = data.lastName + // email.value = data.email - if (data.pointsAwardedCount) - pointsAwardedCount.value = data.pointsAwardedCount + // if (data.godMode) + // godMode.value = data.godMode - if (data.pointsAwardedResetTime) { - const d = new Date(data.pointsAwardedResetTime) - if (d.getFullYear() !== 1) { // Zero value in Go time.TIme - pointsAwardedResetTime.value = d - } - } - } + // if (data.points) + // points.value = data.points - function populateInst(data: Institution) { - institutionName.value = data.name - institutionShortName.value = data.shortName - institutionDescription.value = data.description - } + // if (data.pointsAwardedCount) + // pointsAwardedCount.value = data.pointsAwardedCount + // if (data.pointsAwardedResetTime) { + // const d = new Date(data.pointsAwardedResetTime) + // if (d.getFullYear() !== 1) { // Zero value in Go time.TIme + // pointsAwardedResetTime.value = d + // } + // } + } return { - firstName, - lastName, - email, - points, - pointsAwardedCount, - pointsAwardedResetTime, - godMode, - - institutionName, - institutionShortName, - institutionDescription, + ...user.value, authenticated, diff --git a/layouts/app.vue b/layouts/app.vue index 43ae01f..644bc15 100644 --- a/layouts/app.vue +++ b/layouts/app.vue @@ -41,7 +41,7 @@ useAsyncData(async () => {
- + diff --git a/pages/@[[institution]]/dashboard/index.vue b/pages/@[[institution]]/dashboard/index.vue index 6ea2b49..709211e 100644 --- a/pages/@[[institution]]/dashboard/index.vue +++ b/pages/@[[institution]]/dashboard/index.vue @@ -1,12 +1,47 @@ diff --git a/pages/@[[institution]]/manage/groups/[shortName].vue b/pages/@[[institution]]/manage/groups/[shortName].vue index da5d6b5..dde439a 100644 --- a/pages/@[[institution]]/manage/groups/[shortName].vue +++ b/pages/@[[institution]]/manage/groups/[shortName].vue @@ -75,7 +75,7 @@ async function update() { summary: 'Success', detail: 'Group updated', }) - navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institution?.shortName}/manage/groups/${formData.value.shortName}`) } } @@ -90,7 +90,7 @@ async function del() { summary: 'Success', detail: 'Group deleted', }) - navigateTo(`/@${auth.institutionShortName}/manage/groups`) + navigateTo(`/@${auth.institution?.shortName}/manage/groups`) } } diff --git a/pages/@[[institution]]/manage/groups/new.vue b/pages/@[[institution]]/manage/groups/new.vue index 1e6cb72..0510ee1 100644 --- a/pages/@[[institution]]/manage/groups/new.vue +++ b/pages/@[[institution]]/manage/groups/new.vue @@ -46,7 +46,7 @@ async function create() { summary: 'Success', detail: 'Group created', }) - navigateTo(`/@${auth.institutionShortName}/manage/groups/${formData.value.shortName}`) + navigateTo(`/@${auth.institution?.shortName}/manage/groups/${formData.value.shortName}`) } } diff --git a/pages/login.vue b/pages/login.vue index 4b99b05..52ab1fa 100644 --- a/pages/login.vue +++ b/pages/login.vue @@ -28,7 +28,7 @@ async function login() { formData.isLoading = true const err = await auth.login(formData.email, formData.password) if (!err) - return navigateTo(`/@${auth.institutionShortName}/dashboard`) + return navigateTo(`/@${auth.institution?.shortName}/dashboard`) formData.error = err formData.isLoading = false } diff --git a/utils/api.ts b/utils/api.ts index 7af6092..79059bb 100644 --- a/utils/api.ts +++ b/utils/api.ts @@ -6,6 +6,7 @@ interface Institution { } interface User { + institution: Institution | null | undefined firstName: string lastName: string email: string