11'use client' ;
22
3- import React , { FC , useCallback } from 'react' ;
4- import { DelayIcon } from '@gitroom/frontend/components/ui/icons' ;
3+ import React , { FC , useCallback , useEffect , useState } from 'react' ;
4+ import { DelayIcon , DropdownArrowIcon } from '@gitroom/frontend/components/ui/icons' ;
55import clsx from 'clsx' ;
66import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store' ;
77import { useShallow } from 'zustand/react/shallow' ;
88import { useT } from '@gitroom/react/translation/get.transation.service.client' ;
9+ import { useClickOutside } from '@mantine/hooks' ;
10+
11+ const delayOptions = [
12+ { value : 1 , label : '1m' } ,
13+ { value : 2 , label : '2m' } ,
14+ { value : 5 , label : '5m' } ,
15+ { value : 10 , label : '10m' } ,
16+ { value : 15 , label : '15m' } ,
17+ { value : 30 , label : '30m' } ,
18+ { value : 60 , label : '1h' } ,
19+ { value : 120 , label : '2h' } ,
20+ ] ;
921
1022export const DelayComponent : FC < {
1123 currentIndex : number ;
1224 currentDelay : number ;
1325} > = ( { currentIndex, currentDelay } ) => {
1426 const t = useT ( ) ;
27+ const [ isOpen , setIsOpen ] = useState ( false ) ;
28+ const [ customValue , setCustomValue ] = useState ( '' ) ;
29+
30+ const isCustomDelay = currentDelay > 0 && ! delayOptions . some ( ( opt ) => opt . value === currentDelay ) ;
31+
32+ useEffect ( ( ) => {
33+ if ( isOpen && isCustomDelay ) {
34+ setCustomValue ( String ( currentDelay ) ) ;
35+ } else if ( isOpen && ! isCustomDelay ) {
36+ setCustomValue ( '' ) ;
37+ }
38+ } , [ isOpen , isCustomDelay , currentDelay ] ) ;
39+
1540 const { current, setInternalDelay, setGlobalDelay } = useLaunchStore (
1641 useShallow ( ( state ) => ( {
1742 current : state . current ,
@@ -20,6 +45,13 @@ export const DelayComponent: FC<{
2045 } ) )
2146 ) ;
2247
48+ const ref = useClickOutside ( ( ) => {
49+ if ( ! isOpen ) {
50+ return ;
51+ }
52+ setIsOpen ( false ) ;
53+ } ) ;
54+
2355 const setDelay = useCallback (
2456 ( index : number ) => ( minutes : number ) => {
2557 if ( current !== 'global' ) {
@@ -31,20 +63,92 @@ export const DelayComponent: FC<{
3163 [ currentIndex , current ]
3264 ) ;
3365
66+ const handleSelectDelay = useCallback (
67+ ( minutes : number ) => {
68+ setDelay ( currentIndex ) ( minutes ) ;
69+ setIsOpen ( false ) ;
70+ } ,
71+ [ currentIndex , setDelay ]
72+ ) ;
73+
74+ const getCurrentDelayLabel = ( ) => {
75+ if ( ! currentDelay ) return null ;
76+ const option = delayOptions . find ( ( opt ) => opt . value === currentDelay ) ;
77+ return option ?. label || `${ currentDelay } min` ;
78+ } ;
79+
3480 return (
35- < DelayIcon
36- // move it into the modal
37- onClick = { ( ) => setDelay ( currentIndex ) ( 100 ) }
38- data-tooltip-id = "tooltip"
39- data-tooltip-content = {
40- ! currentDelay
41- ? t ( 'delay_comment' , 'Delay comment' )
42- : `Comment delayed by ${ currentDelay } minutes`
43- }
44- className = { clsx (
45- 'cursor-pointer' ,
46- currentDelay > 0 && 'bg-[#D82D7E] text-white rounded-full'
81+ < div ref = { ref } className = "relative" >
82+ < div
83+ onClick = { ( ) => setIsOpen ( ! isOpen ) }
84+ data-tooltip-id = "tooltip"
85+ data-tooltip-content = {
86+ ! currentDelay
87+ ? t ( 'delay_comment' , 'Delay comment' )
88+ : `${ t ( 'delay_comment_by' , 'Comment delayed by' ) } ${ getCurrentDelayLabel ( ) } `
89+ }
90+ className = { clsx (
91+ 'cursor-pointer flex items-center gap-[4px]' ,
92+ currentDelay > 0 && 'bg-[#D82D7E] text-white rounded-full'
93+ ) }
94+ >
95+ < DelayIcon />
96+ </ div >
97+ { isOpen && (
98+ < div className = "z-[300] absolute end-0 top-[100%] w-[200px] bg-newBgColorInner p-[8px] menu-shadow translate-y-[10px] flex flex-col rounded-[8px]" >
99+ < div className = "grid grid-cols-4 gap-[4px]" >
100+ { delayOptions . map ( ( option ) => (
101+ < div
102+ onClick = { ( ) => handleSelectDelay ( option . value ) }
103+ key = { option . value }
104+ className = { clsx (
105+ 'h-[32px] flex items-center justify-center rounded-[4px] cursor-pointer hover:bg-newBgColor text-[13px]' ,
106+ currentDelay === option . value && 'bg-[#612BD3] text-white hover:bg-[#612BD3]'
107+ ) }
108+ >
109+ { option . label }
110+ </ div >
111+ ) ) }
112+ </ div >
113+ < div className = "border-t border-newTextColor/10 mt-[8px] pt-[8px]" >
114+ < div className = "flex gap-[4px]" >
115+ < input
116+ type = "number"
117+ min = "1"
118+ value = { customValue }
119+ onChange = { ( e ) => setCustomValue ( e . target . value ) }
120+ onClick = { ( e ) => e . stopPropagation ( ) }
121+ placeholder = "Custom min"
122+ className = { clsx (
123+ 'flex-1 w-full h-[32px] px-[8px] rounded-[4px] bg-newBgColor border text-[13px] outline-none focus:border-[#612BD3]' ,
124+ isCustomDelay ? 'border-[#612BD3]' : 'border-newTextColor/10'
125+ ) }
126+ />
127+ < button
128+ onClick = { ( e ) => {
129+ e . stopPropagation ( ) ;
130+ const value = parseInt ( customValue , 10 ) ;
131+ if ( value > 0 ) {
132+ handleSelectDelay ( value ) ;
133+ setCustomValue ( '' ) ;
134+ }
135+ } }
136+ className = "h-[32px] px-[10px] rounded-[4px] bg-[#612BD3] text-white text-[12px] font-[600] hover:bg-[#612BD3]/80"
137+ >
138+ Set
139+ </ button >
140+ </ div >
141+ </ div >
142+ { currentDelay > 0 && (
143+ < button
144+ onClick = { ( ) => handleSelectDelay ( 0 ) }
145+ className = "mt-[8px] h-[32px] w-full rounded-[4px] text-[13px] text-red-400 hover:bg-red-400/10"
146+ >
147+ Remove delay
148+ </ button >
149+ ) }
150+ </ div >
47151 ) }
48- / >
152+ </ div >
49153 ) ;
50154} ;
0 commit comments