|
4 | 4 | useOptimistic, |
5 | 5 | useTransition, |
6 | 6 | startTransition, |
| 7 | + useRef, |
7 | 8 | } from "react"; |
8 | 9 | import { useStore } from "@nanostores/react"; |
9 | 10 | import { |
@@ -62,15 +63,12 @@ type ChangeProjectDomainProps = { |
62 | 63 | refresh: () => void; |
63 | 64 | }; |
64 | 65 |
|
65 | | -// type TimeoutId = undefined | ReturnType<typeof setTimeout>; |
66 | | - |
67 | 66 | const ChangeProjectDomain = ({ |
68 | 67 | project, |
69 | 68 | refresh, |
70 | 69 | }: ChangeProjectDomainProps) => { |
71 | 70 | const id = useId(); |
72 | 71 | const publishedOrigin = useStore($publishedOrigin); |
73 | | - const hasProPlan = useStore($userPlanFeatures).hasProPlan; |
74 | 72 |
|
75 | 73 | const [domain, setDomain] = useState(project.domain); |
76 | 74 | const [error, setError] = useState<string>(); |
@@ -112,19 +110,15 @@ const ChangeProjectDomain = ({ |
112 | 110 | status: "PENDING" as const, |
113 | 111 | }; |
114 | 112 |
|
115 | | - const hideDomainCheckbox = project.domainsVirtual.length === 0 && hasProPlan; |
116 | | - |
117 | 113 | return ( |
118 | 114 | <CollapsibleDomainSection |
119 | 115 | title={new URL(publishedOrigin).host} |
120 | 116 | prefix={ |
121 | | - hideDomainCheckbox ? null : ( |
122 | | - <DomainCheckbox |
123 | | - defaultChecked={project.latestBuildVirtual?.domain === domain} |
124 | | - buildId={project.latestBuildVirtual?.buildId} |
125 | | - domain={domain} |
126 | | - ></DomainCheckbox> |
127 | | - ) |
| 117 | + <DomainCheckbox |
| 118 | + defaultChecked={project.latestBuildVirtual?.domain === domain} |
| 119 | + buildId={project.latestBuildVirtual?.buildId} |
| 120 | + domain={domain} |
| 121 | + /> |
128 | 122 | } |
129 | 123 | suffix={ |
130 | 124 | <Grid flow="column" align="center"> |
@@ -208,6 +202,39 @@ const Publish = ({ |
208 | 202 | }) => { |
209 | 203 | const [publishError, setPublishError] = useState<string | undefined>(); |
210 | 204 | const [isPublishing, setIsPublishing] = useOptimistic(false); |
| 205 | + const buttonRef = useRef<HTMLButtonElement>(null); |
| 206 | + const [hasSelectedDomains, setHasSelectedDomains] = useState(false); |
| 207 | + |
| 208 | + useEffect(() => { |
| 209 | + const form = buttonRef.current?.closest("form"); |
| 210 | + |
| 211 | + if (form == null) { |
| 212 | + return; |
| 213 | + } |
| 214 | + |
| 215 | + const handleFormInput = () => { |
| 216 | + const formData = new FormData(form); |
| 217 | + const domainsSelected = formData.getAll(domainToPublishName).length; |
| 218 | + setHasSelectedDomains(domainsSelected > 0); |
| 219 | + }; |
| 220 | + |
| 221 | + const observer = new MutationObserver(() => { |
| 222 | + handleFormInput(); |
| 223 | + }); |
| 224 | + |
| 225 | + observer.observe(form, { |
| 226 | + attributes: true, |
| 227 | + childList: true, |
| 228 | + subtree: true, |
| 229 | + attributeFilter: ["value", "checked"], |
| 230 | + }); |
| 231 | + |
| 232 | + handleFormInput(); |
| 233 | + |
| 234 | + return () => { |
| 235 | + observer.disconnect(); |
| 236 | + }; |
| 237 | + }, []); |
211 | 238 |
|
212 | 239 | const handlePublish = async (formData: FormData) => { |
213 | 240 | setPublishError(undefined); |
@@ -301,13 +328,19 @@ const Publish = ({ |
301 | 328 |
|
302 | 329 | <Tooltip |
303 | 330 | content={ |
304 | | - isPublishInProgress ? "Publish process in progress" : undefined |
| 331 | + isPublishInProgress |
| 332 | + ? "Publish process in progress" |
| 333 | + : hasSelectedDomains |
| 334 | + ? undefined |
| 335 | + : "Select at least one domain to publish" |
305 | 336 | } |
306 | 337 | > |
307 | 338 | <Button |
| 339 | + ref={buttonRef} |
308 | 340 | formAction={handlePublish} |
309 | 341 | color="positive" |
310 | 342 | state={isPublishInProgress ? "pending" : undefined} |
| 343 | + disabled={hasSelectedDomains === false} |
311 | 344 | > |
312 | 345 | Publish |
313 | 346 | </Button> |
|
0 commit comments