87 | >(({ className, ...props }, ref) => (
88 | [role=checkbox]]:translate-y-[2px]",
92 | className
93 | )}
94 | {...props}
95 | />
96 | ))
97 | TableCell.displayName = "TableCell"
98 |
99 | const TableCaption = React.forwardRef<
100 | HTMLTableCaptionElement,
101 | React.HTMLAttributes
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | TableCaption.displayName = "TableCaption"
110 |
111 | export {
112 | Table,
113 | TableHeader,
114 | TableBody,
115 | TableFooter,
116 | TableHead,
117 | TableRow,
118 | TableCell,
119 | TableCaption,
120 | }
121 |
--------------------------------------------------------------------------------
/components/auth/LoginForm.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useTransition } from "react";
4 | import { AuthCard } from "./AuthCard";
5 | import { useForm } from "react-hook-form";
6 | import { z } from "zod";
7 | import { loginSchema } from "../schema/authType";
8 | import { zodResolver } from '@hookform/resolvers/zod';
9 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
10 | import { Input } from "../ui/input";
11 | import { Button } from "../ui/button";
12 | import { LoginApi } from "@/action/authHandler";
13 | import toast from "react-hot-toast";
14 |
15 | export const LoginForm = () => {
16 | const [isPanding, startTransistion] = useTransition();
17 |
18 | const form = useForm>({
19 | resolver: zodResolver(loginSchema),
20 | defaultValues: {
21 | email: '',
22 | password: ''
23 | }
24 | })
25 |
26 | const onSubmit = (values: z.infer) => {
27 | startTransistion(() => {
28 | LoginApi(values)
29 | .then((response) => {
30 | if(response?.error) {
31 | toast.error(response.error);
32 | }
33 | })
34 | .catch((error) => {
35 | console.log(error);
36 | })
37 | })
38 | }
39 |
40 | return(
41 |
46 |
91 |
92 |
93 |
94 | )
95 | }
--------------------------------------------------------------------------------
/components/profile/UserProfile.tsx:
--------------------------------------------------------------------------------
1 | import { useForm } from "react-hook-form";
2 | import { UserDataProps } from "./Profile";
3 | import { z } from "zod";
4 | import { nameUpdateSchema } from "../schema/profileType";
5 | import { zodResolver } from "@hookform/resolvers/zod";
6 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
7 | import { Input } from "../ui/input";
8 | import { Button } from "../ui/button";
9 | import { useTransition } from "react";
10 | import { updateUserName } from "@/action/profileHandler";
11 | import toast from "react-hot-toast";
12 |
13 |
14 | export const Userprofile = ({ userData }: { userData: UserDataProps }) => {
15 | const [isPanding, startTransition] = useTransition();
16 |
17 | const form = useForm>({
18 | resolver: zodResolver(nameUpdateSchema),
19 | defaultValues: {
20 | email: userData.email,
21 | name: userData.name,
22 | }
23 | })
24 |
25 | const onSubmit = (values: z.infer) => {
26 | startTransition(() => {
27 | updateUserName({ name: values.name })
28 | .then((response) => {
29 | if (response.status === 400){
30 | toast.error(response.message)
31 | }
32 |
33 | if (response.status == 'success') {
34 | toast.success(`User name update Successful!`)
35 | }
36 | })
37 | .catch((error) => {
38 | console.log(error);
39 | })
40 | })
41 | }
42 |
43 | return (
44 |
45 |
46 | Update User Name
47 |
48 |
91 |
92 |
93 | )
94 | }
--------------------------------------------------------------------------------
/components/ui/data-table.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import {
4 | ColumnDef,
5 | flexRender,
6 | getCoreRowModel,
7 | useReactTable,
8 | getPaginationRowModel,
9 | } from "@tanstack/react-table";
10 |
11 | import {
12 | Table,
13 | TableBody,
14 | TableCell,
15 | TableHead,
16 | TableHeader,
17 | TableRow,
18 | } from "@/components/ui/table";
19 | import { Button } from "@/components/ui/button";
20 | import { useEffect, useState } from "react";
21 | import { useRouter, useSearchParams } from "next/navigation";
22 |
23 | interface DataTableProps {
24 | columns: ColumnDef[];
25 | data: TData[];
26 | totalCount: number; // Total count for pagination
27 | }
28 |
29 | export function DataTable({
30 | columns,
31 | data,
32 | totalCount,
33 | }: DataTableProps) {
34 |
35 | const router = useRouter();
36 | const searchParams = useSearchParams();
37 |
38 | const initialPage = Number(searchParams.get("page")) || 1;
39 | const [page, setPage] = useState(initialPage);
40 | const limit = 10; // Adjust based on your needs
41 |
42 | const table = useReactTable({
43 | data,
44 | columns,
45 | getCoreRowModel: getCoreRowModel(),
46 | getPaginationRowModel: getPaginationRowModel(),
47 | });
48 |
49 | useEffect(() => {
50 |
51 | const params = new URLSearchParams(window.location.search);
52 | params.set("page", String(page))
53 | params.set("limit", String(limit))
54 |
55 | router.push(`${window.location.pathname}?${params.toString()}`)
56 | },[page, limit, router])
57 |
58 | return (
59 |
60 |
61 |
62 |
63 | {table.getHeaderGroups().map((headerGroup) => (
64 |
65 | {headerGroup.headers.map((header) => {
66 | return (
67 |
68 | {header.isPlaceholder
69 | ? null
70 | : flexRender(
71 | header.column.columnDef.header,
72 | header.getContext()
73 | )}
74 |
75 | );
76 | })}
77 |
78 | ))}
79 |
80 |
81 | {table.getRowModel().rows?.length ? (
82 | table.getRowModel().rows.map((row) => (
83 |
87 | {row.getVisibleCells().map((cell) => (
88 |
89 | {flexRender(
90 | cell.column.columnDef.cell,
91 | cell.getContext()
92 | )}
93 |
94 | ))}
95 |
96 | ))
97 | ) : (
98 |
99 |
103 | No results.
104 |
105 |
106 | )}
107 |
108 |
109 |
110 |
111 |
119 |
128 |
129 |
130 | );
131 | }
132 |
--------------------------------------------------------------------------------
/components/ui/dialog.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as DialogPrimitive from "@radix-ui/react-dialog"
5 | import { Cross2Icon } from "@radix-ui/react-icons"
6 |
7 | import { cn } from "@/lib/utils"
8 |
9 | const Dialog = DialogPrimitive.Root
10 |
11 | const DialogTrigger = DialogPrimitive.Trigger
12 |
13 | const DialogPortal = DialogPrimitive.Portal
14 |
15 | const DialogClose = DialogPrimitive.Close
16 |
17 | const DialogOverlay = React.forwardRef<
18 | React.ElementRef,
19 | React.ComponentPropsWithoutRef
20 | >(({ className, ...props }, ref) => (
21 |
29 | ))
30 | DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31 |
32 | const DialogContent = React.forwardRef<
33 | React.ElementRef,
34 | React.ComponentPropsWithoutRef
35 | >(({ className, children, ...props }, ref) => (
36 |
37 |
38 |
46 | {children}
47 |
48 |
49 | Close
50 |
51 |
52 |
53 | ))
54 | DialogContent.displayName = DialogPrimitive.Content.displayName
55 |
56 | const DialogHeader = ({
57 | className,
58 | ...props
59 | }: React.HTMLAttributes) => (
60 |
67 | )
68 | DialogHeader.displayName = "DialogHeader"
69 |
70 | const DialogFooter = ({
71 | className,
72 | ...props
73 | }: React.HTMLAttributes) => (
74 |
81 | )
82 | DialogFooter.displayName = "DialogFooter"
83 |
84 | const DialogTitle = React.forwardRef<
85 | React.ElementRef,
86 | React.ComponentPropsWithoutRef
87 | >(({ className, ...props }, ref) => (
88 |
96 | ))
97 | DialogTitle.displayName = DialogPrimitive.Title.displayName
98 |
99 | const DialogDescription = React.forwardRef<
100 | React.ElementRef,
101 | React.ComponentPropsWithoutRef
102 | >(({ className, ...props }, ref) => (
103 |
108 | ))
109 | DialogDescription.displayName = DialogPrimitive.Description.displayName
110 |
111 | export {
112 | Dialog,
113 | DialogPortal,
114 | DialogOverlay,
115 | DialogTrigger,
116 | DialogClose,
117 | DialogContent,
118 | DialogHeader,
119 | DialogFooter,
120 | DialogTitle,
121 | DialogDescription,
122 | }
123 |
--------------------------------------------------------------------------------
/components/ui/form.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import * as LabelPrimitive from "@radix-ui/react-label"
5 | import { Slot } from "@radix-ui/react-slot"
6 | import {
7 | Controller,
8 | ControllerProps,
9 | FieldPath,
10 | FieldValues,
11 | FormProvider,
12 | useFormContext,
13 | } from "react-hook-form"
14 |
15 | import { cn } from "@/lib/utils"
16 | import { Label } from "@/components/ui/label"
17 |
18 | const Form = FormProvider
19 |
20 | type FormFieldContextValue<
21 | TFieldValues extends FieldValues = FieldValues,
22 | TName extends FieldPath = FieldPath
23 | > = {
24 | name: TName
25 | }
26 |
27 | const FormFieldContext = React.createContext(
28 | {} as FormFieldContextValue
29 | )
30 |
31 | const FormField = <
32 | TFieldValues extends FieldValues = FieldValues,
33 | TName extends FieldPath = FieldPath
34 | >({
35 | ...props
36 | }: ControllerProps) => {
37 | return (
38 |
39 |
40 |
41 | )
42 | }
43 |
44 | const useFormField = () => {
45 | const fieldContext = React.useContext(FormFieldContext)
46 | const itemContext = React.useContext(FormItemContext)
47 | const { getFieldState, formState } = useFormContext()
48 |
49 | const fieldState = getFieldState(fieldContext.name, formState)
50 |
51 | if (!fieldContext) {
52 | throw new Error("useFormField should be used within ")
53 | }
54 |
55 | const { id } = itemContext
56 |
57 | return {
58 | id,
59 | name: fieldContext.name,
60 | formItemId: `${id}-form-item`,
61 | formDescriptionId: `${id}-form-item-description`,
62 | formMessageId: `${id}-form-item-message`,
63 | ...fieldState,
64 | }
65 | }
66 |
67 | type FormItemContextValue = {
68 | id: string
69 | }
70 |
71 | const FormItemContext = React.createContext(
72 | {} as FormItemContextValue
73 | )
74 |
75 | const FormItem = React.forwardRef<
76 | HTMLDivElement,
77 | React.HTMLAttributes
78 | >(({ className, ...props }, ref) => {
79 | const id = React.useId()
80 |
81 | return (
82 |
83 |
84 |
85 | )
86 | })
87 | FormItem.displayName = "FormItem"
88 |
89 | const FormLabel = React.forwardRef<
90 | React.ElementRef,
91 | React.ComponentPropsWithoutRef
92 | >(({ className, ...props }, ref) => {
93 | const { error, formItemId } = useFormField()
94 |
95 | return (
96 |
102 | )
103 | })
104 | FormLabel.displayName = "FormLabel"
105 |
106 | const FormControl = React.forwardRef<
107 | React.ElementRef,
108 | React.ComponentPropsWithoutRef
109 | >(({ ...props }, ref) => {
110 | const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
111 |
112 | return (
113 |
124 | )
125 | })
126 | FormControl.displayName = "FormControl"
127 |
128 | const FormDescription = React.forwardRef<
129 | HTMLParagraphElement,
130 | React.HTMLAttributes
131 | >(({ className, ...props }, ref) => {
132 | const { formDescriptionId } = useFormField()
133 |
134 | return (
135 |
141 | )
142 | })
143 | FormDescription.displayName = "FormDescription"
144 |
145 | const FormMessage = React.forwardRef<
146 | HTMLParagraphElement,
147 | React.HTMLAttributes
148 | >(({ className, children, ...props }, ref) => {
149 | const { error, formMessageId } = useFormField()
150 | const body = error ? String(error?.message) : children
151 |
152 | if (!body) {
153 | return null
154 | }
155 |
156 | return (
157 |
163 | {body}
164 |
165 | )
166 | })
167 | FormMessage.displayName = "FormMessage"
168 |
169 | export {
170 | useFormField,
171 | Form,
172 | FormItem,
173 | FormLabel,
174 | FormControl,
175 | FormDescription,
176 | FormMessage,
177 | FormField,
178 | }
179 |
--------------------------------------------------------------------------------
/app/(protected)/receive/components/CellAction.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@/components/ui/button";
2 | import { ReceiveColumnsType } from "./columns";
3 | import { DownloadIcon } from "lucide-react";
4 | import { useState } from "react";
5 | import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
6 | import { Separator } from "@/components/ui/separator";
7 | import { z } from "zod";
8 | import { useForm } from "react-hook-form";
9 | import { zodResolver } from "@hookform/resolvers/zod";
10 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
11 | import { Input } from "@/components/ui/input";
12 | import toast from "react-hot-toast";
13 |
14 | interface CellActionProps {
15 | data: ReceiveColumnsType;
16 | token: string | null;
17 | }
18 |
19 | const passwordSchema = z.object({
20 | password: z.string()
21 | .min(6, { message: "Password should be at least 6 characters long" }),
22 | })
23 |
24 | export const CellAction = ({ data, token }: CellActionProps) => {
25 | const [isOpen, setIsOpen] = useState(false);
26 | const [isLoading, setIsLoading] = useState(false);
27 |
28 | const handleToggle = () => {
29 | setIsOpen(!isOpen);
30 | }
31 | const onClickHandler = () => {
32 | handleToggle()
33 | }
34 |
35 | const form = useForm>({
36 | resolver: zodResolver(passwordSchema),
37 | defaultValues:{
38 | password: '',
39 | }
40 | })
41 |
42 | const onSubmit = async (values: z.infer) => {
43 | setIsLoading(true)
44 | try {
45 | const response = await fetch('http://localhost:8000/api/file/retrieve', {
46 | method: 'POST',
47 | headers: {
48 | Authorization: `Bearer ${token}`,
49 | 'Content-Type': 'application/json',
50 | },
51 | body: JSON.stringify({ shared_id: data.file_id, password: values.password }),
52 | });
53 |
54 | if (!response.ok) {
55 | const errorData = await response.json();
56 | throw new Error(errorData.message || 'Failed to retrieve file');
57 | }
58 |
59 | const blob = await response.blob();
60 | const url = URL.createObjectURL(blob);
61 | const link = document.createElement('a');
62 | link.href = url;
63 | link.setAttribute('download', data.file_name); // You can set a specific filename here
64 | document.body.appendChild(link);
65 | link.click();
66 | link.remove();
67 | form.reset();
68 | handleToggle();
69 | } catch (err) {
70 | const errorMessage = err instanceof Error ? err.message : "Something went wrong!";
71 | toast.error(errorMessage);
72 | }
73 |
74 | setIsLoading(false)
75 | }
76 |
77 | return (
78 |
79 |
82 |
116 |
117 | )
118 | }
--------------------------------------------------------------------------------
/components/profile/PasswordChange.tsx:
--------------------------------------------------------------------------------
1 | import { useForm } from "react-hook-form"
2 | import { z } from "zod"
3 | import { passwordChangeSchema } from "../schema/profileType"
4 | import { zodResolver } from "@hookform/resolvers/zod"
5 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form"
6 | import { Input } from "../ui/input"
7 | import { Button } from "../ui/button"
8 | import { useTransition } from "react"
9 | import { updateUserPassword } from "@/action/profileHandler"
10 | import toast from "react-hot-toast"
11 |
12 | export const PasswordChange = () => {
13 |
14 | const [isPanding, startTransition] = useTransition();
15 |
16 | const form = useForm>({
17 | resolver: zodResolver(passwordChangeSchema),
18 | defaultValues: {
19 | old_password: '',
20 | new_password: '',
21 | new_password_confirm: ''
22 | }
23 | })
24 |
25 | const onSubmit = (values: z.infer) => {
26 | startTransition(() => {
27 | updateUserPassword(values)
28 | .then((response) => {
29 | if (response.status === 400){
30 | toast.error(response.message)
31 | }
32 |
33 | if (response.status == 'success') {
34 | toast.success(`User password update Successful!`)
35 | }
36 | })
37 | .catch((error) => {
38 | console.log(error);
39 | })
40 | })
41 | }
42 |
43 | return (
44 |
45 |
46 | Update User Password
47 |
48 |
110 |
111 |
112 | )
113 | }
--------------------------------------------------------------------------------
/components/auth/RegisterForm.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { useTransition } from "react";
4 | import { AuthCard } from "./AuthCard";
5 | import { useForm } from "react-hook-form";
6 | import { z } from "zod";
7 | import { registerSchema } from "../schema/authType";
8 | import { zodResolver } from "@hookform/resolvers/zod";
9 | import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
10 | import { Input } from "../ui/input";
11 | import { Button } from "../ui/button";
12 | import { RegisterApi } from "@/action/authHandler";
13 | import toast from "react-hot-toast";
14 | import { useRouter } from "next/navigation";
15 |
16 | export const RegisterForm = () => {
17 | const [isPanding, startTransistion] = useTransition();
18 | const router = useRouter();
19 |
20 | const form = useForm>({
21 | resolver: zodResolver(registerSchema),
22 | defaultValues: {
23 | name: "",
24 | email: "",
25 | password: "",
26 | passwordConfirm: "",
27 | },
28 | });
29 |
30 | const onSubmit = (values: z.infer) => {
31 | startTransistion(() => {
32 | RegisterApi(values).then((response) => {
33 | if (response.status === 400) {
34 | toast.error(response.message);
35 | }
36 |
37 | if (response.status == "success") {
38 | toast.success(`${response.message}, Redirecting to login...`);
39 | router.push("/login");
40 | }
41 | });
42 | });
43 | };
44 |
45 | return (
46 |
52 |
147 |
148 |
149 | );
150 | };
151 |
--------------------------------------------------------------------------------
/components/ui/select.tsx:
--------------------------------------------------------------------------------
1 | "use client"
2 |
3 | import * as React from "react"
4 | import {
5 | CaretSortIcon,
6 | CheckIcon,
7 | ChevronDownIcon,
8 | ChevronUpIcon,
9 | } from "@radix-ui/react-icons"
10 | import * as SelectPrimitive from "@radix-ui/react-select"
11 |
12 | import { cn } from "@/lib/utils"
13 |
14 | const Select = SelectPrimitive.Root
15 |
16 | const SelectGroup = SelectPrimitive.Group
17 |
18 | const SelectValue = SelectPrimitive.Value
19 |
20 | const SelectTrigger = React.forwardRef<
21 | React.ElementRef,
22 | React.ComponentPropsWithoutRef
23 | >(({ className, children, ...props }, ref) => (
24 | span]:line-clamp-1",
28 | className
29 | )}
30 | {...props}
31 | >
32 | {children}
33 |
34 |
35 |
36 |
37 | ))
38 | SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
39 |
40 | const SelectScrollUpButton = React.forwardRef<
41 | React.ElementRef,
42 | React.ComponentPropsWithoutRef
43 | >(({ className, ...props }, ref) => (
44 |
52 |
53 |
54 | ))
55 | SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
56 |
57 | const SelectScrollDownButton = React.forwardRef<
58 | React.ElementRef,
59 | React.ComponentPropsWithoutRef
60 | >(({ className, ...props }, ref) => (
61 |
69 |
70 |
71 | ))
72 | SelectScrollDownButton.displayName =
73 | SelectPrimitive.ScrollDownButton.displayName
74 |
75 | const SelectContent = React.forwardRef<
76 | React.ElementRef,
77 | React.ComponentPropsWithoutRef
78 | >(({ className, children, position = "popper", ...props }, ref) => (
79 |
80 |
91 |
92 |
99 | {children}
100 |
101 |
102 |
103 |
104 | ))
105 | SelectContent.displayName = SelectPrimitive.Content.displayName
106 |
107 | const SelectLabel = React.forwardRef<
108 | React.ElementRef,
109 | React.ComponentPropsWithoutRef
110 | >(({ className, ...props }, ref) => (
111 |
116 | ))
117 | SelectLabel.displayName = SelectPrimitive.Label.displayName
118 |
119 | const SelectItem = React.forwardRef<
120 | React.ElementRef,
121 | React.ComponentPropsWithoutRef
122 | >(({ className, children, ...props }, ref) => (
123 |
131 |
132 |
133 |
134 |
135 |
136 | {children}
137 |
138 | ))
139 | SelectItem.displayName = SelectPrimitive.Item.displayName
140 |
141 | const SelectSeparator = React.forwardRef<
142 | React.ElementRef,
143 | React.ComponentPropsWithoutRef
144 | >(({ className, ...props }, ref) => (
145 |
150 | ))
151 | SelectSeparator.displayName = SelectPrimitive.Separator.displayName
152 |
153 | export {
154 | Select,
155 | SelectGroup,
156 | SelectValue,
157 | SelectTrigger,
158 | SelectContent,
159 | SelectLabel,
160 | SelectItem,
161 | SelectSeparator,
162 | SelectScrollUpButton,
163 | SelectScrollDownButton,
164 | }
165 |
--------------------------------------------------------------------------------
/app/(protected)/upload/new/components/UploadNew.tsx:
--------------------------------------------------------------------------------
1 | "use client";
2 |
3 | import { searchEmail } from "@/action/fileHandler";
4 | import { Button } from "@/components/ui/button";
5 | import { Calendar } from "@/components/ui/calendar";
6 | import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
7 | import {
8 | Form,
9 | FormControl,
10 | FormField,
11 | FormItem,
12 | FormLabel,
13 | FormMessage,
14 | } from "@/components/ui/form";
15 | import { Input } from "@/components/ui/input";
16 | import {
17 | Popover,
18 | PopoverContent,
19 | PopoverTrigger,
20 | } from "@/components/ui/popover";
21 | import {
22 | Select,
23 | SelectContent,
24 | SelectItem,
25 | SelectTrigger,
26 | SelectValue,
27 | } from "@/components/ui/select";
28 | import { Separator } from "@/components/ui/separator";
29 | import { cn } from "@/lib/utils";
30 | import { zodResolver } from "@hookform/resolvers/zod";
31 | import { format } from "date-fns";
32 | import { CalendarIcon } from "lucide-react";
33 | import { useRouter } from "next/navigation";
34 | import { useEffect, useState } from "react";
35 | import { useForm } from "react-hook-form";
36 | import toast from "react-hot-toast";
37 | import { z } from "zod";
38 |
39 | const emailFormSchema = z.object({
40 | recipient_email: z.string().email("Please enter a valid email address"),
41 | password: z.string().min(6, "Password must be at least 6 characters"),
42 | expiration_date: z
43 | .date()
44 | .refine(
45 | (val) => val >= new Date(),
46 | "Expiration date must be in the future"
47 | ),
48 | fileUpload: z
49 | .instanceof(File, { message: "Please select a file" })
50 | .refine(
51 | (file) =>
52 | file &&
53 | ["image/jpeg", "image/png", "image/jpg", "application/pdf"].includes(
54 | file.type
55 | ),
56 | "Only images (jpg, jpeg, png) and PDF files are allowed"
57 | ).refine(
58 | (file) => file && file.size <= 4 * 1024 * 1024, // 4MB in bytes
59 | { message: "File size must be less than or equal to 4MB" }
60 | ),
61 | });
62 |
63 | export const UploadNew = ({ token }: { token: string | null }) => {
64 | const [emailSuggestions, setEmailSuggestions] = useState<
65 | { email: string }[]
66 | >([]);
67 | const [isFetchingEmails, setIsFetchingEmails] = useState(false);
68 | const [isPanding, setIsPanding] = useState(false);
69 | const router = useRouter();
70 |
71 | const tomorrowDate = () => {
72 | const tomorrow = new Date();
73 | tomorrow.setDate(tomorrow.getDate() + 1);
74 | return tomorrow;
75 | };
76 |
77 | const form = useForm>({
78 | resolver: zodResolver(emailFormSchema),
79 | defaultValues: {
80 | recipient_email: "",
81 | password: "",
82 | expiration_date: tomorrowDate(),
83 | },
84 | });
85 | const recipient_email = form.watch("recipient_email");
86 | const password = form.watch("password");
87 | const expirationDate = form.watch("expiration_date");
88 |
89 | const isFormFilled = recipient_email && password && expirationDate;
90 |
91 | useEffect(() => {
92 | const fetchEmailSuggestions = async (query: string) => {
93 | if (!query) return;
94 | setIsFetchingEmails(true);
95 | try {
96 | const response = await searchEmail(query);
97 | setEmailSuggestions(response.emails || []);
98 | } catch (error) {
99 | console.error("Failed to fetch email suggestions:", error);
100 | } finally {
101 | setIsFetchingEmails(false);
102 | }
103 | };
104 |
105 | // Debounce API calls
106 | const delayDebounceFn = setTimeout(() => {
107 | if (recipient_email) {
108 | fetchEmailSuggestions(recipient_email);
109 | }
110 | }, 300);
111 |
112 | return () => clearTimeout(delayDebounceFn);
113 | }, [recipient_email]);
114 |
115 | const handleFileUplaod = (event: React.ChangeEvent) => {
116 | const file = event.target.files?.[0];
117 | if (file) {
118 | form.setValue("fileUpload", file);
119 | }
120 | };
121 |
122 | const onSubmit = async (values: z.infer) => {
123 | setIsPanding(true);
124 | const formData = new FormData();
125 |
126 | formData.append('recipient_email', values.recipient_email);
127 | formData.append('password', values.password);
128 | formData.append('expiration_date', values.expiration_date.toISOString());
129 | formData.append('fileUpload', values.fileUpload);
130 |
131 | const response = await fetch(`http://localhost:8000/api/file/upload`,
132 | {
133 | method: 'post',
134 | body: formData,
135 | headers: {
136 | Authorization: `Bearer ${token}`,
137 | }
138 | }
139 | )
140 |
141 | const result = await response.json();
142 | if(result.status == "success") {
143 | toast.success(result.message);
144 | router.push('/upload')
145 | }else{
146 | toast.error(result.message)
147 | }
148 | setIsPanding(false);
149 | }
150 |
151 | return (
152 |
153 |
154 | Upload new File
155 |
156 |
157 |
158 |
274 |
275 |
276 |
277 | );
278 | };
279 |
--------------------------------------------------------------------------------
|