@@ -166,136 +166,28 @@ const StatusIcon = (props: { projectDomain: Domain; isLoading: boolean }) => {
166
166
) ;
167
167
} ;
168
168
169
- const DomainConfig = ( {
169
+ const DomainItem = ( {
170
+ initiallyOpen,
170
171
projectDomain,
171
- onUpdateStatus,
172
+ project,
173
+ refresh,
172
174
} : {
173
- projectDomain : Domain ;
174
- onUpdateStatus : ( ) => void ;
175
- } ) => {
176
- const { load : findDomainRegistrar , data : registrar } =
177
- trpcClient . domain . findDomainRegistrar . useQuery ( ) ;
178
- const cname = extractCname ( projectDomain . domain ) ;
179
- useEffect ( ( ) => {
180
- if ( cname === "@" ) {
181
- findDomainRegistrar ( { domain : projectDomain . domain } ) ;
182
- }
183
- } , [ projectDomain . domain , cname ] ) ;
184
- const publisherHost = useStore ( $publisherHost ) ;
185
-
186
- const cnameRecord = {
187
- // use alias for domain root when supported to avoid conflicting
188
- // with MX, NS etc records
189
- type : cname === "@" && registrar ?. alias ? "ALIAS" : "CNAME" ,
190
- host : cname ,
191
- value : `${ projectDomain . cname } .customers.${ publisherHost } ` ,
192
- ttl : 300 ,
193
- } as const ;
194
-
195
- const txtRecord = {
196
- type : "TXT" ,
197
- host : cname === "@" ? "_webstudio_is" : `_webstudio_is.${ cname } ` ,
198
- value : projectDomain . expectedTxtRecord ,
199
- ttl : 300 ,
200
- } as const ;
201
-
202
- const dnsRecords = [ cnameRecord , txtRecord ] ;
203
-
204
- return (
205
- < >
206
- < Text color = "subtle" >
207
- < strong > To verify your domain:</ strong >
208
- < br />
209
- Visit the admin console of your domain registrar (the website you
210
- purchased your domain from) and create one < strong > CNAME</ strong > record
211
- and one < strong > TXT</ strong > record with the values shown below:
212
- </ Text >
213
-
214
- < Grid
215
- gap = { 2 }
216
- css = { { gridTemplateColumns : `${ theme . spacing [ 18 ] } 1fr 1fr` } }
217
- >
218
- < Text color = "subtle" variant = "titles" >
219
- TYPE
220
- </ Text >
221
- < Text color = "subtle" variant = "titles" >
222
- NAME
223
- </ Text >
224
- < Text color = "subtle" variant = "titles" >
225
- VALUE
226
- </ Text >
227
-
228
- { dnsRecords . map ( ( record , index ) => (
229
- < Fragment key = { index } >
230
- < InputEllipsis readOnly value = { record . type } />
231
- < InputEllipsis
232
- readOnly
233
- value = { record . host }
234
- suffix = {
235
- < CopyToClipboard text = { record . host } >
236
- < NestedInputButton type = "button" >
237
- < CopyIcon />
238
- </ NestedInputButton >
239
- </ CopyToClipboard >
240
- }
241
- />
242
- < InputEllipsis
243
- readOnly
244
- value = { record . value }
245
- suffix = {
246
- < CopyToClipboard text = { record . value } >
247
- < NestedInputButton type = "button" >
248
- < CopyIcon />
249
- </ NestedInputButton >
250
- </ CopyToClipboard >
251
- }
252
- />
253
- </ Fragment >
254
- ) ) }
255
- </ Grid >
256
-
257
- < Grid
258
- gap = { 2 }
259
- align = { "center" }
260
- css = { {
261
- gridTemplateColumns : `1fr auto 1fr` ,
262
- } }
263
- >
264
- < Separator css = { { alignSelf : "unset" } } />
265
- < Text color = "main" > OR</ Text >
266
- < Separator css = { { alignSelf : "unset" } } />
267
- </ Grid >
268
-
269
- < Entri
270
- dnsRecords = { dnsRecords }
271
- domain = { projectDomain . domain }
272
- onClose = { ( ) => {
273
- // Sometimes Entri modal dialog hangs even if it's successful,
274
- // until they fix that, we'll just refresh the status here on every onClose event
275
- onUpdateStatus ( ) ;
276
- } }
277
- />
278
- </ >
279
- ) ;
280
- } ;
281
-
282
- const DomainItem = ( props : {
283
175
initiallyOpen : boolean ;
284
176
projectDomain : Domain ;
285
- refresh : ( ) => Promise < void > ;
286
177
project : Project ;
178
+ refresh : ( ) => Promise < void > ;
287
179
} ) => {
288
180
const timeSinceLastUpdateMs =
289
- Date . now ( ) - new Date ( props . projectDomain . updatedAt ) . getTime ( ) ;
181
+ Date . now ( ) - new Date ( projectDomain . updatedAt ) . getTime ( ) ;
290
182
291
183
const DAY_IN_MS = 24 * 60 * 60 * 1000 ;
292
184
293
- const status = props . projectDomain . verified
294
- ? ( `VERIFIED_${ props . projectDomain . status } ` as `VERIFIED_${DomainStatus } `)
185
+ const status = projectDomain . verified
186
+ ? ( `VERIFIED_${ projectDomain . status } ` as `VERIFIED_${DomainStatus } `)
295
187
: `UNVERIFIED` ;
296
188
297
189
const [ isStatusLoading , setIsStatusLoading ] = useState (
298
- props . initiallyOpen ||
190
+ initiallyOpen ||
299
191
status === "VERIFIED_ACTIVE" ||
300
192
timeSinceLastUpdateMs > DAY_IN_MS
301
193
? false
@@ -310,16 +202,16 @@ const DomainItem = (props: {
310
202
const handleRemoveDomain = async ( ) => {
311
203
setIsRemoveInProgress ( true ) ;
312
204
const result = await nativeClient . domain . remove . mutate ( {
313
- projectId : props . projectDomain . projectId ,
314
- domainId : props . projectDomain . domainId ,
205
+ projectId : projectDomain . projectId ,
206
+ domainId : projectDomain . domainId ,
315
207
} ) ;
316
208
317
209
if ( result . success === false ) {
318
210
toast . error ( result . error ) ;
319
211
return ;
320
212
}
321
213
322
- await props . refresh ( ) ;
214
+ await refresh ( ) ;
323
215
} ;
324
216
325
217
const [ verifyError , setVerifyError ] = useState < string | undefined > ( undefined ) ;
@@ -329,16 +221,16 @@ const DomainItem = (props: {
329
221
setIsCheckStateInProgress ( true ) ;
330
222
331
223
const verifyResult = await nativeClient . domain . verify . mutate ( {
332
- projectId : props . projectDomain . projectId ,
333
- domainId : props . projectDomain . domainId ,
224
+ projectId : projectDomain . projectId ,
225
+ domainId : projectDomain . domainId ,
334
226
} ) ;
335
227
336
228
if ( verifyResult . success === false ) {
337
229
setVerifyError ( verifyResult . error ) ;
338
230
return ;
339
231
}
340
232
341
- await props . refresh ( ) ;
233
+ await refresh ( ) ;
342
234
} ) ;
343
235
344
236
const [ updateStatusError , setUpdateStatusError ] = useState <
@@ -350,8 +242,8 @@ const DomainItem = (props: {
350
242
setIsCheckStateInProgress ( true ) ;
351
243
352
244
const updateStatusResult = await nativeClient . domain . updateStatus . mutate ( {
353
- projectId : props . projectDomain . projectId ,
354
- domain : props . projectDomain . domain ,
245
+ projectId : projectDomain . projectId ,
246
+ domain : projectDomain . domain ,
355
247
} ) ;
356
248
357
249
setIsStatusLoading ( false ) ;
@@ -361,7 +253,7 @@ const DomainItem = (props: {
361
253
return ;
362
254
}
363
255
364
- await props . refresh ( ) ;
256
+ await refresh ( ) ;
365
257
} ) ;
366
258
367
259
const onceRef = useRef ( false ) ;
@@ -387,43 +279,69 @@ const DomainItem = (props: {
387
279
} ) ;
388
280
} , [ status , handleVerify , handleUpdateStatus , isStatusLoading ] ) ;
389
281
390
- const domainStatus = getStatus ( props . projectDomain ) ;
282
+ const domainStatus = getStatus ( projectDomain ) ;
391
283
392
284
const { isVerifiedActive, text } = getStatusText ( {
393
- projectDomain : props . projectDomain ,
285
+ projectDomain,
394
286
isLoading : false ,
395
287
} ) ;
396
288
289
+ const publisherHost = useStore ( $publisherHost ) ;
290
+ const { load : findDomainRegistrar , data : registrar } =
291
+ trpcClient . domain . findDomainRegistrar . useQuery ( ) ;
292
+ const cname = extractCname ( projectDomain . domain ) ;
293
+ useEffect ( ( ) => {
294
+ if ( cname === "@" ) {
295
+ findDomainRegistrar ( { domain : projectDomain . domain } ) ;
296
+ }
297
+ } , [ projectDomain . domain , cname ] ) ;
298
+ const dnsRecords = [
299
+ {
300
+ // use alias for domain root when supported to avoid conflicting
301
+ // with MX, NS etc records
302
+ type : cname === "@" && registrar ?. alias ? "ALIAS" : "CNAME" ,
303
+ host : cname ,
304
+ value : `${ projectDomain . cname } .customers.${ publisherHost } ` ,
305
+ ttl : 300 ,
306
+ } as const ,
307
+ {
308
+ type : "TXT" ,
309
+ host : cname === "@" ? "_webstudio_is" : `_webstudio_is.${ cname } ` ,
310
+ value : projectDomain . expectedTxtRecord ,
311
+ ttl : 300 ,
312
+ } as const ,
313
+ ] ;
314
+
397
315
return (
398
316
< CollapsibleDomainSection
399
317
prefix = {
400
318
< DomainCheckbox
401
- buildId = { props . projectDomain . latestBuildVirtual ?. buildId }
319
+ buildId = { projectDomain . latestBuildVirtual ?. buildId }
402
320
defaultChecked = {
403
- props . projectDomain . latestBuildVirtual ?. buildId != null &&
404
- props . projectDomain . latestBuildVirtual ?. buildId ===
405
- props . project . latestBuildVirtual ?. buildId
321
+ projectDomain . latestBuildVirtual ?. buildId != null &&
322
+ projectDomain . latestBuildVirtual ?. buildId ===
323
+ project . latestBuildVirtual ?. buildId
406
324
}
407
- domain = { props . projectDomain . domain }
325
+ domain = { projectDomain . domain }
408
326
disabled = { domainStatus !== "VERIFIED_ACTIVE" }
409
327
/>
410
328
}
411
- initiallyOpen = { props . initiallyOpen }
412
- title = { props . projectDomain . domain }
329
+ initiallyOpen = { initiallyOpen }
330
+ title = { projectDomain . domain }
413
331
suffix = {
414
332
< Grid flow = "column" >
415
333
< StatusIcon
416
334
isLoading = { isStatusLoading }
417
- projectDomain = { props . projectDomain }
335
+ projectDomain = { projectDomain }
418
336
/>
419
337
420
- < Tooltip content = { `Proceed to ${ props . projectDomain . domain } ` } >
338
+ < Tooltip content = { `Proceed to ${ projectDomain . domain } ` } >
421
339
< IconButton
422
340
type = "button"
423
341
tabIndex = { - 1 }
424
342
disabled = { status !== "VERIFIED_ACTIVE" }
425
343
onClick = { ( event ) => {
426
- const url = new URL ( `https://${ props . projectDomain . domain } ` ) ;
344
+ const url = new URL ( `https://${ projectDomain . domain } ` ) ;
427
345
window . open ( url . href , "_blank" ) ;
428
346
event . preventDefault ( ) ;
429
347
} }
@@ -503,9 +421,76 @@ const DomainItem = (props: {
503
421
) }
504
422
</ Grid >
505
423
506
- < DomainConfig
507
- projectDomain = { props . projectDomain }
508
- onUpdateStatus = { ( ) => {
424
+ < Text color = "subtle" >
425
+ < strong > To verify your domain:</ strong >
426
+ < br />
427
+ Visit the admin console of your domain registrar (the website you
428
+ purchased your domain from) and create one < strong > CNAME</ strong > { " " }
429
+ record and one < strong > TXT</ strong > record with the values shown
430
+ below:
431
+ </ Text >
432
+
433
+ < Grid
434
+ gap = { 2 }
435
+ css = { { gridTemplateColumns : `${ theme . spacing [ 18 ] } 1fr 1fr` } }
436
+ >
437
+ < Text color = "subtle" variant = "titles" >
438
+ TYPE
439
+ </ Text >
440
+ < Text color = "subtle" variant = "titles" >
441
+ NAME
442
+ </ Text >
443
+ < Text color = "subtle" variant = "titles" >
444
+ VALUE
445
+ </ Text >
446
+
447
+ { dnsRecords . map ( ( record , index ) => (
448
+ < Fragment key = { index } >
449
+ < InputEllipsis readOnly value = { record . type } />
450
+ < InputEllipsis
451
+ readOnly
452
+ value = { record . host }
453
+ suffix = {
454
+ < CopyToClipboard text = { record . host } >
455
+ < NestedInputButton type = "button" >
456
+ < CopyIcon />
457
+ </ NestedInputButton >
458
+ </ CopyToClipboard >
459
+ }
460
+ />
461
+ < InputEllipsis
462
+ readOnly
463
+ value = { record . value }
464
+ suffix = {
465
+ < CopyToClipboard text = { record . value } >
466
+ < NestedInputButton type = "button" >
467
+ < CopyIcon />
468
+ </ NestedInputButton >
469
+ </ CopyToClipboard >
470
+ }
471
+ />
472
+ </ Fragment >
473
+ ) ) }
474
+ </ Grid >
475
+
476
+ < Grid
477
+ gap = { 2 }
478
+ align = { "center" }
479
+ css = { {
480
+ gridTemplateColumns : `1fr auto 1fr` ,
481
+ } }
482
+ >
483
+ < Separator css = { { alignSelf : "unset" } } />
484
+ < Text color = "main" > OR</ Text >
485
+ < Separator css = { { alignSelf : "unset" } } />
486
+ </ Grid >
487
+
488
+ < Entri
489
+ dnsRecords = { dnsRecords }
490
+ domain = { projectDomain . domain }
491
+ onClose = { ( ) => {
492
+ // Sometimes Entri modal dialog hangs even if it's successful,
493
+ // until they fix that, we'll just refresh the status here on every onClose event
509
494
if ( status === "UNVERIFIED" ) {
510
495
startTransition ( async ( ) => {
511
496
await handleVerify ( ) ;
0 commit comments