Skip to content

Commit 47878d9

Browse files
committed
fix: resolve RLS join bugs and redesign team detail UI
- Fix all 14 RLS join bug instances using two-query approach - overflow/actions.ts: 7 functions fixed - TaskComments.tsx: 5 functions + helper added - InternalProjects.tsx: 2 instances fixed - Add comprehensive RLS join bug documentation - Redesign team detail page with minimalist UI - Convert action buttons to icon-only design - Compact info cards with smaller footprint - Reduce vertical space usage significantly
1 parent d2d9017 commit 47878d9

11 files changed

Lines changed: 908 additions & 590 deletions

File tree

‎apps/codebility/app/home/interns/_components/InternalProjects.tsx‎

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,17 @@ export default function InternalProjects() {
4949
// If no Codebility client found, try to get internal projects another way
5050
if (!clients || clients.length === 0) {
5151
// Alternative: fetch all projects and filter by name patterns
52+
// Step 1: Fetch projects with project_members (no codev join!)
5253
const { data: allProjects, error: projectsError } = await supabase
5354
.from("projects")
5455
.select(
5556
`
5657
*,
5758
project_members (
5859
id,
60+
codev_id,
5961
role,
60-
joined_at,
61-
codev (
62-
id,
63-
first_name,
64-
last_name,
65-
image_url
66-
)
62+
joined_at
6763
)
6864
`,
6965
)
@@ -78,7 +74,45 @@ export default function InternalProjects() {
7874
throw new Error("Failed to fetch projects");
7975
}
8076

81-
setProjects(allProjects || []);
77+
if (!allProjects || allProjects.length === 0) {
78+
setProjects([]);
79+
return;
80+
}
81+
82+
// Step 2: Collect all unique codev_ids from all projects
83+
const allCodevIds = new Set<string>();
84+
allProjects.forEach((project) => {
85+
project.project_members?.forEach((pm: any) => {
86+
if (pm.codev_id) allCodevIds.add(pm.codev_id);
87+
});
88+
});
89+
90+
// Step 3: Fetch codev records separately to bypass RLS join filtering
91+
let codevMap = new Map<string, any>();
92+
93+
if (allCodevIds.size > 0) {
94+
const { data: codevs, error: codevError } = await supabase
95+
.from("codev")
96+
.select("id, first_name, last_name, image_url")
97+
.in("id", Array.from(allCodevIds));
98+
99+
if (codevError) {
100+
console.error("Error fetching codev records for internal projects:", codevError);
101+
} else {
102+
codevs?.forEach((c: any) => codevMap.set(c.id, c));
103+
}
104+
}
105+
106+
// Step 4: Merge codev data back into project_members
107+
const projectsWithMembers = allProjects.map((project) => ({
108+
...project,
109+
project_members: project.project_members?.map((pm: any) => ({
110+
...pm,
111+
codev: codevMap.get(pm.codev_id) ?? null,
112+
})),
113+
}));
114+
115+
setProjects(projectsWithMembers);
82116
return;
83117
}
84118

@@ -88,21 +122,17 @@ export default function InternalProjects() {
88122
}
89123

90124
// Now fetch all projects for this client with their members
125+
// Step 1: Fetch projects with project_members (no codev join!)
91126
const { data: projectsData, error: projectError } = await supabase
92127
.from("projects")
93128
.select(
94129
`
95130
*,
96131
project_members (
97132
id,
133+
codev_id,
98134
role,
99-
joined_at,
100-
codev (
101-
id,
102-
first_name,
103-
last_name,
104-
image_url
105-
)
135+
joined_at
106136
)
107137
`,
108138
)
@@ -115,7 +145,44 @@ export default function InternalProjects() {
115145
throw new Error("Failed to fetch projects");
116146
}
117147

118-
setProjects(projectsData || []);
148+
if (!projectsData || projectsData.length === 0) {
149+
setProjects([]);
150+
} else {
151+
// Step 2: Collect all unique codev_ids from all projects
152+
const allCodevIds = new Set<string>();
153+
projectsData.forEach((project) => {
154+
project.project_members?.forEach((pm: any) => {
155+
if (pm.codev_id) allCodevIds.add(pm.codev_id);
156+
});
157+
});
158+
159+
// Step 3: Fetch codev records separately to bypass RLS join filtering
160+
let codevMap = new Map<string, any>();
161+
162+
if (allCodevIds.size > 0) {
163+
const { data: codevs, error: codevError } = await supabase
164+
.from("codev")
165+
.select("id, first_name, last_name, image_url")
166+
.in("id", Array.from(allCodevIds));
167+
168+
if (codevError) {
169+
console.error("Error fetching codev records for client projects:", codevError);
170+
} else {
171+
codevs?.forEach((c: any) => codevMap.set(c.id, c));
172+
}
173+
}
174+
175+
// Step 4: Merge codev data back into project_members
176+
const projectsWithMembers = projectsData.map((project) => ({
177+
...project,
178+
project_members: project.project_members?.map((pm: any) => ({
179+
...pm,
180+
codev: codevMap.get(pm.codev_id) ?? null,
181+
})),
182+
}));
183+
184+
setProjects(projectsWithMembers);
185+
}
119186

120187
// Set first project as selected by default
121188
if (projectsData && projectsData.length > 0) {

0 commit comments

Comments
 (0)