BasicInfo.tsx140 lines · main
1import dayjs from 'dayjs'
2import { useEffect, useState } from 'react'
3import { Control, ControllerRenderProps } from 'react-hook-form'
4import {
5 FormControl,
6 FormField,
7 Input,
8 Select,
9 SelectContent,
10 SelectItem,
11 SelectTrigger,
12 SelectValue,
13 WarningIcon,
14} from 'ui'
15import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
16
17import {
18 CUSTOM_EXPIRY_VALUE,
19 EXPIRES_AT_OPTIONS,
20 NON_EXPIRING_TOKEN_VALUE,
21} from '../../AccessToken.constants'
22import { type TokenFormValues } from '../../AccessToken.schemas'
23import { DatePicker } from '@/components/ui/DatePicker'
24
25interface BasicInfoProps {
26 control: Control<TokenFormValues>
27 expirationDate: string
28 onCustomDateChange?: (date: { date: string } | undefined) => void
29 onCustomExpiryChange?: (isCustom: boolean) => void
30}
31
32export const BasicInfo = ({
33 control,
34 expirationDate,
35 onCustomDateChange,
36 onCustomExpiryChange,
37}: BasicInfoProps) => {
38 const [customDate, setCustomDate] = useState<Date>()
39 const [isCustomSelected, setIsCustomSelected] = useState(false)
40
41 useEffect(() => {
42 const isCustom = expirationDate === CUSTOM_EXPIRY_VALUE
43 setIsCustomSelected(isCustom)
44 onCustomExpiryChange?.(isCustom)
45 }, [expirationDate, onCustomExpiryChange])
46
47 const handleCustomDateChange = (date: Date | undefined) => {
48 setCustomDate(date)
49 if (date) {
50 onCustomDateChange?.({ date: date.toISOString() })
51 } else {
52 onCustomDateChange?.(undefined)
53 }
54 }
55
56 const handleExpiryChange = (
57 value: string,
58 field: ControllerRenderProps<TokenFormValues, 'expiresAt'>
59 ) => {
60 const isCustom = value === CUSTOM_EXPIRY_VALUE
61 setIsCustomSelected(isCustom)
62 onCustomExpiryChange?.(isCustom)
63 field.onChange(value)
64 }
65
66 return (
67 <div className="space-y-4 px-5 sm:px-6 py-6">
68 <FormField
69 key="tokenName"
70 name="tokenName"
71 control={control}
72 render={({ field }) => (
73 <FormItemLayout name="tokenName" label="Name">
74 <FormControl>
75 <Input id="tokenName" {...field} placeholder="Provide a name for your token" />
76 </FormControl>
77 </FormItemLayout>
78 )}
79 />
80
81 <FormField
82 key="expiresAt"
83 name="expiresAt"
84 control={control}
85 render={({ field }) => (
86 <FormItemLayout name="expiresAt" label="Expires in">
87 <div className="flex gap-2">
88 <FormControl className="grow">
89 <Select
90 value={field.value}
91 onValueChange={(value) => handleExpiryChange(value, field)}
92 >
93 <SelectTrigger>
94 <SelectValue placeholder="Expires at" />
95 </SelectTrigger>
96 <SelectContent>
97 {Object.values(EXPIRES_AT_OPTIONS).map(
98 (option: { value: string; label: string }) => (
99 <SelectItem key={option.value} value={option.value}>
100 {option.label}
101 </SelectItem>
102 )
103 )}
104 </SelectContent>
105 </Select>
106 </FormControl>
107 {isCustomSelected && (
108 <DatePicker
109 selectsRange={false}
110 triggerButtonSize="small"
111 contentSide="top"
112 minDate={new Date()}
113 maxDate={dayjs().add(1, 'year').toDate()}
114 onChange={(date) => {
115 const selectedDate = date.to || date.from
116 if (selectedDate) {
117 handleCustomDateChange(new Date(selectedDate))
118 } else {
119 handleCustomDateChange(undefined)
120 }
121 }}
122 >
123 {customDate ? `${dayjs(customDate).format('DD MMM, HH:mm')}` : 'Select date'}
124 </DatePicker>
125 )}
126 </div>
127 {field.value === NON_EXPIRING_TOKEN_VALUE && (
128 <div className="w-full flex gap-x-2 items-center mt-3 mx-0.5">
129 <WarningIcon />
130 <span className="text-xs text-left text-foreground-lighter">
131 Make sure to keep your non-expiring token safe and secure.
132 </span>
133 </div>
134 )}
135 </FormItemLayout>
136 )}
137 />
138 </div>
139 )
140}