refactor and restructure pinia store and trpc routers + add members list to account store
This commit is contained in:
@@ -4,15 +4,15 @@
|
||||
|
||||
const supabase = useSupabaseAuthClient();
|
||||
const user = useSupabaseUser();
|
||||
const store = useAppStore()
|
||||
const { activeMembership } = storeToRefs(store);
|
||||
const authStore = useAuthStore()
|
||||
const { activeMembership } = storeToRefs(authStore);
|
||||
|
||||
const { $client } = useNuxtApp();
|
||||
|
||||
const { data: dbUser } = await $client.userAccount.getDBUser.useQuery();
|
||||
const { data: dbUser } = await $client.auth.getDBUser.useQuery();
|
||||
|
||||
onMounted(async () => {
|
||||
await store.initUser();
|
||||
await authStore.initUser();
|
||||
});
|
||||
|
||||
async function signout() {
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- Account Switching -->
|
||||
<p v-if="(dbUser?.dbUser?.memberships) && (dbUser.dbUser.memberships.length > 1)">
|
||||
<span>Switch Account.. </span>
|
||||
<button v-for="membership in dbUser?.dbUser.memberships" @click="store.changeActiveMembership(((membership as unknown) as MembershipWithAccount))"> <!-- This cast is infuriating -->
|
||||
<button v-for="membership in dbUser?.dbUser.memberships" @click="authStore.changeActiveMembership(((membership as unknown) as MembershipWithAccount))"> <!-- This cast is infuriating -->
|
||||
{{ membership.account.name }}
|
||||
<span v-if="membership.account_id === activeMembership?.account_id">*</span>
|
||||
</button>
|
||||
|
||||
@@ -45,6 +45,15 @@ export default class UserAccountService {
|
||||
});
|
||||
}
|
||||
|
||||
async getAccountMembers(account_id: number): Promise<MembershipWithUser[]> {
|
||||
return prisma_client.membership.findMany({
|
||||
where: { account_id },
|
||||
include: {
|
||||
user: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async updateAccountStipeCustomerId (account_id: number, stripe_customer_id: string){
|
||||
return await prisma_client.account.update({
|
||||
where: { id: account_id },
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ACCOUNT_ACCESS } from '@prisma/client';
|
||||
|
||||
const store = useAppStore();
|
||||
const { activeMembership } = storeToRefs(store);
|
||||
const authStore = useAuthStore();
|
||||
const { activeMembership } = storeToRefs(authStore);
|
||||
const accountStore = useAccountStore();
|
||||
const { activeAccountMembers } = storeToRefs(accountStore)
|
||||
|
||||
const config = useRuntimeConfig();
|
||||
const newAccountName = ref("");
|
||||
|
||||
watchEffect(async () => {
|
||||
if (activeMembership.value) {
|
||||
await accountStore.getActiveAccountMembers();
|
||||
}
|
||||
})
|
||||
|
||||
function formatDate(date: Date | undefined){
|
||||
if(!date){ return ""; }
|
||||
return new Intl.DateTimeFormat('default', {dateStyle: 'long'}).format(date);
|
||||
@@ -15,7 +24,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<h3>Account</h3>
|
||||
<p>Name: {{ activeMembership?.account.name }} <span v-if="activeMembership && (activeMembership.access === ACCOUNT_ACCESS.OWNER || activeMembership.access !== ACCOUNT_ACCESS.ADMIN)"><input v-model="newAccountName" placeholder="Enter New Name"/><button @click.prevent="store.changeAccountName(newAccountName)">Change Name</button></span></p>
|
||||
<p>Name: {{ activeMembership?.account.name }} <span v-if="activeMembership && (activeMembership.access === ACCOUNT_ACCESS.OWNER || activeMembership.access !== ACCOUNT_ACCESS.ADMIN)"><input v-model="newAccountName" placeholder="Enter New Name"/><button @click.prevent="accountStore.changeAccountName(newAccountName)">Change Name</button></span></p>
|
||||
<p>Current Period Ends: {{ formatDate(activeMembership?.account.current_period_ends) }}</p>
|
||||
<p>Permitted Features: {{ activeMembership?.account.features }}</p>
|
||||
<p>Maximum Notes: {{ activeMembership?.account.max_notes }}</p>
|
||||
@@ -23,6 +32,11 @@
|
||||
<p>Access Level: {{ activeMembership?.access }}</p>
|
||||
<p>Plan: {{ activeMembership?.account.plan_name }}</p>
|
||||
|
||||
<h4>Members</h4>
|
||||
<ul>
|
||||
<li v-for="accountMember in activeAccountMembers">{{ accountMember.user.display_name }}</li>
|
||||
</ul>
|
||||
|
||||
<template v-if="config.public.debugMode">
|
||||
<p>******* Debug *******</p>
|
||||
<p>Account ID: {{ activeMembership?.account.id }}</p>
|
||||
@@ -32,5 +46,11 @@
|
||||
<p>Membership Id: {{ activeMembership?.id }}</p>
|
||||
<p>User Id: {{ activeMembership?.user_id }}</p>
|
||||
</template>
|
||||
|
||||
<button @click.prevent="accountStore.changeAccountPlan(2)">Change active Account Plan to 2</button>
|
||||
<button @click.prevent="accountStore.joinUserToAccount(4)">Join user 4 to active account</button>
|
||||
<button @click.prevent="accountStore.changeUserAccessWithinAccount(4, 'OWNER')">Change user 4 access within account 5 to OWNER (SHOULD FAIL)</button>
|
||||
<button @click.prevent="accountStore.changeUserAccessWithinAccount(4, 'ADMIN')">Change user 4 access within account 5 to ADMIN</button>
|
||||
<button @click.prevent="accountStore.claimOwnershipOfAccount()">Claim Ownership of current account for current user</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,19 +5,21 @@
|
||||
middleware: ['auth'],
|
||||
});
|
||||
|
||||
const store = useAppStore();
|
||||
const { notes } = storeToRefs(store); // ensure the notes list is reactive
|
||||
const authStore = useAuthStore();
|
||||
const { activeMembership } = storeToRefs(authStore);
|
||||
|
||||
const notesStore = useNotesStore();
|
||||
const { notes } = storeToRefs(notesStore); // ensure the notes list is reactive
|
||||
|
||||
watchEffect(async () => {
|
||||
if (activeMembership.value) {
|
||||
await notesStore.fetchNotesForCurrentUser();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<h3>Notes Dashboard</h3>
|
||||
<p v-for="note in notes">{{ note.note_text }}</p>
|
||||
|
||||
<button @click.prevent="store.changeAccountPlan(2)">Change active Account Plan to 2</button>
|
||||
<button @click.prevent="store.joinUserToAccount(4)">Join user 4 to active account</button>
|
||||
<button @click.prevent="store.changeUserAccessWithinAccount(4, 'OWNER')">Change user 4 access within account 5 to OWNER (SHOULD FAIL)</button>
|
||||
<button @click.prevent="store.changeUserAccessWithinAccount(4, 'ADMIN')">Change user 4 access within account 5 to ADMIN</button>
|
||||
<button @click.prevent="store.claimOwnershipOfAccount()">Claim Ownership of current account for current user</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { ACCOUNT_ACCESS } from '@prisma/client';
|
||||
|
||||
const store = useAppStore()
|
||||
const { activeMembership } = storeToRefs(store);
|
||||
const authStore = useAuthStore()
|
||||
const { activeMembership } = storeToRefs(authStore);
|
||||
|
||||
</script>
|
||||
<template>
|
||||
|
||||
@@ -4,14 +4,16 @@
|
||||
*/
|
||||
import { createNuxtApiHandler } from 'trpc-nuxt'
|
||||
|
||||
import { publicProcedure, router } from '~/server/trpc/trpc'
|
||||
import { router } from '~/server/trpc/trpc'
|
||||
import { createContext } from '~~/server/trpc/context';
|
||||
import { notesRouter } from '~~/server/trpc/routers/notes.router';
|
||||
import { userAccountRouter } from '~~/server/trpc/routers/user.account.router';
|
||||
import { authRouter } from '~~/server/trpc/routers/auth.router';
|
||||
import { accountRouter } from '~~/server/trpc/routers/account.router';
|
||||
|
||||
export const appRouter = router({
|
||||
notes: notesRouter,
|
||||
userAccount: userAccountRouter,
|
||||
auth: authRouter,
|
||||
account: accountRouter,
|
||||
})
|
||||
|
||||
// export only the type definition of the API
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import UserAccountService from '~~/lib/services/user.account.service';
|
||||
import { protectedProcedure, router, adminProcedure } from '../trpc'
|
||||
import { router, adminProcedure } from '../trpc'
|
||||
import { ACCOUNT_ACCESS } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const userAccountRouter = router({
|
||||
getDBUser: protectedProcedure
|
||||
.query(({ ctx }) => {
|
||||
return {
|
||||
dbUser: ctx.dbUser,
|
||||
}
|
||||
}),
|
||||
export const accountRouter = router({
|
||||
changeAccountName: adminProcedure
|
||||
.input(z.object({ account_id: z.number(), new_name: z.string() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
@@ -49,7 +43,7 @@ export const userAccountRouter = router({
|
||||
membership,
|
||||
}
|
||||
}),
|
||||
claimOwnershipOfAccount: adminProcedure
|
||||
claimOwnershipOfAccount: adminProcedure
|
||||
.input(z.object({ account_id: z.number() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const uaService = new UserAccountService();
|
||||
@@ -59,4 +53,14 @@ export const userAccountRouter = router({
|
||||
membership,
|
||||
}
|
||||
}),
|
||||
getAccountMembers: adminProcedure
|
||||
.input(z.object({ account_id: z.number() }))
|
||||
.query(async ({ ctx, input }) => {
|
||||
const uaService = new UserAccountService();
|
||||
const memberships = await uaService.getAccountMembers(input.account_id);
|
||||
|
||||
return {
|
||||
memberships,
|
||||
}
|
||||
}),
|
||||
})
|
||||
10
server/trpc/routers/auth.router.ts
Normal file
10
server/trpc/routers/auth.router.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { protectedProcedure, router } from '../trpc'
|
||||
|
||||
export const authRouter = router({
|
||||
getDBUser: protectedProcedure
|
||||
.query(({ ctx }) => {
|
||||
return {
|
||||
dbUser: ctx.dbUser,
|
||||
}
|
||||
}),
|
||||
})
|
||||
73
stores/account.store.ts
Normal file
73
stores/account.store.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { ACCOUNT_ACCESS } from ".prisma/client"
|
||||
import { defineStore } from "pinia"
|
||||
import { MembershipWithUser } from "~~/lib/services/user.account.service"
|
||||
|
||||
import { useAuthStore } from './auth.store'
|
||||
|
||||
interface State {
|
||||
activeAccountMembers: MembershipWithUser[]
|
||||
}
|
||||
|
||||
export const useAccountStore = defineStore('account', {
|
||||
state: (): State => {
|
||||
return {
|
||||
activeAccountMembers: [],
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async getActiveAccountMembers(){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: members } = await $client.account.getAccountMembers.useQuery({account_id: authStore.activeMembership.account_id});
|
||||
if(members.value?.memberships){
|
||||
this.activeAccountMembers = members.value?.memberships;
|
||||
}
|
||||
},
|
||||
async changeAccountName(new_name: string){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: account } = await $client.account.changeAccountName.useQuery({account_id: authStore.activeMembership.account_id, new_name});
|
||||
if(account.value?.account){
|
||||
authStore.activeMembership.account = account.value.account;
|
||||
}
|
||||
},
|
||||
async changeAccountPlan(plan_id: number){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: account } = await $client.account.changeAccountPlan.useQuery({account_id: authStore.activeMembership.account_id, plan_id});
|
||||
if(account.value?.account){
|
||||
authStore.activeMembership.account = account.value.account;
|
||||
}
|
||||
},
|
||||
async joinUserToAccount(user_id: number){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.account.joinUserToAccount.useQuery({account_id: authStore.activeMembership.account_id, user_id});
|
||||
if(membership.value?.membership){
|
||||
authStore.activeMembership = membership.value.membership;
|
||||
}
|
||||
},
|
||||
async changeUserAccessWithinAccount(user_id: number, access: ACCOUNT_ACCESS){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.account.changeUserAccessWithinAccount.useQuery({account_id: authStore.activeMembership.account_id, user_id, access});
|
||||
if(membership.value?.membership){
|
||||
authStore.activeMembership = membership.value.membership;
|
||||
}
|
||||
},
|
||||
async claimOwnershipOfAccount(){
|
||||
const authStore = useAuthStore();
|
||||
if(!authStore.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.account.claimOwnershipOfAccount.useQuery({account_id: authStore.activeMembership.account_id});
|
||||
if(membership.value?.membership){
|
||||
authStore.activeMembership = membership.value.membership;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,89 +0,0 @@
|
||||
import { ACCOUNT_ACCESS, Note } from ".prisma/client"
|
||||
import { defineStore } from "pinia"
|
||||
import { FullDBUser, MembershipWithAccount } from "~~/lib/services/user.account.service"
|
||||
|
||||
interface State {
|
||||
dbUser?: FullDBUser
|
||||
activeMembership: MembershipWithAccount | null
|
||||
notes: Note[]
|
||||
}
|
||||
|
||||
export const useAppStore = defineStore('app', {
|
||||
state: (): State => {
|
||||
return {
|
||||
notes: [],
|
||||
activeMembership: null
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async initUser() {
|
||||
if(!this.dbUser || !this.activeMembership){
|
||||
const { $client } = useNuxtApp();
|
||||
const { dbUser } = await $client.userAccount.getDBUser.query();
|
||||
|
||||
if(dbUser){
|
||||
this.dbUser = dbUser;
|
||||
if(dbUser.memberships.length > 0){
|
||||
this.activeMembership = dbUser.memberships[0];
|
||||
await this.fetchNotesForCurrentUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async fetchNotesForCurrentUser() {
|
||||
if(!this.activeMembership) { return; }
|
||||
|
||||
const { $client } = useNuxtApp();
|
||||
const { notes } = await $client.notes.getForCurrentUser.query({account_id: this.activeMembership.account_id});
|
||||
if(notes){
|
||||
this.notes = notes;
|
||||
}
|
||||
},
|
||||
async changeActiveMembership(membership: MembershipWithAccount) {
|
||||
if(membership !== this.activeMembership){
|
||||
this.activeMembership = membership;
|
||||
await this.fetchNotesForCurrentUser();
|
||||
}
|
||||
},
|
||||
async changeAccountName(new_name: string){
|
||||
if(!this.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: account } = await $client.userAccount.changeAccountName.useQuery({account_id: this.activeMembership.account_id, new_name});
|
||||
if(account.value?.account){
|
||||
this.activeMembership.account = account.value.account;
|
||||
}
|
||||
},
|
||||
async changeAccountPlan(plan_id: number){
|
||||
if(!this.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: account } = await $client.userAccount.changeAccountPlan.useQuery({account_id: this.activeMembership.account_id, plan_id});
|
||||
if(account.value?.account){
|
||||
this.activeMembership.account = account.value.account;
|
||||
}
|
||||
},
|
||||
async joinUserToAccount(user_id: number){
|
||||
if(!this.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.userAccount.joinUserToAccount.useQuery({account_id: this.activeMembership.account_id, user_id});
|
||||
if(membership.value?.membership){
|
||||
this.activeMembership = membership.value.membership;
|
||||
}
|
||||
},
|
||||
async changeUserAccessWithinAccount(user_id: number, access: ACCOUNT_ACCESS){
|
||||
if(!this.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.userAccount.changeUserAccessWithinAccount.useQuery({account_id: this.activeMembership.account_id, user_id, access});
|
||||
if(membership.value?.membership){
|
||||
this.activeMembership = membership.value.membership;
|
||||
}
|
||||
},
|
||||
async claimOwnershipOfAccount(){
|
||||
if(!this.activeMembership) { return; }
|
||||
const { $client } = useNuxtApp();
|
||||
const { data: membership } = await $client.userAccount.claimOwnershipOfAccount.useQuery({account_id: this.activeMembership.account_id});
|
||||
if(membership.value?.membership){
|
||||
this.activeMembership = membership.value.membership;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
35
stores/auth.store.ts
Normal file
35
stores/auth.store.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { FullDBUser, MembershipWithAccount } from "~~/lib/services/user.account.service"
|
||||
|
||||
interface State {
|
||||
dbUser?: FullDBUser
|
||||
activeMembership: MembershipWithAccount | null
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: (): State => {
|
||||
return {
|
||||
activeMembership: null
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async initUser() {
|
||||
if(!this.dbUser || !this.activeMembership){
|
||||
const { $client } = useNuxtApp();
|
||||
const { dbUser } = await $client.auth.getDBUser.query();
|
||||
|
||||
if(dbUser){
|
||||
this.dbUser = dbUser;
|
||||
if(dbUser.memberships.length > 0){
|
||||
this.activeMembership = dbUser.memberships[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async changeActiveMembership(membership: MembershipWithAccount) {
|
||||
if(membership !== this.activeMembership){
|
||||
this.activeMembership = membership;
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
29
stores/notes.store.ts
Normal file
29
stores/notes.store.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Note } from ".prisma/client"
|
||||
import { defineStore } from "pinia"
|
||||
|
||||
import { useAuthStore } from './auth.store'
|
||||
|
||||
interface State {
|
||||
notes: Note[]
|
||||
}
|
||||
|
||||
export const useNotesStore = defineStore('notes', {
|
||||
state: (): State => {
|
||||
return {
|
||||
notes: [],
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
async fetchNotesForCurrentUser() {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
if(!authStore.activeMembership) { return; }
|
||||
|
||||
const { $client } = useNuxtApp();
|
||||
const { notes } = await $client.notes.getForCurrentUser.query({account_id: authStore.activeMembership.account_id});
|
||||
if(notes){
|
||||
this.notes = notes;
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user