@@ -86,14 +86,18 @@ const StyledSelect = styled(Select)`
86
86
}
87
87
` ;
88
88
89
- const useCopyToClipboard = ( ) => {
89
+ const useCopyToClipboard = ( timeout ?: number ) => {
90
90
const [ copied , setCopied ] = React . useState ( false ) ;
91
91
92
92
React . useEffect ( ( ) => {
93
93
if ( ! copied ) {
94
94
return ;
95
95
}
96
96
97
+ if ( ! timeout ) {
98
+ return setCopied ( false ) ;
99
+ }
100
+
97
101
const timeOut = setTimeout ( ( ) => {
98
102
setCopied ( false ) ;
99
103
} , 1000 * 2 ) ;
@@ -106,9 +110,7 @@ const useCopyToClipboard = () => {
106
110
return {
107
111
copied,
108
112
copy : ( text : string ) => {
109
- if ( navigator ?. clipboard ?. writeText ) {
110
- setCopied ( true ) ;
111
-
113
+ if ( navigator ?. clipboard . writeText ) {
112
114
navigator . clipboard . writeText ( text ) ;
113
115
} else {
114
116
const element = document . createElement ( 'textarea' ) ;
@@ -128,9 +130,9 @@ const useCopyToClipboard = () => {
128
130
document . execCommand ( 'copy' ) ;
129
131
130
132
document . body . removeChild ( element ) ;
131
-
132
- setCopied ( true ) ;
133
133
}
134
+
135
+ setCopied ( true ) ;
134
136
} ,
135
137
} ;
136
138
} ;
@@ -148,7 +150,7 @@ const TemplatePreview = (
148
150
)
149
151
>
150
152
) => {
151
- const clipboard = useCopyToClipboard ( ) ;
153
+ const clipboard = useCopyToClipboard ( 2000 ) ;
152
154
153
155
return (
154
156
< Box
@@ -385,16 +387,16 @@ const QuerySection = (
385
387
} , [ updateDependency ] ) ;
386
388
} ;
387
389
388
- const useNotification = ( ) => {
390
+ const useTemplateNotification = ( ) => {
389
391
const [ type , setType ] = React . useState (
390
- 'none' as 'loading' | 'succeed' | 'none ' | 'failed'
392
+ undefined as 'loading' | 'succeed' | 'failed ' | undefined
391
393
) ;
392
394
393
395
React . useEffect ( ( ) => {
394
396
toast . dismiss ( ) ;
395
397
396
398
switch ( type ) {
397
- case 'none' : {
399
+ case undefined : {
398
400
break ;
399
401
}
400
402
case 'loading' : {
@@ -425,6 +427,33 @@ const useNotification = () => {
425
427
} ;
426
428
} ;
427
429
430
+ const useCopyNotification = ( ) => {
431
+ const [ type , setType ] = React . useState ( undefined as 'succeed' | undefined ) ;
432
+
433
+ React . useEffect ( ( ) => {
434
+ toast . dismiss ( ) ;
435
+
436
+ switch ( type ) {
437
+ case undefined : {
438
+ break ;
439
+ }
440
+ case 'succeed' : {
441
+ toast . success ( '🎉 Copied All' ) ;
442
+ break ;
443
+ }
444
+ }
445
+ } , [ type ] ) ;
446
+
447
+ return {
448
+ succeed : ( ) => {
449
+ setType ( 'succeed' ) ;
450
+ } ,
451
+ unset : ( ) => {
452
+ setType ( undefined ) ;
453
+ } ,
454
+ } ;
455
+ } ;
456
+
428
457
const Templates = ( ) => {
429
458
const delimiter = ',' ;
430
459
@@ -438,7 +467,9 @@ const Templates = () => {
438
467
439
468
const clipboard = useCopyToClipboard ( ) ;
440
469
441
- const notification = useNotification ( ) ;
470
+ const templateNotification = useTemplateNotification ( ) ;
471
+
472
+ const copyNotification = useCopyNotification ( ) ;
442
473
443
474
const [ templates , setTemplate ] = React . useState ( [ ] as Templates ) ;
444
475
@@ -447,15 +478,15 @@ const Templates = () => {
447
478
} ) ;
448
479
449
480
React . useEffect ( ( ) => {
450
- notification . loading ( ) ;
481
+ templateNotification . loading ( ) ;
451
482
452
483
trpcClient . template . findAllTemplates
453
484
. query ( )
454
485
. then ( ( result ) => {
455
486
if ( ! result . hadSucceed ) {
456
- notification . failed ( ) ;
487
+ templateNotification . failed ( ) ;
457
488
} else {
458
- notification . succeed ( ) ;
489
+ templateNotification . succeed ( ) ;
459
490
}
460
491
461
492
return result ;
@@ -470,6 +501,12 @@ const Templates = () => {
470
501
. then ( setTemplate ) ;
471
502
} , [ ] ) ;
472
503
504
+ React . useEffect ( ( ) => {
505
+ if ( clipboard . copied ) {
506
+ copyNotification . succeed ( ) ;
507
+ }
508
+ } , [ clipboard . copied ] ) ;
509
+
473
510
return (
474
511
< Layout title = "Templates" >
475
512
< Seo
@@ -492,13 +529,18 @@ const Templates = () => {
492
529
minHeight = "30vh"
493
530
boxSizing = "border-box"
494
531
>
495
- < Box display = "flex" justifyContent = "space-between" >
532
+ < Box
533
+ display = "flex"
534
+ justifyContent = "space-between"
535
+ alignItems = "center"
536
+ gap = { 8 }
537
+ >
496
538
< QuerySection
497
539
templates = { {
498
540
all : templates ,
499
541
selected,
500
542
updateSelected : ( selected ) => {
501
- const params =
543
+ const query =
502
544
formQueryParamStringFromRecord ( {
503
545
names : selected
504
546
. map ( ( { name } ) => {
@@ -510,7 +552,7 @@ const Templates = () => {
510
552
router . push (
511
553
{
512
554
pathname : '/templates' ,
513
- query : params ,
555
+ query,
514
556
} ,
515
557
undefined ,
516
558
{
@@ -525,12 +567,11 @@ const Templates = () => {
525
567
colorScheme = "messenger"
526
568
isDisabled = { isFalsy ( selected . length ) }
527
569
onClick = { ( ) => {
570
+ copyNotification . unset ( ) ;
528
571
clipboard . copy ( combineTemplates ( selected ) ) ;
529
572
} }
530
573
>
531
- { ! clipboard . copied
532
- ? 'Copy All'
533
- : '🎉 Copied All' }
574
+ Copy All
534
575
</ Button >
535
576
< Divider orientation = "vertical" />
536
577
< Button
0 commit comments