a tool for shared writing and social publishing
at feature/email 152 lines 4.7 kB view raw
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}