create utility types on server - include Account with Membership - start moving account functions to store actions
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}}}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user