create utility types on server - include Account with Membership - start moving account functions to store actions

This commit is contained in:
Michael Dausmann
2023-02-20 00:21:56 +11:00
parent b3ee03b5c3
commit fbe2436231
6 changed files with 65 additions and 29 deletions

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { MembershipWithAccount } from '~~/lib/services/user.account.service';
import { storeToRefs } from 'pinia';
const supabase = useSupabaseAuthClient();
@@ -19,9 +20,18 @@ async function signout() {
<template>
<div>
<h3>Nuxt 3 Boilerplate - AppHeader</h3>
<!-- logged in & sign out -->
<div v-if="user">logged in as: {{ user.email }}: <button @click="signout()">Sign Out</button></div>
<div v-if="!user">Not Logged in</div>
<button v-for="membership in dbUser?.dbUser.memberships" @click="store.changeActiveMembership(membership)">{{ membership.account_id }}<span v-if="membership.account_id === activeMembership?.account_id">*</span></button>
<!-- Account Switching -->
<p v-if="(dbUser?.dbUser?.memberships) && (dbUser.dbUser.memberships.length > 0)">
<span>Switch Account.. </span>
<button v-for="membership in dbUser?.dbUser.memberships" @click="store.changeActiveMembership(((membership as unknown) as MembershipWithAccount))"> <!-- This cast is infuriating -->
{{ membership.account.name }}
<span v-if="membership.account_id === activeMembership?.account_id">*</span>
</button>
</p>
<hr>
</div>
</template>

View File

@@ -1,8 +1,11 @@
import { ACCOUNT_ACCESS, PrismaClient, User as DBUser, Membership } from '@prisma/client';
import { ACCOUNT_ACCESS, PrismaClient, User, Membership, Account } from '@prisma/client';
import { UtilService } from './util.service';
const TRIAL_PLAN_NAME = '3 Month Trial'; // TODO - some sort of config.. this will change for every use of the boilerplate
export type MembershipWithAccount = (Membership & {account: Account});
export type FullDBUser = (User & { memberships: MembershipWithAccount[]; });
export default class UserAccountService {
private prisma: PrismaClient;
@@ -10,15 +13,34 @@ export default class UserAccountService {
this.prisma = prisma;
}
async getUserBySupabaseId(supabase_uid: string): Promise<(DBUser & { memberships: Membership[]; }) | null> {
return this.prisma.user.findFirst({ where: { supabase_uid }, include: { memberships: true } });
async getUserBySupabaseId(supabase_uid: string): Promise<FullDBUser | null> {
return this.prisma.user.findFirst({
where: { supabase_uid },
include: { memberships: {include: {
account: true
}}}
});
}
async getUserById(user_id: number) {
return this.prisma.user.findFirstOrThrow({ where: { id: user_id }, include: { memberships: true } });
async getFullUserBySupabaseId(supabase_uid: string): Promise<FullDBUser | null> {
return this.prisma.user.findFirst({
where: { supabase_uid },
include: { memberships: {include: {
account: true
}}}
});
}
async createUser( supabase_uid: string, display_name: string ) {
async getUserById(user_id: number): Promise<FullDBUser | null> {
return this.prisma.user.findFirstOrThrow({
where: { id: user_id },
include: { memberships: {include: {
account: true
}}}
});
}
async createUser( supabase_uid: string, display_name: string ): Promise<FullDBUser | null> {
const trialPlan = await this.prisma.plan.findFirstOrThrow({ where: { name: TRIAL_PLAN_NAME}});
return this.prisma.user.create({
data:{
@@ -39,7 +61,9 @@ export default class UserAccountService {
}
}
},
include: { memberships: true },
include: { memberships: {include: {
account: true
}}}
});
}

View File

@@ -14,11 +14,6 @@
await store.initUser();
})
async function changeAccountPlan(){
const { data: account } = await $client.userAccount.changeAccountPlan.useQuery();
console.log(`account with updated plan: ${JSON.stringify(account)}`);
}
async function joinUserToAccount(){
const { data: membership } = await $client.userAccount.joinUserToAccount.useQuery();
console.log(`added membership on current account: ${JSON.stringify(membership)}`);
@@ -39,7 +34,7 @@
<h3>Notes Dashboard</h3>
<p v-for="note in notes">{{ note.note_text }}</p>
<button @click.prevent="changeAccountPlan()">Change Account Plan</button>
<button @click.prevent="store.changeAccountPlan(2)">Change Account Plan to 2</button>
<button @click.prevent="joinUserToAccount()">Join user to account</button>
<button @click.prevent="changeUserAccessWithinAccount()">Change user access within account</button>
<button @click.prevent="claimOwnershipOfAccount()">Claim Account Ownership</button>

View File

@@ -1,15 +1,15 @@
import { Membership, PrismaClient, User as DBUser } from '@prisma/client';
import { PrismaClient } from '@prisma/client';
import { inferAsyncReturnType, TRPCError } from '@trpc/server'
import { H3Event } from 'h3';
import { serverSupabaseClient } from '#supabase/server';
import SupabaseClient from '@supabase/supabase-js/dist/module/SupabaseClient';
import { User } from '@supabase/supabase-js';
import UserAccountService from '~~/lib/services/user.account.service';
import UserAccountService, { FullDBUser } from '~~/lib/services/user.account.service';
let prisma: PrismaClient | undefined
let supabase: SupabaseClient | undefined
let user: User | null;
let dbUser: (DBUser & { memberships: Membership[]; }) | null
let dbUser: FullDBUser | null
export async function createContext(event: H3Event){
if (!supabase) {
@@ -23,7 +23,7 @@ export async function createContext(event: H3Event){
}
if (!dbUser && user) {
const userService = new UserAccountService(prisma);
dbUser = await userService.getUserBySupabaseId(user.id);
dbUser = await userService.getFullUserBySupabaseId(user.id);
if (!dbUser && user) {
dbUser = await userService.createUser( user.id, user.user_metadata.full_name );

View File

@@ -1,6 +1,7 @@
import UserAccountService from '~~/lib/services/user.account.service';
import { protectedProcedure, router } from '../trpc'
import { ACCOUNT_ACCESS } from '@prisma/client';
import { z } from 'zod';
export const userAccountRouter = router({
getDBUser: protectedProcedure
@@ -10,10 +11,10 @@ export const userAccountRouter = router({
}
}),
changeAccountPlan: protectedProcedure
.query(async ({ ctx }) => {
.input(z.object({ account_id: z.number(), plan_id: z.number() }))
.query(async ({ ctx, input }) => {
const uaService = new UserAccountService(ctx.prisma);
// TODO - account id and plan should be an input param and then the ternary removed
const account = (ctx.dbUser?.memberships[0].account_id)?await uaService.changeAccountPlan(ctx.dbUser?.memberships[0].account_id, 2):null;
const account = await uaService.changeAccountPlan(input.account_id, input.plan_id);
return {
account,
}

View File

@@ -1,10 +1,10 @@
import { Membership, Note, User } from ".prisma/client"
import { defineStore } from "pinia"
export type DBUser = User & { memberships: Membership[]; }
import { FullDBUser, MembershipWithAccount } from "~~/lib/services/user.account.service"
interface State {
dbUser?: DBUser
activeMembership: Membership | null
dbUser?: FullDBUser
activeMembership: MembershipWithAccount | null
notes: Note[]
}
@@ -28,9 +28,7 @@ export const useAppStore = defineStore('app', {
}
},
async fetchNotesForCurrentUser() {
if(!this.activeMembership) {
return;
}
if(!this.activeMembership) { return; }
const { $client } = useNuxtApp();
const { data: foundNotes } = await $client.notes.getForCurrentUser.useQuery({account_id: this.activeMembership.account_id});
@@ -38,11 +36,19 @@ export const useAppStore = defineStore('app', {
this.notes = foundNotes.value.notes;
}
},
async changeActiveMembership(membership: Membership) {
async changeActiveMembership(membership: MembershipWithAccount) {
if(membership !== this.activeMembership){
this.activeMembership = membership;
await this.fetchNotesForCurrentUser();
}
},
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;
}
}
}
});