tasks-import-dialog.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { z } from 'zod'
  2. import { useForm } from 'react-hook-form'
  3. import { zodResolver } from '@hookform/resolvers/zod'
  4. import { toast } from '@/hooks/use-toast'
  5. import { Button } from '@/components/ui/button'
  6. import {
  7. Dialog,
  8. DialogClose,
  9. DialogContent,
  10. DialogDescription,
  11. DialogFooter,
  12. DialogHeader,
  13. DialogTitle,
  14. } from '@/components/ui/dialog'
  15. import {
  16. Form,
  17. FormControl,
  18. FormField,
  19. FormItem,
  20. FormLabel,
  21. FormMessage,
  22. } from '@/components/ui/form'
  23. import { Input } from '@/components/ui/input'
  24. const formSchema = z.object({
  25. file: z
  26. .instanceof(FileList)
  27. .refine((files) => files.length > 0, {
  28. message: 'Please upload a file',
  29. })
  30. .refine(
  31. (files) => ['text/csv'].includes(files?.[0]?.type),
  32. 'Please upload csv format.'
  33. ),
  34. })
  35. interface Props {
  36. open: boolean
  37. onOpenChange: (open: boolean) => void
  38. }
  39. export function TasksImportDialog({ open, onOpenChange }: Props) {
  40. const form = useForm<z.infer<typeof formSchema>>({
  41. resolver: zodResolver(formSchema),
  42. defaultValues: { file: undefined },
  43. })
  44. const fileRef = form.register('file')
  45. const onSubmit = () => {
  46. const file = form.getValues('file')
  47. if (file && file[0]) {
  48. const fileDetails = {
  49. name: file[0].name,
  50. size: file[0].size,
  51. type: file[0].type,
  52. }
  53. toast({
  54. title: 'You have imported the following file:',
  55. description: (
  56. <pre className='mt-2 w-[340px] rounded-md bg-slate-950 p-4'>
  57. <code className='text-white'>
  58. {JSON.stringify(fileDetails, null, 2)}
  59. </code>
  60. </pre>
  61. ),
  62. })
  63. }
  64. onOpenChange(false)
  65. }
  66. return (
  67. <Dialog
  68. open={open}
  69. onOpenChange={(val) => {
  70. onOpenChange(val)
  71. form.reset()
  72. }}
  73. >
  74. <DialogContent className='sm:max-w-sm gap-2'>
  75. <DialogHeader className='text-left'>
  76. <DialogTitle>Import Tasks</DialogTitle>
  77. <DialogDescription>
  78. Import tasks quickly from a CSV file.
  79. </DialogDescription>
  80. </DialogHeader>
  81. <Form {...form}>
  82. <form id='task-import-form' onSubmit={form.handleSubmit(onSubmit)}>
  83. <FormField
  84. control={form.control}
  85. name='file'
  86. render={() => (
  87. <FormItem className='space-y-1 mb-2'>
  88. <FormLabel>File</FormLabel>
  89. <FormControl>
  90. <Input type='file' {...fileRef} className='h-8' />
  91. </FormControl>
  92. <FormMessage />
  93. </FormItem>
  94. )}
  95. />
  96. </form>
  97. </Form>
  98. <DialogFooter className='gap-2 sm:gap-0'>
  99. <DialogClose asChild>
  100. <Button variant='outline'>Close</Button>
  101. </DialogClose>
  102. <Button type='submit' form='task-import-form'>
  103. Import
  104. </Button>
  105. </DialogFooter>
  106. </DialogContent>
  107. </Dialog>
  108. )
  109. }