Download apps/frontend/src/components/new-launch/delay.component.tsx from Leon4gr45/postio: direct link, hf CLI and curl.
- Browser
- Download file 5.15 kB
-
https://huggingface.co/spaces/Leon4gr45/postio/resolve/main/apps/frontend/src/components/new-launch/delay.component.tsx
- Command line
-
hf download hf://spaces/Leon4gr45/postio/apps/frontend/src/components/new-launch/delay.component.tsx
-
curl -L -o delay.component.tsx https://huggingface.co/spaces/Leon4gr45/postio/resolve/main/apps/frontend/src/components/new-launch/delay.component.tsx
5.15 kB
| 'use client'; | |
| import React, { FC, useCallback, useEffect, useState } from 'react'; | |
| import { DelayIcon, DropdownArrowIcon } from '@gitroom/frontend/components/ui/icons'; | |
| import clsx from 'clsx'; | |
| import { useLaunchStore } from '@gitroom/frontend/components/new-launch/store'; | |
| import { useShallow } from 'zustand/react/shallow'; | |
| import { useT } from '@gitroom/react/translation/get.transation.service.client'; | |
| import { useClickOutside } from '@mantine/hooks'; | |
| const delayOptions = [ | |
| { value: 1, label: '1m' }, | |
| { value: 2, label: '2m' }, | |
| { value: 5, label: '5m' }, | |
| { value: 10, label: '10m' }, | |
| { value: 15, label: '15m' }, | |
| { value: 30, label: '30m' }, | |
| { value: 60, label: '1h' }, | |
| { value: 120, label: '2h' }, | |
| ]; | |
| export const DelayComponent: FC<{ | |
| currentIndex: number; | |
| currentDelay: number; | |
| }> = ({ currentIndex, currentDelay }) => { | |
| const t = useT(); | |
| const [isOpen, setIsOpen] = useState(false); | |
| const [customValue, setCustomValue] = useState(''); | |
| const isCustomDelay = currentDelay > 0 && !delayOptions.some((opt) => opt.value === currentDelay); | |
| useEffect(() => { | |
| if (isOpen && isCustomDelay) { | |
| setCustomValue(String(currentDelay)); | |
| } else if (isOpen && !isCustomDelay) { | |
| setCustomValue(''); | |
| } | |
| }, [isOpen, isCustomDelay, currentDelay]); | |
| const { current, setInternalDelay, setGlobalDelay } = useLaunchStore( | |
| useShallow((state) => ({ | |
| current: state.current, | |
| setGlobalDelay: state.setGlobalDelay, | |
| setInternalDelay: state.setInternalDelay, | |
| })) | |
| ); | |
| const ref = useClickOutside(() => { | |
| if (!isOpen) { | |
| return; | |
| } | |
| setIsOpen(false); | |
| }); | |
| const setDelay = useCallback( | |
| (index: number) => (minutes: number) => { | |
| if (current !== 'global') { | |
| return setInternalDelay(current, index, minutes); | |
| } | |
| return setGlobalDelay(index, minutes); | |
| }, | |
| [currentIndex, current] | |
| ); | |
| const handleSelectDelay = useCallback( | |
| (minutes: number) => { | |
| setDelay(currentIndex)(minutes); | |
| setIsOpen(false); | |
| }, | |
| [currentIndex, setDelay] | |
| ); | |
| const getCurrentDelayLabel = () => { | |
| if (!currentDelay) return null; | |
| const option = delayOptions.find((opt) => opt.value === currentDelay); | |
| return option?.label || `${currentDelay} min`; | |
| }; | |
| return ( | |
| <div ref={ref} className="relative"> | |
| <div | |
| onClick={() => setIsOpen(!isOpen)} | |
| data-tooltip-id="tooltip" | |
| data-tooltip-content={ | |
| !currentDelay | |
| ? t('delay_comment', 'Delay comment') | |
| : `${t('delay_comment_by', 'Comment delayed by')} ${getCurrentDelayLabel()}` | |
| } | |
| className={clsx( | |
| 'cursor-pointer flex items-center gap-[4px]', | |
| currentDelay > 0 && 'bg-[#D82D7E] text-white rounded-full' | |
| )} | |
| > | |
| <DelayIcon /> | |
| </div> | |
| {isOpen && ( | |
| <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]"> | |
| <div className="grid grid-cols-4 gap-[4px]"> | |
| {delayOptions.map((option) => ( | |
| <div | |
| onClick={() => handleSelectDelay(option.value)} | |
| key={option.value} | |
| className={clsx( | |
| 'h-[32px] flex items-center justify-center rounded-[4px] cursor-pointer hover:bg-newBgColor text-[13px]', | |
| currentDelay === option.value && 'bg-[#612BD3] text-white hover:bg-[#612BD3]' | |
| )} | |
| > | |
| {option.label} | |
| </div> | |
| ))} | |
| </div> | |
| <div className="border-t border-newTextColor/10 mt-[8px] pt-[8px]"> | |
| <div className="flex gap-[4px]"> | |
| <input | |
| type="number" | |
| min="1" | |
| value={customValue} | |
| onChange={(e) => setCustomValue(e.target.value)} | |
| onClick={(e) => e.stopPropagation()} | |
| placeholder="Custom min" | |
| className={clsx( | |
| 'flex-1 w-full h-[32px] px-[8px] rounded-[4px] bg-newBgColor border text-[13px] outline-none focus:border-[#612BD3]', | |
| isCustomDelay ? 'border-[#612BD3]' : 'border-newTextColor/10' | |
| )} | |
| /> | |
| <button | |
| onClick={(e) => { | |
| e.stopPropagation(); | |
| const value = parseInt(customValue, 10); | |
| if (value > 0) { | |
| handleSelectDelay(value); | |
| setCustomValue(''); | |
| } | |
| }} | |
| className="h-[32px] px-[10px] rounded-[4px] bg-[#612BD3] text-white text-[12px] font-[600] hover:bg-[#612BD3]/80" | |
| > | |
| Set | |
| </button> | |
| </div> | |
| </div> | |
| {currentDelay > 0 && ( | |
| <button | |
| onClick={() => handleSelectDelay(0)} | |
| className="mt-[8px] h-[32px] w-full rounded-[4px] text-[13px] text-red-400 hover:bg-red-400/10" | |
| > | |
| Remove delay | |
| </button> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| ); | |
| }; | |