Skip to content

Commit 05e7b31

Browse files
committed
Fix opt_in_communication column type and add proper tests
1 parent 1e35372 commit 05e7b31

5 files changed

Lines changed: 60 additions & 17 deletions

File tree

src/components/volunteers/VolunteersTable.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,11 @@ export const VolunteersTable = (): React.JSX.Element => {
142142
if (v) options[col.id]?.add(v);
143143
});
144144
} else if (value) {
145-
options[col.id]?.add(String(value));
145+
if (col.id === "opt_in_communication") {
146+
options[col.id]?.add(value ? "Yes" : "No");
147+
} else {
148+
options[col.id]?.add(String(value));
149+
}
146150
}
147151
}
148152
});
@@ -182,9 +186,6 @@ export const VolunteersTable = (): React.JSX.Element => {
182186

183187
return {
184188
...entry.volunteer,
185-
opt_in_communication: entry.volunteer.opt_in_communication
186-
? "Yes"
187-
: "No",
188189
cohorts: entry.cohorts.map(formatTag),
189190
current_roles: entry.roles
190191
.filter((r) => r.type === "current")
@@ -216,7 +217,7 @@ export const VolunteersTable = (): React.JSX.Element => {
216217
useEffect(() => {
217218
let ignore = false;
218219
const applyFilters = async (): Promise<void> => {
219-
if (!allVolunteers) return;
220+
if (!allVolunteers || allVolunteers.length === 0) return;
220221
setGlobalFilter("");
221222
setSorting([]);
222223
setRowSelection({});

src/components/volunteers/types.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ export type VolunteerRow = Database["public"]["Tables"]["Volunteers"]["Row"];
44
export type CohortRow = Database["public"]["Tables"]["Cohorts"]["Row"];
55
export type RoleRow = Database["public"]["Tables"]["Roles"]["Row"];
66

7-
export interface Volunteer extends Omit<VolunteerRow, "opt_in_communication"> {
8-
opt_in_communication: string;
7+
export interface Volunteer extends VolunteerRow {
98
cohorts: string[];
109
prior_roles: string[];
1110
current_roles: string[];

src/components/volunteers/volunteerColumns.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ interface ColumnConfig {
2222
isMulti?: boolean;
2323
size: number;
2424
cell?: (info: CellContext<Volunteer, unknown>) => React.JSX.Element;
25+
accessorFn?: (row: Volunteer) => unknown;
2526
}
2627

2728
const renderMultiTags = (
@@ -133,6 +134,11 @@ const COLUMNS_CONFIG: ColumnConfig[] = [
133134
filterType: "options",
134135
isMulti: false,
135136
size: 150,
137+
accessorFn: (row: Volunteer): string | null => {
138+
if (row.opt_in_communication === true) return "Yes";
139+
if (row.opt_in_communication === false) return "No";
140+
return null;
141+
},
136142
cell: renderSingleTag,
137143
},
138144
{
@@ -155,10 +161,15 @@ export const FILTERABLE_COLUMNS = COLUMNS_CONFIG.filter(
155161
}));
156162

157163
export const getBaseColumns = (): ColumnDef<Volunteer>[] => {
158-
return COLUMNS_CONFIG.map((col) => ({
159-
accessorKey: col.id,
160-
header: () => <HeaderWithIcon icon={col.icon} label={col.label} />,
161-
size: col.size,
162-
...(col.cell ? { cell: col.cell } : {}),
163-
}));
164+
return COLUMNS_CONFIG.map(
165+
(col): ColumnDef<Volunteer> => ({
166+
id: col.id,
167+
header: () => <HeaderWithIcon icon={col.icon} label={col.label} />,
168+
size: col.size,
169+
...(col.accessorFn
170+
? { accessorFn: col.accessorFn }
171+
: { accessorKey: col.id }),
172+
...(col.cell ? { cell: col.cell } : {}),
173+
})
174+
);
164175
};

src/lib/api/getVolunteersByMultipleColumns.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type VolunteerFilterResponse =
5656
* @param op - The global operation on the filters ('AND'/'OR').
5757
*
5858
* @returns A Promise resolving to an object containing:
59-
* - data: Volunteer rows.
59+
* - data: Volunteer ids.
6060
* - error: Error message.
6161
*/
6262
export async function getVolunteersByMultipleColumns(
@@ -83,7 +83,7 @@ export async function getVolunteersByMultipleColumns(
8383
f.field === "prior_roles" ||
8484
f.field === "future_interests"
8585
) {
86-
let roleType;
86+
let roleType: "current" | "prior" | "future_interest";
8787
if (f.field === "current_roles") roleType = "current";
8888
else if (f.field === "prior_roles") roleType = "prior";
8989
else roleType = "future_interest";

tests/lib/api/getVolunteersByMultipleColumns.test.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ describe("getVolunteersByMultipleColumns (integration)", () => {
106106
let volunteer1Id: number; // Role 1, Cohort 1
107107
let volunteer2Id: number; // Role 2, Cohort 1, Cohort 2
108108
let volunteer3Id: number; // Role 1, Role 2, Cohort 2
109-
let role1Id: number, role2Id: number;
109+
let role1Id: number, role2Id: number, role3Id: number, role4Id: number;
110110
let cohort1Id: number, cohort2Id: number;
111111

112112
beforeAll(async () => {
@@ -138,6 +138,8 @@ describe("getVolunteersByMultipleColumns (integration)", () => {
138138
.insert([
139139
makeTestRoleInsert({ name: "TEST_Role1" }),
140140
makeTestRoleInsert({ name: "TEST_Role2" }),
141+
makeTestRoleInsert({ name: "TEST_Role3", type: "prior" }),
142+
makeTestRoleInsert({ name: "TEST_Role4", type: "future_interest" }),
141143
])
142144
.select();
143145

@@ -158,9 +160,11 @@ describe("getVolunteersByMultipleColumns (integration)", () => {
158160
volunteer2Id = v2!.id;
159161
volunteer3Id = v3!.id;
160162

161-
const [r1, r2] = r!;
163+
const [r1, r2, r3, r4] = r!;
162164
role1Id = r1!.id;
163165
role2Id = r2!.id;
166+
role3Id = r3!.id;
167+
role4Id = r4!.id;
164168

165169
const [c1, c2] = c!;
166170
cohort1Id = c1!.id;
@@ -170,9 +174,13 @@ describe("getVolunteersByMultipleColumns (integration)", () => {
170174
.from("VolunteerRoles")
171175
.insert([
172176
makeTestVolunteerRoleInsert(volunteer1Id, role1Id),
177+
makeTestVolunteerRoleInsert(volunteer1Id, role3Id),
173178
makeTestVolunteerRoleInsert(volunteer3Id, role1Id),
179+
makeTestVolunteerRoleInsert(volunteer2Id, role4Id),
174180
makeTestVolunteerRoleInsert(volunteer2Id, role2Id),
175181
makeTestVolunteerRoleInsert(volunteer3Id, role2Id),
182+
makeTestVolunteerRoleInsert(volunteer3Id, role3Id),
183+
makeTestVolunteerRoleInsert(volunteer3Id, role4Id),
176184
]);
177185

178186
const { error: vcError } = await client
@@ -228,6 +236,30 @@ describe("getVolunteersByMultipleColumns (integration)", () => {
228236
expect(ids).not.toContain(volunteer2Id);
229237
});
230238

239+
it("filters by prior_roles", async () => {
240+
const filters: FilterTuple[] = [
241+
{ field: "prior_roles", miniOp: "OR", values: ["TEST_Role3"] },
242+
];
243+
const { data } = await getVolunteersByMultipleColumns(filters, "AND");
244+
const ids = data;
245+
246+
expect(ids).toContain(volunteer1Id);
247+
expect(ids).toContain(volunteer3Id);
248+
expect(ids).not.toContain(volunteer2Id);
249+
});
250+
251+
it("filters by future_interests", async () => {
252+
const filters: FilterTuple[] = [
253+
{ field: "future_interests", miniOp: "OR", values: ["TEST_Role4"] },
254+
];
255+
const { data } = await getVolunteersByMultipleColumns(filters, "AND");
256+
const ids = data;
257+
258+
expect(ids).toContain(volunteer2Id);
259+
expect(ids).toContain(volunteer3Id);
260+
expect(ids).not.toContain(volunteer1Id);
261+
});
262+
231263
it("cohorts by cohort with OR", async () => {
232264
const filters: FilterTuple[] = [
233265
{ field: "cohorts", miniOp: "OR", values: [["Fall", String(TEST_YEAR)]] },

0 commit comments

Comments
 (0)