a tool for shared writing and social publishing
1"use client";
2import { useIdentityData } from "components/IdentityProvider";
3import { useDomainStatus } from "./useDomainStatus";
4import { getDomainAssignment } from "./domainAssignment";
5import { Identity } from "components/IdentityProvider";
6import { GoToArrow } from "components/Icons/GoToArrow";
7
8export type CustomDomain = NonNullable<Identity>["custom_domains"][number];
9
10export function DomainList(props: {
11 onSelectDomain: (domain: string) => void;
12 filter?: (domain: CustomDomain) => boolean;
13}) {
14 let { identity } = useIdentityData();
15 let domains = identity?.custom_domains || [];
16 if (props.filter) domains = domains.filter(props.filter);
17
18 let pubDomains = domains.filter(
19 (d) => getDomainAssignment(d).type === "publication",
20 );
21 let leafletDomains = domains.filter(
22 (d) => getDomainAssignment(d).type === "document",
23 );
24 let unassignedDomains = domains.filter(
25 (d) => getDomainAssignment(d).type === "unassigned",
26 );
27
28 return (
29 <div className="flex flex-col gap-2 text-secondary">
30 {pubDomains.length > 0 && (
31 <div className="flex flex-col gap-0.5">
32 <div className="font-bold text-secondary">Publications</div>
33 {pubDomains.map((domain) => (
34 <DomainGroup
35 key={domain.domain}
36 domain={domain}
37 onSelect={() => props.onSelectDomain(domain.domain)}
38 showBase={false}
39 />
40 ))}
41 </div>
42 )}
43 {pubDomains.length > 0 && leafletDomains.length > 0 && (
44 <hr className="border-border-light" />
45 )}
46 {leafletDomains.length > 0 && (
47 <div className="flex flex-col gap-0.5">
48 <div className="font-bold text-secondary">Leaflets</div>
49 {leafletDomains.map((domain) => (
50 <DomainGroup
51 key={domain.domain}
52 domain={domain}
53 onSelect={() => props.onSelectDomain(domain.domain)}
54 showBase
55 />
56 ))}
57 </div>
58 )}
59 {unassignedDomains.length > 0 && (
60 <>
61 {(pubDomains.length > 0 || leafletDomains.length > 0) && (
62 <hr className="border-border-light my-1" />
63 )}
64 <div className="flex flex-col gap-0.5">
65 <div className="font-bold text-secondary">Unassigned</div>
66 {unassignedDomains.map((domain) => (
67 <UnassignedDomainRow
68 key={domain.domain}
69 domain={domain}
70 onSelect={() => props.onSelectDomain(domain.domain)}
71 />
72 ))}
73 </div>
74 </>
75 )}
76 </div>
77 );
78}
79
80function DomainGroup(props: {
81 domain: CustomDomain;
82 onSelect: () => void;
83 showBase: boolean;
84}) {
85 let assignment = getDomainAssignment(props.domain);
86
87 return (
88 <div className="flex flex-col gap-0.5">
89 {props.showBase && (
90 <button
91 type="button"
92 className="text-secondary font-normal! text-left flex gap-2 menuItem -mx-[8px] items-center py-0.5!"
93 onClick={props.onSelect}
94 >
95 <div className="grow truncate min-w-0">{props.domain.domain}</div>
96 <div className="text-sm text-tertiary font-normal shrink-0">
97 {props.domain.custom_domain_routes.length} leaflet
98 {props.domain.custom_domain_routes.length === 1 ? "" : "s"}
99 </div>
100 <GoToArrow className="shrink-0" />
101 </button>
102 )}
103 {assignment.type === "publication" && (
104 <SubDomainRow
105 path="/"
106 label={props.domain.domain}
107 onSelect={props.onSelect}
108 />
109 )}
110 </div>
111 );
112}
113
114function SubDomainRow(props: {
115 path: string;
116 label: string;
117 onSelect: () => void;
118}) {
119 return (
120 <button
121 type="button"
122 className="text-secondary font-normal! text-left flex gap-2 menuItem -mx-[8px] items-center py-0.5!"
123 onClick={props.onSelect}
124 >
125 <div className="grow flex gap-2 items-center justify-between w-full truncate">
126 <div className="grow truncate">{props.label}</div>
127 <GoToArrow />
128 </div>
129 </button>
130 );
131}
132
133function UnassignedDomainRow(props: {
134 domain: CustomDomain;
135 onSelect: () => void;
136}) {
137 let { pending } = useDomainStatus(props.domain.domain);
138
139 return (
140 <button
141 type="button"
142 className="py-0! flex gap-2 font-normal! items-center text-left menuItem -mx-[8px]"
143 onClick={props.onSelect}
144 >
145 <div className="grow truncate min-w-0">{props.domain.domain}</div>
146 {pending && (
147 <div className="text-sm text-tertiary animate-pulse">unverified</div>
148 )}
149 <GoToArrow />
150 </button>
151 );
152}