| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import { zodResolver } from '@hookform/resolvers/zod'
- import dayjs from 'dayjs'
- import { SubmitHandler, useForm, useWatch } from 'react-hook-form'
- import {
- Button,
- Form,
- FormControl,
- FormField,
- Input,
- Modal,
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
- } from 'ui'
- import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
- import * as z from 'zod'
- import { useCopyUrl } from './useCopyUrl'
- import { DATETIME_FORMAT } from '@/lib/constants'
- import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'
- const unitMap = {
- days: 3600 * 24,
- weeks: 3600 * 24 * 7,
- months: 3600 * 24 * 30,
- years: 3600 * 24 * 365,
- } as const
- const formSchema = z.object({
- expiresIn: z.preprocess(
- (val) => (val ? val : undefined),
- z.coerce
- .number({ required_error: 'Required', invalid_type_error: 'Required' })
- .positive('Expiry duration must be greater than 0')
- ),
- units: z.enum(['days', 'weeks', 'months', 'years']),
- })
- type FormSchema = z.infer<typeof formSchema>
- const formId = 'storage-custom-expiry-form'
- export const CustomExpiryModal = () => {
- const { onCopyUrl } = useCopyUrl()
- const snap = useStorageExplorerStateSnapshot()
- const { selectedFileCustomExpiry, setSelectedFileCustomExpiry } = snap
- const visible = selectedFileCustomExpiry !== undefined
- const onClose = () => setSelectedFileCustomExpiry(undefined)
- const form = useForm<FormSchema>({
- resolver: zodResolver(formSchema as any),
- defaultValues: { expiresIn: 0, units: 'days' },
- })
- const handleClose = () => {
- onClose()
- form.reset()
- }
- const { isDirty, isSubmitting, isValid } = form.formState
- const handleSubmit: SubmitHandler<FormSchema> = async (values) => {
- await onCopyUrl(selectedFileCustomExpiry!.path!, values.expiresIn * unitMap[values.units])
- handleClose()
- }
- const [expiresIn, units] = useWatch({
- name: ['expiresIn', 'units'],
- control: form.control,
- })
- return (
- <Modal
- hideFooter
- size="small"
- header="Custom expiry for signed URL"
- visible={visible}
- alignFooter="right"
- confirmText="Get URL"
- onCancel={handleClose}
- >
- <Form {...form}>
- <Modal.Content>
- <p className="text-sm text-foreground-light mb-4">
- Enter the duration for which the URL will be valid for:
- </p>
- <form
- id={formId}
- onSubmit={form.handleSubmit(handleSubmit)}
- noValidate
- className="flex items-start space-x-2"
- >
- <div className="grow">
- <FormField
- control={form.control}
- name="expiresIn"
- render={({ field }) => (
- <FormItemLayout layout="vertical" label="Duration">
- <FormControl>
- <Input
- {...field}
- type="number"
- onChange={(e) => {
- field.onChange(
- isNaN(e.target.valueAsNumber) ? '' : e.target.valueAsNumber
- )
- }}
- />
- </FormControl>
- </FormItemLayout>
- )}
- />
- </div>
- <div>
- <FormField
- control={form.control}
- name="units"
- render={({ field }) => (
- <FormItemLayout layout="vertical" label="Units">
- <FormControl>
- <Select value={field.value} onValueChange={field.onChange}>
- <SelectTrigger>
- <SelectValue aria-label="Units" placeholder="Select an option" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="days">days</SelectItem>
- <SelectItem value="weeks">weeks</SelectItem>
- <SelectItem value="months">months</SelectItem>
- <SelectItem value="years">years</SelectItem>
- </SelectContent>
- </Select>
- </FormControl>
- </FormItemLayout>
- )}
- />
- </div>
- </form>
- {isDirty && isValid && (
- <p className="text-sm text-foreground-light mt-2">
- URL will expire on {dayjs().add(expiresIn, units).format(DATETIME_FORMAT)}
- </p>
- )}
- </Modal.Content>
- <Modal.Separator />
- <Modal.Content className="flex items-center justify-end space-x-2">
- <Button type="default" onClick={handleClose}>
- Cancel
- </Button>
- <Button
- form={formId}
- disabled={!isDirty || isSubmitting}
- loading={isSubmitting}
- htmlType="submit"
- type="primary"
- >
- Get signed URL
- </Button>
- </Modal.Content>
- </Form>
- </Modal>
- )
- }
|