@@ -3,14 +3,19 @@ import { Search } from "@/components/Search";
3
3
import { TeamsCardList } from "@/components/Teams/TeamsCardList" ;
4
4
import { Button } from "@/components/ui/button" ;
5
5
import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card" ;
6
- import { getOrganizationTitle } from "@/data/user/organizations" ;
7
- import { getAllProjectsInOrganization } from "@/data/user/projects" ;
6
+ import { Separator } from "@/components/ui/separator" ;
7
+ import { T } from "@/components/ui/Typography" ;
8
+ import { getLoggedInUserOrganizationRole , getOrganizationTitle } from "@/data/user/organizations" ;
9
+ import { getAllProjectsInOrganization , getProjectsForUser } from "@/data/user/projects" ;
8
10
import { getSlimTeamById , getTeams } from "@/data/user/teams" ;
11
+ import { Tables } from "@/lib/database.types" ;
12
+ import { Enum } from "@/types" ;
13
+ import { serverGetLoggedInUser } from "@/utils/server/serverGetLoggedInUser" ;
9
14
import {
10
15
organizationParamSchema ,
11
16
projectsfilterSchema
12
17
} from "@/utils/zod-schemas/params" ;
13
- import { Layers , Plus } from "lucide-react" ;
18
+ import { Layers , Plus , Settings } from "lucide-react" ;
14
19
import type { Metadata } from 'next' ;
15
20
import Link from "next/link" ;
16
21
import { Suspense } from "react" ;
@@ -23,24 +28,46 @@ import TeamsLoadingFallback from "./TeamsLoadingFallback";
23
28
async function Projects ( {
24
29
organizationId,
25
30
filters,
31
+ userId,
32
+ userRole,
26
33
} : {
27
34
organizationId : string ;
28
35
filters : z . infer < typeof projectsfilterSchema > ;
36
+ userId : string ;
37
+ userRole : Enum < 'organization_member_role' > ;
29
38
} ) {
30
- const projects = await getAllProjectsInOrganization ( {
31
- organizationId,
32
- ...filters ,
33
- } ) ;
39
+ let projects : Tables < 'projects' > [ ] ;
40
+
41
+ if ( userRole === 'admin' ) {
42
+ projects = await getAllProjectsInOrganization ( {
43
+ organizationId,
44
+ ...filters ,
45
+ } ) ;
46
+ } else {
47
+ projects = await getProjectsForUser ( {
48
+ userId,
49
+ userRole,
50
+ organizationId,
51
+ ...filters ,
52
+ } ) ;
53
+ }
54
+
34
55
const projectWithTeamNames = await Promise . all ( projects . map ( async ( project ) => {
35
56
if ( project . team_id ) {
36
- const team = await getSlimTeamById ( project . team_id ) ;
37
- const projectWithTeamName = { ...project , teamName : team . name } ;
38
- return projectWithTeamName ;
57
+ try {
58
+ const team = await getSlimTeamById ( project . team_id ) ;
59
+ return { ...project , teamName : team ?. name || 'Unknown Team' } ;
60
+ } catch ( error ) {
61
+ console . error ( `Error fetching team for project ${ project . id } :` , error ) ;
62
+ return { ...project } ;
63
+ }
39
64
}
40
65
return project ;
41
66
} ) ) ;
67
+
42
68
return < ProjectsCardList projects = { projectWithTeamNames } /> ;
43
69
}
70
+
44
71
async function Teams ( {
45
72
organizationId,
46
73
filters,
@@ -65,38 +92,60 @@ export type DashboardProps = {
65
92
async function Dashboard ( { params, searchParams } : DashboardProps ) {
66
93
const { organizationId } = organizationParamSchema . parse ( params ) ;
67
94
const validatedSearchParams = projectsfilterSchema . parse ( searchParams ) ;
95
+ const { id : userId } = await serverGetLoggedInUser ( ) ;
96
+ const userRole = await getLoggedInUserOrganizationRole ( organizationId ) ;
68
97
69
98
return (
70
99
< DashboardClientWrapper >
100
+ < div className = "flex justify-between gap-4 w-full" >
101
+ < T . H2 > Dashboard</ T . H2 >
102
+ < Link href = { `/org/${ organizationId } /settings` } >
103
+ < Button className = "w-fit" variant = "outline" >
104
+ < Settings className = "mr-2 h-4 w-4" />
105
+ Organization Settings
106
+ </ Button >
107
+ </ Link >
108
+ </ div >
71
109
< Card >
72
- < CardHeader className = "flex flex-row items-center justify-between space-y-0 pb-6" >
73
- < CardTitle className = "text-3xl font-bold tracking-tight" > Dashboard</ CardTitle >
74
- < div className = "flex space-x-4" >
75
- < Link href = { `/org/${ organizationId } /projects/create` } >
76
- < Button variant = "default" size = "sm" >
77
- < Plus className = "mr-2 h-4 w-4" />
78
- Create Project
79
- </ Button >
80
- </ Link >
81
- </ div >
82
- </ CardHeader >
83
- < CardContent >
84
- < div className = "flex items-center justify-between mb-6" >
85
- < h2 className = "text-2xl font-semibold tracking-tight" > Recent Projects</ h2 >
110
+ < CardHeader >
111
+ < div className = "flex items-center justify-between" >
112
+ < CardTitle >
113
+ Recent Projects
114
+ </ CardTitle >
86
115
< div className = "flex items-center space-x-4" >
87
- < Search className = "w-[200px]" placeholder = "Search projects" />
116
+ < div className = "flex items-center space-x-4" >
117
+ < Search placeholder = "Search projects" />
118
+ { /* <MultiSelect
119
+ options={userTeams.map(team => ({ label: team.name, value: team.id }))}
120
+ placeholder="Filter by teams"
121
+ /> */ }
122
+ </ div >
88
123
< Button variant = "secondary" size = "sm" asChild >
89
124
< Link href = { `/org/${ organizationId } /projects` } >
90
125
< Layers className = "mr-2 h-4 w-4" />
91
126
View all projects
92
127
</ Link >
93
128
</ Button >
129
+ < Separator orientation = "vertical" className = "h-6" />
130
+ < div className = "flex space-x-4" >
131
+ < Link href = { `/org/${ organizationId } /projects/create` } >
132
+ < Button variant = "default" size = "sm" >
133
+ < Plus className = "mr-2 h-4 w-4" />
134
+ Create Project
135
+ </ Button >
136
+ </ Link >
137
+ </ div >
94
138
</ div >
95
139
</ div >
140
+ </ CardHeader >
141
+ < CardContent >
142
+
96
143
< Suspense fallback = { < ProjectsLoadingFallback quantity = { 3 } /> } >
97
144
< Projects
98
145
organizationId = { organizationId }
99
146
filters = { validatedSearchParams }
147
+ userId = { userId }
148
+ userRole = { userRole }
100
149
/>
101
150
{ validatedSearchParams . query && (
102
151
< p className = "mt-4 text-sm text-muted-foreground" >
@@ -143,7 +192,6 @@ async function Dashboard({ params, searchParams }: DashboardProps) {
143
192
export async function generateMetadata ( { params } : DashboardProps ) : Promise < Metadata > {
144
193
const { organizationId } = organizationParamSchema . parse ( params ) ;
145
194
const title = await getOrganizationTitle ( organizationId ) ;
146
- console . log ( 'Organization title' , title ) ;
147
195
148
196
return {
149
197
title : `Dashboard | ${ title } ` ,
0 commit comments