|
1 | 1 | import { auth } from "@/app/lib/auth"; |
2 | 2 | import { db } from "@comp/db"; |
3 | | -import { cache } from "react"; |
| 3 | +// Import types directly from @prisma/client |
| 4 | +import type { |
| 5 | + Member, |
| 6 | + User, |
| 7 | + Policy, |
| 8 | + EmployeeTrainingVideoCompletion, |
| 9 | + Organization, |
| 10 | +} from "@prisma/client"; |
4 | 11 | import { headers } from "next/headers"; |
5 | | -import { EmployeeTasksList } from "./EmployeeTasksList"; |
6 | | - |
7 | | -export async function Overview() { |
8 | | - const policies = await getPolicies(); |
9 | | - const trainingVideos = await getTrainingVideos(); |
10 | | - const member = await getMember(); |
11 | | - |
12 | | - return ( |
13 | | - <div className="space-y-6"> |
14 | | - <div className="flex flex-col gap-1"> |
15 | | - <h1 className="text-2xl font-bold">Welcome back, {member.user.name}</h1> |
16 | | - <p className="text-sm">Please complete the following tasks</p> |
17 | | - </div> |
18 | | - <EmployeeTasksList |
19 | | - policies={policies} |
20 | | - trainingVideos={trainingVideos} |
21 | | - member={member} |
22 | | - /> |
23 | | - </div> |
24 | | - ); |
| 12 | +import { redirect } from "next/navigation"; |
| 13 | +// Removed EmployeeTasksList import as it's not used directly here |
| 14 | +import { NoAccessMessage } from "./NoAccessMessage"; |
| 15 | +// Removed OrganizationSelector import |
| 16 | +import { OrganizationDashboard } from "./OrganizationDashboard"; |
| 17 | + |
| 18 | +// Define the type for the member prop including the user and organization relations |
| 19 | +interface MemberWithUserOrg extends Member { |
| 20 | + user: User; |
| 21 | + organization: Organization; |
25 | 22 | } |
26 | 23 |
|
27 | | -const getMember = cache(async () => { |
| 24 | +// Removed OverviewProps interface and searchParams prop |
| 25 | +// export async function Overview({ searchParams }: OverviewProps) { |
| 26 | +export async function Overview() { |
28 | 27 | const session = await auth.api.getSession({ |
29 | 28 | headers: await headers(), |
30 | 29 | }); |
31 | 30 |
|
32 | 31 | if (!session?.user) { |
33 | | - throw new Error("Unauthorized"); |
| 32 | + redirect("/login"); // Or appropriate login/auth route |
34 | 33 | } |
35 | 34 |
|
36 | | - const member = await db.member.findFirst({ |
| 35 | + // Fetch all memberships for the user, including organization details |
| 36 | + const memberships = await db.member.findMany({ |
37 | 37 | where: { |
38 | 38 | userId: session.user.id, |
39 | | - role: "employee", |
| 39 | + // We might want to filter by role if needed, but let's see all memberships first |
| 40 | + // role: "employee", // Keep commented unless needed |
40 | 41 | }, |
41 | 42 | include: { |
42 | 43 | user: true, |
| 44 | + organization: true, // Include organization details |
43 | 45 | }, |
44 | 46 | }); |
45 | 47 |
|
46 | | - if (!member) { |
47 | | - throw new Error("Unauthorized"); |
| 48 | + // Case 1: No memberships found |
| 49 | + if (memberships.length === 0) { |
| 50 | + return <NoAccessMessage />; |
48 | 51 | } |
49 | 52 |
|
50 | | - return member; |
51 | | -}); |
52 | | - |
53 | | -const getPolicies = cache(async () => { |
54 | | - const member = await getMember(); |
55 | | - const organizationId = member.organizationId; |
| 53 | + // Filter memberships to only those with valid organization data |
| 54 | + const validMemberships = memberships.filter( |
| 55 | + (member): member is MemberWithUserOrg & { organization: Organization } => |
| 56 | + Boolean(member.organization) |
| 57 | + ); |
56 | 58 |
|
57 | | - if (!organizationId) { |
58 | | - throw new Error("Unauthorized"); |
| 59 | + // If after filtering, there are no valid memberships with organizations |
| 60 | + if (validMemberships.length === 0) { |
| 61 | + // This case might indicate memberships exist but lack organization links |
| 62 | + console.warn("User has memberships but none with associated organizations.", { userId: session.user.id }); |
| 63 | + return <NoAccessMessage message="You don't seem to belong to any organizations currently." />; |
59 | 64 | } |
60 | 65 |
|
61 | | - const policies = await db.policy.findMany({ |
62 | | - where: { |
63 | | - organizationId, |
64 | | - isRequiredToSign: true, |
65 | | - }, |
66 | | - }); |
67 | 66 |
|
68 | | - return policies; |
69 | | -}); |
| 67 | + // Render a dashboard for each valid membership |
| 68 | + return ( |
| 69 | + <div className="space-y-8"> {/* Added a wrapper div with spacing */} |
| 70 | + {validMemberships.map((member) => ( |
| 71 | + <OrganizationDashboard |
| 72 | + key={member.organizationId} // Use organizationId as key |
| 73 | + organizationId={member.organizationId} |
| 74 | + member={member} // Pass the full member object (already includes org) |
| 75 | + /> |
| 76 | + ))} |
| 77 | + </div> |
| 78 | + ); |
| 79 | + |
| 80 | + // Removed the logic for OrganizationSelector and single/selected org handling |
| 81 | + /* |
| 82 | + // Extract unique organizations |
| 83 | + const organizations = memberships.reduce((acc, member) => { |
| 84 | + if (member.organization && !acc.some(org => org.id === member.organizationId)) { |
| 85 | + acc.push(member.organization); |
| 86 | + } |
| 87 | + return acc; |
| 88 | + }, [] as Organization[]); |
| 89 | +
|
| 90 | +
|
| 91 | + const selectedOrgId = searchParams?.orgId as string | undefined; |
70 | 92 |
|
71 | | -const getTrainingVideos = cache(async () => { |
72 | | - const member = await getMember(); |
| 93 | + // Case 2: Multiple organizations, and none selected yet OR selected is invalid |
| 94 | + if (organizations.length > 1) { |
| 95 | + const isValidSelection = selectedOrgId && organizations.some(org => org.id === selectedOrgId); |
73 | 96 |
|
74 | | - if (!member) { |
75 | | - throw new Error("Unauthorized"); |
| 97 | + if (!isValidSelection) { |
| 98 | + // If multiple orgs and no valid selection, show selector |
| 99 | + return <OrganizationSelector organizations={organizations} />; |
| 100 | + } |
| 101 | + // If valid selection, proceed to find member and render dashboard (handled below) |
76 | 102 | } |
77 | 103 |
|
78 | | - const organizationId = member.organizationId; |
| 104 | + // Case 3: Exactly one organization OR multiple orgs with a valid selection |
| 105 | + let targetOrgId: string | undefined = undefined; |
| 106 | + let targetMember: MemberWithUserOrg | undefined = undefined; |
| 107 | +
|
| 108 | + if (organizations.length === 1) { |
| 109 | + targetOrgId = organizations[0].id; |
| 110 | + // Find the specific membership for this single organization |
| 111 | + targetMember = memberships.find(m => m.organizationId === targetOrgId); |
| 112 | + } else if (selectedOrgId) { |
| 113 | + // Already validated that selectedOrgId is one of the user's orgs |
| 114 | + targetOrgId = selectedOrgId; |
| 115 | + targetMember = memberships.find(m => m.organizationId === targetOrgId); |
| 116 | + } |
79 | 117 |
|
80 | | - if (!organizationId) { |
81 | | - throw new Error("Unauthorized"); |
| 118 | + // If we have a target organization and member, render the dashboard |
| 119 | + if (targetOrgId && targetMember) { |
| 120 | + // We need the full MemberWithUserOrg type here potentially |
| 121 | + // Ensure targetMember is correctly typed if OrganizationDashboard expects more |
| 122 | + return <OrganizationDashboard organizationId={targetOrgId} member={targetMember as MemberWithUserOrg} />; |
82 | 123 | } |
83 | 124 |
|
84 | | - const trainingVideos = await db.employeeTrainingVideoCompletion.findMany({ |
85 | | - where: { |
86 | | - memberId: member.id, |
87 | | - }, |
88 | | - }); |
| 125 | + // Fallback case (should ideally not be reached with the logic above) |
| 126 | + // If multiple orgs but somehow didn't render selector or dashboard |
| 127 | + if (organizations.length > 1) { |
| 128 | + return <OrganizationSelector organizations={organizations} />; |
| 129 | + } |
89 | 130 |
|
90 | | - return trainingVideos; |
91 | | -}); |
| 131 | + // If single org but couldn't find member (data inconsistency?) |
| 132 | + // Or some other unexpected state |
| 133 | + console.error("Unexpected state in Overview component", { userId: session.user.id, memberships }); |
| 134 | + return <NoAccessMessage message="An unexpected error occurred. Please contact support." />; // Or a more specific error |
| 135 | + */ |
| 136 | +} |
0 commit comments