diff --git a/app/(customer)/dashboard/profile/page.tsx b/app/(customer)/dashboard/profile/page.tsx index 7b86781f..03e8fd62 100644 --- a/app/(customer)/dashboard/profile/page.tsx +++ b/app/(customer)/dashboard/profile/page.tsx @@ -11,6 +11,7 @@ import {Button} from "@/components/ui/button"; import {ButtonWithConfirm} from "@/components/wrappers/Button/ButtonWithConfirm/ButtonWithConfirm"; import {ButtonDeleteAccount} from "@/components/wrappers/Dashboard/Profile/ButtonDeleteAccount/ButtonDeleteAccount"; import {useIsMobile} from "@/hooks/use-mobile"; +import {AvatarWithUpload} from "@/components/wrappers/Dashboard/Profile/Avatar/AvatarWithUpload"; export default async function RoutePage(props: PageParams<{}>) { @@ -25,23 +26,13 @@ export default async function RoutePage(props: PageParams<{}>) { } }) - console.log(userInfo) - - const test = () => { - console.log("test") - } return ( {/**/}
- - {user.name?.[0]} - {user.image ? ( - - ) : null} - + {user.name} {userInfo.authMethod} diff --git a/src/components/wrappers/Dashboard/LoggedInDropdown/LoggedInDropdown.tsx b/src/components/wrappers/Dashboard/LoggedInDropdown/LoggedInDropdown.tsx index f0a644e3..43b283d3 100644 --- a/src/components/wrappers/Dashboard/LoggedInDropdown/LoggedInDropdown.tsx +++ b/src/components/wrappers/Dashboard/LoggedInDropdown/LoggedInDropdown.tsx @@ -3,11 +3,6 @@ import {PropsWithChildren} from "react"; import {DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger} from "@/components/ui/dropdown-menu"; import {signOutAction} from "@/features/auth/auth.action"; -import {Home, LogOut, Square, User, Gauge, User2, ChevronUp} from "lucide-react"; -import Link from "next/link"; -import {useTranslations} from "use-intl"; -import {SidebarMenuButton} from "@/components/ui/sidebar"; -import {UserAvatar} from "@/components/wrappers/Dashboard/UserAvatar/UserAvatar"; import {redirect} from "next/navigation"; export type LoggedInDropdownProps = PropsWithChildren<{}> diff --git a/src/components/wrappers/Dashboard/Profile/Avatar/AvatarWithUpload.tsx b/src/components/wrappers/Dashboard/Profile/Avatar/AvatarWithUpload.tsx new file mode 100644 index 00000000..bce604fa --- /dev/null +++ b/src/components/wrappers/Dashboard/Profile/Avatar/AvatarWithUpload.tsx @@ -0,0 +1,83 @@ +"use client" +import {Avatar, AvatarFallback, AvatarImage} from "@/components/ui/avatar"; +import {User} from "@prisma/client"; +import {UploadIcon} from "lucide-react"; +import {toast} from "sonner"; +import {uploadImageAction} from "@/features/upload/upload.action"; +import {useMutation} from "@tanstack/react-query"; +import {prisma} from "@/prisma"; + +export type AvatarWithUploadProps = { + user: User +} + + +export const AvatarWithUpload = (props: AvatarWithUploadProps) => { + const user = props.user + + + const submitImage = useMutation({ + mutationFn: async (file: File) => { + const formData = new FormData(); + formData.set("file", file); + const uploadImage = await uploadImageAction(formData) + const data = uploadImage?.data?.data + + if (uploadImage?.serverError || !data) { + console.log(uploadImage?.serverError); + toast.error(uploadImage?.serverError); + return; + } + + console.log(props.user.id) + await prisma.user.update({ + where: { + id: props.user.id, + }, + data: { + image: data.url + } + }) + + toast.success("Successfully uploaded user image!"); + + + + } + }) + + const handleImageUpload = async (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (!file) return; + if (!file.type.includes("image")) { + toast.error("File not an image") + return; + } + submitImage.mutate(file) + }; + + + return ( +
+ + {user.name?.[0]} + {user.image ? ( + + ) : null} + +
{ + const fileInput = document.createElement("input"); + fileInput.type = "file"; + fileInput.accept = "image/*"; + // @ts-ignore + fileInput.onchange = handleImageUpload; + fileInput.click(); + }} + className="cursor-pointer absolute inset-0 flex justify-center items-center opacity-0 transition-opacity hover:opacity-100 hover:bg-gray-500 hover:bg-opacity-50 rounded-full size-14" + > + +
+
+ ) +} \ No newline at end of file diff --git a/src/features/upload/upload.action.ts b/src/features/upload/upload.action.ts new file mode 100644 index 00000000..bc2f17f1 --- /dev/null +++ b/src/features/upload/upload.action.ts @@ -0,0 +1,50 @@ +"use server" +import {userAction} from "@/safe-actions"; +import {z} from "zod"; +import {v4 as uuidv4} from 'uuid'; +import { writeFile } from "fs/promises"; +import path from "path"; +import {env} from "@/env.mjs"; + + +export const uploadImageAction = userAction + .schema(z.instanceof(FormData)) + .action(async ({parsedInput: formData, ctx}) => { + + const file = formData.get("file") as File + const uuid = uuidv4() + + const fileFormat = file.name.split(".").slice(-1)[0] + const fileName = uuid + "." + fileFormat + const arrayBuffer = await file.arrayBuffer() + const buffer = Buffer.from(arrayBuffer) + + const localDir = "public/uploads/" + + try { + const result = await writeFile( + path.join(process.cwd(), localDir + fileName), + buffer + ); + + let url: string = ""; + + if (env.NODE_ENV === "production") { + // url = `https://${env.S3_ENDPOINT}/${bucketName}/${fileName}` + } else { + url = `http://localhost:8887/${localDir}${fileName}` + } + return { + data: {result: result, url: url}, + } + + } catch (error) { + console.log("Error occured ", error); + throw new Error('An error occured while importing image'); + + } + + + }); + +