BasicInfo.tsx 4.4 KB

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