diff --git a/apps/client-ts/src/components/RootLayout/index.tsx b/apps/client-ts/src/components/RootLayout/index.tsx index be61586d7..0354317ab 100644 --- a/apps/client-ts/src/components/RootLayout/index.tsx +++ b/apps/client-ts/src/components/RootLayout/index.tsx @@ -12,8 +12,6 @@ import { useStytchUser } from '@stytch/nextjs'; import useProfile from '@/hooks/useProfile'; import useProfileStore from '@/state/profileStore'; import useProjectStore from '@/state/projectStore'; -import useProjects from '@/hooks/useProjects'; -import useProjectsByUser from '@/hooks/useProjectsByUser'; const useDeviceSize = () => { @@ -41,9 +39,9 @@ export const RootLayout = () => { const [width, height] = useDeviceSize(); const router = useRouter() const base = process.env.NEXT_PUBLIC_WEBAPP_DOMAIN; - const [userId, setUserId] = useState(""); const { user } = useStytchUser(); const {data, isLoading, isError, error} = useProfile(user?.user_id!); + if(isLoading) { console.log("loading profiles"); } @@ -53,28 +51,22 @@ export const RootLayout = () => { const { profile, setProfile } = useProfileStore(); - const { idProject, setIdProject } = useProjectStore(); - //const { data : projects, isLoading: isloadingProjects } = useProjects(); - const {data : projects, isLoading: isloadingProjects} = useProjectsByUser(userId); - useEffect(()=>{ - if(projects && projects[0]){ - setIdProject(projects[0].id_project); - } - },[projects, setIdProject]) + const { setIdProject } = useProjectStore(); - useEffect(()=> { + useEffect(()=> { if(data){ - //console.log("data is "+ JSON.stringify(data)); + //console.log("data from bundled call is "+ JSON.stringify(data)); setProfile({ id_user: data.id_user, email: data.email!, first_name: data.first_name, last_name: data.last_name, + projects: data.projects //id_organization: data.id_organization as string, }) - //setUserId(data.id_user); + setIdProject(data.projects[0].id_project) } - }, [data, setProfile]); + }, [data, setIdProject, setProfile]); const handlePageChange = (page: string) => { @@ -100,7 +92,7 @@ export const RootLayout = () => { - + -interface TeamSwitcherProps extends PopoverTriggerProps {} +interface TeamSwitcherProps extends PopoverTriggerProps { + userId: string; +} interface ModalObj { open: boolean; status?: number; // 0 for org, 1 for project } -export default function TeamSwitcher({ className }: TeamSwitcherProps) { +export default function TeamSwitcher({ className, userId }: TeamSwitcherProps) { const [open, setOpen] = useState(false) - const [userId, setUserId] = useState(""); - const [showNewDialog, setShowNewDialog] = useState({ open: false, }) - //const { data : orgs, isLoading: isloadingOrganisations } = useOrganisations(); - //const { data : projects, isLoading: isloadingProjects } = useProjects(); - const { idProject, setIdProject } = useProjectStore(); const { profile } = useProfileStore(); - const {data : projects, isLoading: isloadingProjects} = useProjectsByUser(profile?.id_user!); - - - useEffect(()=>{ - if(projects && projects[0]){ - setIdProject(projects[0].id_project); - } - },[projects, setIdProject]) - - /*useEffect(() => { - if(profile && profile.id_user){ - setUserId(profile.id_user) - } - }, [profile])*/ + const projects = profile?.projects; const handleOpenChange = (open: boolean) => { setShowNewDialog(prevState => ({ ...prevState, open })); @@ -139,7 +119,7 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) { aria-label="Select a team" className={cn("w-[250px] justify-between", className)} > - {projects && projects.length > 0 ? projects[0].name : isloadingProjects ? : "No projects found"} + {projects && projects.length > 0 ? projects[0].name : "No projects found"} @@ -150,7 +130,7 @@ export default function TeamSwitcher({ className }: TeamSwitcherProps) { Not found. { - !isloadingProjects && projects && projects.length > 0 ? projects.map((project) => ( + projects && projects.length > 0 ? projects.map((project) => ( { diff --git a/apps/client-ts/src/hooks/useProfile.tsx b/apps/client-ts/src/hooks/useProfile.tsx index bac61afa2..b1f0a67d0 100644 --- a/apps/client-ts/src/hooks/useProfile.tsx +++ b/apps/client-ts/src/hooks/useProfile.tsx @@ -1,11 +1,12 @@ import config from '@/lib/config'; import { useQuery } from '@tanstack/react-query'; import { users as User } from 'api'; +import { projects as Project } from 'api'; const useProfile = (stytchUserId: string) => { return useQuery({ queryKey: ['profile', stytchUserId], - queryFn: async (): Promise => { + queryFn: async (): Promise => { const response = await fetch(`${config.API_URL}/auth/users/${stytchUserId}`); if (!response.ok) { throw new Error('Network response was not ok'); diff --git a/apps/client-ts/src/state/profileStore.ts b/apps/client-ts/src/state/profileStore.ts index 453366258..64ea05259 100644 --- a/apps/client-ts/src/state/profileStore.ts +++ b/apps/client-ts/src/state/profileStore.ts @@ -1,6 +1,8 @@ import { create } from 'zustand'; +import { projects as Project } from 'api'; -interface User { +type User_ = User & { projects: Project[] }; +type User = { id_user: string; email: string; first_name: string; @@ -9,14 +11,14 @@ interface User { } interface ProfileState { - profile: User | null; - setProfile: (profile: User) => void; + profile: User_ | null; + setProfile: (profile: User_) => void; } const useProfileStore = create()((set) => ({ profile: null, - setProfile: (profile_: User) => set({ profile: profile_ }), + setProfile: (profile_: User_) => set({ profile: profile_ }), })); export default useProfileStore; diff --git a/packages/api/prisma/schema.prisma b/packages/api/prisma/schema.prisma index ff8bb5b14..adde91bb6 100644 --- a/packages/api/prisma/schema.prisma +++ b/packages/api/prisma/schema.prisma @@ -107,10 +107,11 @@ model webhooks_reponses { /// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments model connection_strategies { - id_connection_strategy String @id(map: "pk_connection_strategies") @db.Uuid + id_connection_strategy String @id(map: "pk_connection_strategies") @db.Uuid status Boolean type String - id_project String? @db.Uuid + id_project String? @db.Uuid + cs_entities cs_entities[] } model tcg_collections { @@ -170,9 +171,9 @@ model connections { expiration_timestamp DateTime? @db.Timestamp(6) created_at DateTime @db.Timestamp(6) connection_token String? + vertical String id_project String @db.Uuid id_linked_user String @db.Uuid - vertical String? linked_users linked_users @relation(fields: [id_linked_user], references: [id_linked_user], onDelete: NoAction, onUpdate: NoAction, map: "fk_11") projects projects @relation(fields: [id_project], references: [id_project], onDelete: NoAction, onUpdate: NoAction, map: "fk_9") @@ -413,21 +414,26 @@ model crm_users { } model cs_attributes { - id_cs_attribute String @id(map: "pk_ct_attributes") @db.Uuid + id_cs_attribute String @id(map: "pk_ct_attributes") @db.Uuid attribute_slug String data_type String - id_cs_entity String @db.Uuid + id_cs_entity String @db.Uuid + cs_entities cs_entities @relation(fields: [id_cs_entity], references: [id_cs_entity], onDelete: NoAction, onUpdate: NoAction, map: "fk_cs_entity") + cs_values cs_values[] } model cs_entities { - id_cs_entity String @id(map: "pk_ct_entities") @db.Uuid - id_connection_strategy String @db.Uuid + id_cs_entity String @id(map: "pk_ct_entities") @db.Uuid + id_connection_strategy String @db.Uuid + cs_attributes cs_attributes[] + connection_strategies connection_strategies @relation(fields: [id_connection_strategy], references: [id_connection_strategy], onDelete: NoAction, onUpdate: NoAction, map: "fk_cs_id") } model cs_values { - id_cs_value String @id(map: "pk_ct_values") @db.Uuid + id_cs_value String @id(map: "pk_ct_values") @db.Uuid value String - id_cs_attribute String @db.Uuid + id_cs_attribute String @db.Uuid + cs_attributes cs_attributes @relation(fields: [id_cs_attribute], references: [id_cs_attribute], onDelete: NoAction, onUpdate: NoAction, map: "fk_cs_attribute") } /// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments diff --git a/packages/api/src/@core/auth/auth.service.ts b/packages/api/src/@core/auth/auth.service.ts index f40607a37..d2a974d1e 100644 --- a/packages/api/src/@core/auth/auth.service.ts +++ b/packages/api/src/@core/auth/auth.service.ts @@ -34,12 +34,21 @@ export class AuthService { } async getUserByStytchId(stytchId: string) { try { - return await this.prisma.users.findUnique({ + const user = await this.prisma.users.findUnique({ where: { id_stytch: stytchId, identification_strategy: 'b2c', }, }); + const projects = await this.prisma.projects.findMany({ + where: { + id_user: user.id_user, + }, + }); + return { + ...user, + projects: projects, + }; } catch (error) { handleServiceError(error, this.logger); } diff --git a/packages/api/swagger/swagger-spec.json b/packages/api/swagger/swagger-spec.json index cb930acc2..5bccad4b7 100644 --- a/packages/api/swagger/swagger-spec.json +++ b/packages/api/swagger/swagger-spec.json @@ -451,6 +451,30 @@ ] } }, + "/projects/{userId}": { + "get": { + "operationId": "getProjectsByUser", + "summary": "Retrieve projects by user", + "parameters": [ + { + "name": "userId", + "required": true, + "in": "path", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "tags": [ + "projects" + ] + } + }, "/projects/create": { "post": { "operationId": "createProject",