Skip to content

Commit 278ce62

Browse files
authored
Merge pull request #2253 from dubinc/sheets-partner-table-fix
Show selected partners in tables
2 parents fd4bd03 + 244d35a commit 278ce62

File tree

5 files changed

+175
-72
lines changed

5 files changed

+175
-72
lines changed

apps/web/lib/swr/use-partners.ts

+14-10
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
import { fetcher } from "@dub/utils";
22
import { useParams } from "next/navigation";
3-
import useSWR from "swr";
3+
import useSWR, { SWRConfiguration } from "swr";
44
import { z } from "zod";
55
import { EnrolledPartnerProps } from "../types";
66
import { partnersQuerySchema } from "../zod/schemas/partners";
77
import useWorkspace from "./use-workspace";
88

99
const partialQuerySchema = partnersQuerySchema.partial();
1010

11-
export default function usePartners({
12-
query,
13-
enabled = true,
14-
}: {
15-
query?: z.infer<typeof partialQuerySchema>;
16-
enabled?: boolean;
17-
} = {}) {
11+
export default function usePartners(
12+
{
13+
query,
14+
enabled = true,
15+
}: {
16+
query?: z.infer<typeof partialQuerySchema>;
17+
enabled?: boolean;
18+
} = {},
19+
swrOptions: SWRConfiguration = {},
20+
) {
1821
const { programId } = useParams();
1922
const { id: workspaceId } = useWorkspace();
2023

21-
const { data, error } = useSWR<EnrolledPartnerProps[]>(
24+
const { data, isLoading, error } = useSWR<EnrolledPartnerProps[]>(
2225
enabled && workspaceId
2326
? `/api/partners?${new URLSearchParams({
2427
workspaceId: workspaceId,
@@ -27,11 +30,12 @@ export default function usePartners({
2730
} as Record<string, any>).toString()}`
2831
: undefined,
2932
fetcher,
33+
swrOptions,
3034
);
3135

3236
return {
3337
data,
34-
loading: !data && !error,
38+
loading: isLoading,
3539
error,
3640
};
3741
}

apps/web/ui/partners/add-edit-discount-sheet.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,10 @@ function DiscountSheetContent({
421421
{!isDefault && program?.id && (
422422
<DiscountPartnersTable
423423
partnerIds={partnerIds || []}
424-
partners={discountPartners || []}
425-
setPartners={(value: string[]) => {
424+
setPartnerIds={(value: string[]) => {
426425
setValue("partnerIds", value);
427426
}}
427+
discountPartners={discountPartners || []}
428428
loading={isLoadingDiscountPartners}
429429
/>
430430
)}

apps/web/ui/partners/add-edit-reward-sheet.tsx

+12-11
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,10 @@ function RewardSheetContent({ setIsOpen, event, reward }: RewardSheetProps) {
136136

137137
useEffect(() => {
138138
if (rewardPartners && rewardPartners.length > 0) {
139-
setValue("partnerIds", rewardPartners.map(partner => partner.id));
139+
setValue(
140+
"partnerIds",
141+
rewardPartners.map((partner) => partner.id),
142+
);
140143
}
141144
}, [rewardPartners, setValue]);
142145

@@ -544,16 +547,14 @@ function RewardSheetContent({ setIsOpen, event, reward }: RewardSheetProps) {
544547
</>
545548
)}
546549

547-
{displayPartners && program?.id && (
548-
<RewardPartnersTable
549-
partnerIds={partnerIds || []}
550-
partners={rewardPartners || []}
551-
setPartners={(value: string[]) => {
552-
setValue("partnerIds", value);
553-
}}
554-
loading={isLoadingRewardPartners}
555-
/>
556-
)}
550+
<RewardPartnersTable
551+
partnerIds={partnerIds || []}
552+
setPartnerIds={(value: string[]) => {
553+
setValue("partnerIds", value);
554+
}}
555+
rewardPartners={rewardPartners || []}
556+
loading={isLoadingRewardPartners}
557+
/>
557558
</div>
558559
</div>
559560

apps/web/ui/partners/discount-partners-table.tsx

+74-26
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,22 @@ import { useDebounce } from "use-debounce";
1010

1111
interface DiscountPartnersTableProps {
1212
partnerIds: string[];
13-
partners: EnrolledPartnerProps[];
14-
setPartners: (value: string[]) => void;
13+
setPartnerIds: (value: string[]) => void;
14+
discountPartners: EnrolledPartnerProps[];
1515
loading: boolean;
1616
}
1717

1818
export function DiscountPartnersTable({
1919
partnerIds,
20-
partners,
21-
setPartners,
20+
setPartnerIds,
21+
discountPartners,
2222
loading,
2323
}: DiscountPartnersTableProps) {
2424
const [search, setSearch] = useState("");
2525
const [debouncedSearch] = useDebounce(search, 500);
26-
const [selectedPartners, setSelectedPartners] =
27-
useState<Pick<EnrolledPartnerProps, "id" | "name" | "email" | "image">[]>();
28-
29-
// Get all partners for the table
30-
const { data: allPartners } = usePartners({});
26+
const [selectedPartners, setSelectedPartners] = useState<
27+
Pick<EnrolledPartnerProps, "id" | "name" | "email" | "image">[]
28+
>([]);
3129

3230
// Get filtered partners for the combobox
3331
const { data: searchPartners } = usePartners({
@@ -36,7 +34,23 @@ export function DiscountPartnersTable({
3634
},
3735
});
3836

39-
const options = useMemo(
37+
// Create a map for faster partner lookups
38+
const partnersMap = useMemo(() => {
39+
if (!searchPartners) return new Map();
40+
return new Map(
41+
searchPartners.map((partner) => [
42+
partner.id,
43+
{
44+
id: partner.id,
45+
name: partner.name,
46+
email: partner.email,
47+
image: partner.image,
48+
},
49+
]),
50+
);
51+
}, [searchPartners]);
52+
53+
const partnersOptions = useMemo(
4054
() =>
4155
searchPartners?.map((partner) => ({
4256
icon: (
@@ -48,38 +62,70 @@ export function DiscountPartnersTable({
4862
),
4963
value: partner.id,
5064
label: partner.name,
51-
})),
65+
})) || [],
5266
[searchPartners],
5367
);
5468

5569
const selectedPartnersOptions = useMemo(
5670
() =>
57-
partnerIds
58-
.map((id) => options?.find(({ value }) => value === id)!)
59-
.filter(Boolean),
60-
[partnerIds, options],
71+
partnersOptions.filter((partner) => partnerIds.includes(partner.value)),
72+
[partnerIds, partnersOptions],
6173
);
6274

75+
// Update selectedPartners when discountPartners changes
6376
useEffect(() => {
64-
setSelectedPartners(partners);
65-
}, [partners]);
77+
if (discountPartners && discountPartners.length > 0) {
78+
setSelectedPartners(discountPartners);
79+
}
80+
}, [discountPartners]);
6681

6782
const handlePartnerSelection = (
6883
selectedOptions: typeof selectedPartnersOptions,
6984
) => {
70-
// Get all currently selected IDs
71-
const currentIds = new Set(partnerIds);
85+
// Get all currently selected partner IDs that are not in the current search results
86+
const currentSelectedIds = new Set(partnerIds);
7287

73-
// Add new selections
74-
selectedOptions.forEach(({ value }) => {
75-
currentIds.add(value);
88+
// Remove deselected partners from current search results
89+
partnersOptions.forEach((option) => {
90+
if (
91+
!selectedOptions.some((selected) => selected.value === option.value)
92+
) {
93+
currentSelectedIds.delete(option.value);
94+
}
7695
});
7796

78-
setPartners(Array.from(currentIds));
97+
// Add newly selected partners
98+
selectedOptions.forEach((option) => {
99+
currentSelectedIds.add(option.value);
100+
});
101+
102+
// Convert to array and update partnerIds
103+
const newPartnerIds = Array.from(currentSelectedIds);
104+
setPartnerIds(newPartnerIds);
105+
106+
// Update selectedPartners to maintain all selected partners
107+
const newSelectedPartners = newPartnerIds
108+
.map((id) => {
109+
// First check existing selected partners
110+
const existingPartner = selectedPartners?.find((p) => p.id === id);
111+
if (existingPartner) return existingPartner;
112+
113+
// Then check discountPartners
114+
const discountPartner = discountPartners?.find((p) => p.id === id);
115+
if (discountPartner) return discountPartner;
116+
117+
// Finally check the partnersMap for new selections
118+
return partnersMap.get(id) || null;
119+
})
120+
.filter(
121+
(partner): partner is NonNullable<typeof partner> => partner !== null,
122+
);
123+
124+
setSelectedPartners(newSelectedPartners);
79125
};
80126

81127
const table = useTable({
82-
data: selectedPartners || [],
128+
data: selectedPartners,
83129
columns: [
84130
{
85131
header: "Partner",
@@ -122,7 +168,9 @@ export function DiscountPartnersTable({
122168
icon={<X className="size-4" />}
123169
className="size-4 rounded-md border-0 bg-neutral-50 p-0 hover:bg-neutral-100"
124170
onClick={() => {
125-
setPartners(partnerIds.filter((id) => id !== row.original.id));
171+
setPartnerIds(
172+
partnerIds.filter((id) => id !== row.original.id),
173+
);
126174
setSelectedPartners(
127175
selectedPartners?.filter(
128176
(partner) => partner.id !== row.original.id,
@@ -154,7 +202,7 @@ export function DiscountPartnersTable({
154202
</label>
155203

156204
<Combobox
157-
options={options}
205+
options={partnersOptions}
158206
selected={selectedPartnersOptions}
159207
setSelected={handlePartnerSelection}
160208
caret

0 commit comments

Comments
 (0)