From 1a2241c40e10193c5ff7008a7b7b36cc1d855d96 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 25 Mar 2025 15:55:45 +0900
Subject: initial commit

---
 components/settings/account-form.tsx | 263 +++++++++++++++++++++++++++++++++++
 1 file changed, 263 insertions(+)
 create mode 100644 components/settings/account-form.tsx

(limited to 'components/settings/account-form.tsx')

diff --git a/components/settings/account-form.tsx b/components/settings/account-form.tsx
new file mode 100644
index 00000000..97cad9e5
--- /dev/null
+++ b/components/settings/account-form.tsx
@@ -0,0 +1,263 @@
+"use client"
+
+import * as React from "react"
+import { zodResolver } from "@hookform/resolvers/zod"
+import { useForm } from "react-hook-form"
+import { z } from "zod"
+
+import { toast } from "@/hooks/use-toast"
+import { Button } from "@/components/ui/button"
+
+import {
+  Form,
+  FormControl,
+  FormDescription,
+  FormField,
+  FormItem,
+  FormLabel,
+  FormMessage,
+} from "@/components/ui/form"
+import { Input } from "@/components/ui/input"
+
+import { findUserById } from "@/lib/admin-users/service"
+import { useSession } from "next-auth/react";
+
+import { updateUserProfileImage } from "@/lib/users/service"
+
+
+
+const accountFormSchema = z.object({
+  name: z
+    .string()
+    .min(2, {
+      message: "Name must be at least 2 characters.",
+    })
+    .max(30, {
+      message: "Name must not be longer than 30 characters.",
+    }),
+  email: z.string().email(),
+  company: z
+    .string()
+    .min(2, {
+      message: "Name must be at least 2 characters.",
+    })
+    .max(30, {
+      message: "Name must not be longer than 30 characters.",
+    }),
+
+  imageFile: z.any().optional(),
+
+})
+
+type AccountFormValues = z.infer<typeof accountFormSchema>
+
+
+
+export function AccountForm() {
+
+  const { data: session } = useSession();
+  const userId = session?.user.id || ""
+
+
+  const [previewUrl, setPreviewUrl] = React.useState<string | null>(null)
+
+  const form = useForm<AccountFormValues>({
+    resolver: zodResolver(accountFormSchema),
+    defaultValues: {
+      name: "",
+      company: "",
+      email: "",
+      imageFile: null,
+    },
+  })
+
+  // Fetch data in useEffect
+  React.useEffect(() => {
+    console.log("Form state changed: ", form.getValues());
+
+    async function fetchUser() {
+      try {
+        const data = await findUserById(Number(userId))
+        if (data) {
+          // Also reset the form's default values
+          form.reset({
+            name: data.user_name || "",
+            company: data.company_name || "",
+            email: data.user_email || "",
+            imageFile: data.user_image, // no file to begin with
+          })
+        }
+      } catch (error) {
+        console.error("Failed to fetch user data:", error)
+      }
+    }
+
+    if (userId) {
+      fetchUser()
+    }
+  }, [userId, form])
+
+
+  async function onSubmit(data: AccountFormValues) {
+    // RHF가 추적한 dirtyFields를 가져옵니다.
+    const { dirtyFields } = form.formState
+
+    // 변경된 필드가 전혀 없다면 => 업데이트 스킵
+    if (Object.keys(dirtyFields).length === 0) {
+      toast({
+        title: "No changes",
+        description: "Nothing to update",
+      })
+      return
+    }
+
+    // 바뀐 파일만 업로드
+    let imageFile: File | null = null
+    if (dirtyFields.imageFile && data.imageFile && data.imageFile.length > 0) {
+      // 새로 업로드한 파일
+      imageFile = data.imageFile[0]
+    }
+
+    // FormData 생성
+    const formData = new FormData()
+    formData.append("userId", userId)
+    formData.append("name", data.name)
+    formData.append("company", data.company)
+    formData.append("email", data.email)
+
+    if (imageFile) {
+      formData.append("file", imageFile)
+    }
+
+    try {
+      // 서버 액션(또는 API) 호출
+      await updateUserProfileImage(formData)
+
+      toast({
+        title: "Account updated",
+        description: "User updated successfully!",
+      })
+
+    } catch (error: any) {
+      toast({
+        title: "Error",
+        description: `Error: ${error.message ?? error}`,
+        variant: "destructive",
+      })
+    }
+  }
+
+
+  return (
+    <Form {...form}>
+      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
+        <FormField
+          control={form.control}
+          name="name"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>Name</FormLabel>
+              <FormControl>
+                <Input placeholder="Your name" {...field} />
+              </FormControl>
+              <FormDescription>
+                This is the name that will be displayed on your profile and in
+                emails.
+              </FormDescription>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+
+        <FormField
+          control={form.control}
+          name="email"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>Email</FormLabel>
+              <FormControl>
+                <Input placeholder="Your Email" {...field} />
+              </FormControl>
+              <FormDescription>
+                This is the email that will be used on login. If you want change it, please be careful.
+              </FormDescription>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+
+        <FormField
+          control={form.control}
+          name="company"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>Company</FormLabel>
+              <FormControl>
+                <Input
+                  placeholder="Your Company name"
+                  {...field}
+                  readOnly
+                  className="cursor-not-allowed bg-slate-50"
+                />
+              </FormControl>
+              <FormDescription>
+                This is the name that will be displayed on your profile and in
+                emails.
+              </FormDescription>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+
+
+
+        {/* 이미지 업로드 */}
+        <FormField
+          control={form.control}
+          name="imageFile"
+          render={({ field }) => (
+            <FormItem>
+              <FormLabel>Profile Image</FormLabel>
+              <FormControl>
+              <div className="space-y-2">
+                <Input
+                  type="file"
+                  accept="image/*"
+                  onChange={(e) => {
+                    field.onChange(e.target.files)
+                    if (e.target.files && e.target.files.length > 0) {
+                      // 로컬 미리보기 URL
+                      const file = e.target.files[0]
+                      const url = URL.createObjectURL(file)
+                      setPreviewUrl(url)
+                    }
+                  }}
+                />
+
+                {previewUrl ? (
+                  <img src={previewUrl} alt="Local Preview" width={200}/>
+                ) : (
+                  typeof field.value === "string" &&
+                  field.value && (
+                    <img
+                      src={`/profiles/${field.value}`}
+                      alt="Server Image" 
+                      width={200}
+                    />
+                  )
+                )}
+             </div>
+              </FormControl>
+              <FormDescription>
+                Upload your profile image.
+              </FormDescription>
+              <FormMessage />
+            </FormItem>
+          )}
+        />
+
+        <Button type="submit">Update account</Button>
+      </form>
+    </Form>
+  )
+}
-- 
cgit v1.2.3

