summaryrefslogtreecommitdiff
path: root/lib/vendor-users/table/update-auser-sheet.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-06-27 01:16:20 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-06-27 01:16:20 +0000
commite9897d416b3e7327bbd4d4aef887eee37751ae82 (patch)
treebd20ce6eadf9b21755bd7425492d2d31c7700a0e /lib/vendor-users/table/update-auser-sheet.tsx
parent3bf1952c1dad9d479bb8b22031b06a7434d37c37 (diff)
(대표님) 20250627 오전 10시 작업사항
Diffstat (limited to 'lib/vendor-users/table/update-auser-sheet.tsx')
-rw-r--r--lib/vendor-users/table/update-auser-sheet.tsx273
1 files changed, 273 insertions, 0 deletions
diff --git a/lib/vendor-users/table/update-auser-sheet.tsx b/lib/vendor-users/table/update-auser-sheet.tsx
new file mode 100644
index 00000000..2009e517
--- /dev/null
+++ b/lib/vendor-users/table/update-auser-sheet.tsx
@@ -0,0 +1,273 @@
+"use client"
+
+import * as React from "react"
+import { zodResolver } from "@hookform/resolvers/zod"
+import { Loader } from "lucide-react"
+import { useForm } from "react-hook-form"
+import { toast } from "sonner"
+
+import {
+ Sheet,
+ SheetClose,
+ SheetContent,
+ SheetDescription,
+ SheetFooter,
+ SheetHeader,
+ SheetTitle,
+} from "@/components/ui/sheet"
+import { Button } from "@/components/ui/button"
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+ FormDescription,
+} from "@/components/ui/form"
+import { Input } from "@/components/ui/input"
+import {
+ Select,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ SelectValue,
+ SelectGroup,
+} from "@/components/ui/select"
+// import your MultiSelect or other role selection
+import { MultiSelect } from "@/components/ui/multi-select"
+import { cn } from "@/lib/utils"
+
+import { userRoles, type UserView } from "@/db/schema/users"
+import { UpdateVendorUserSchema, updateVendorUserSchema } from "../validations"
+import { modifiVendorUser } from "../service"
+
+export interface UpdateAuserSheetProps
+ extends React.ComponentPropsWithRef<typeof Sheet> {
+ user: UserView | null
+}
+
+const languageOptions = [
+ { value: "ko", label: "한국어" },
+ { value: "en", label: "English" },
+]
+
+// Phone validation helper
+const validatePhoneNumber = (phone: string): boolean => {
+ if (!phone) return true; // Optional field
+ // Basic international phone number validation
+ const cleanPhone = phone.replace(/[\s\-\(\)]/g, '');
+ return /^\+\d{10,15}$/.test(cleanPhone);
+};
+
+// Get phone placeholder
+const getPhonePlaceholder = (): string => {
+ return "+82 010-1234-5678";
+};
+
+// Get phone description
+const getPhoneDescription = (): string => {
+ return "국제 전화번호를 입력하세요. (예: +82 010-1234-5678)";
+};
+
+export function UpdateAuserSheet({ user, ...props }: UpdateAuserSheetProps) {
+ const [isUpdatePending, startUpdateTransition] = React.useTransition()
+
+ // 1) RHF 설정
+ const form = useForm<UpdateVendorUserSchema & { language?: string; phone?: string }>({
+ resolver: zodResolver(updateVendorUserSchema),
+ defaultValues: {
+ name: user?.user_name ?? "",
+ email: user?.user_email ?? "",
+ phone: user?.user_phone ?? "", // Add phone field
+ roles: user?.roles ?? [],
+ language: 'en',
+ },
+ })
+
+ // 2) user prop 바뀔 때마다 form.reset
+ React.useEffect(() => {
+ if (user) {
+ form.reset({
+ name: user.user_name,
+ email: user.user_email,
+ phone: user.user_phone || "", // Add phone field
+ roles: user.roles,
+ language: 'en', // You might want to get this from user object
+ })
+ }
+ }, [user, form])
+
+ // 3) onSubmit
+ async function onSubmit(input: UpdateVendorUserSchema & { language?: string; phone?: string }) {
+ // Validate phone number if provided
+ if (input.phone && !validatePhoneNumber(input.phone)) {
+ toast.error("올바른 국제 전화번호 형식이 아닙니다.")
+ return
+ }
+
+ startUpdateTransition(async () => {
+ if (!user) return
+
+ const { error } = await modifiVendorUser({
+ id: user.user_id,
+ ...input,
+ })
+
+ if (error) {
+ toast.error(error)
+ return
+ }
+
+ // 성공 시
+ form.reset()
+ props.onOpenChange?.(false)
+ toast.success("User updated successfully!")
+ })
+ }
+
+ return (
+ <Sheet {...props}>
+ <SheetContent className="flex flex-col gap-6 sm:max-w-md">
+ <SheetHeader className="text-left">
+ <SheetTitle>Update user</SheetTitle>
+ <SheetDescription>
+ Update the user details and save the changes
+ </SheetDescription>
+ </SheetHeader>
+
+ {/* 4) RHF Form */}
+ <Form {...form}>
+ <form
+ onSubmit={form.handleSubmit(onSubmit)}
+ className="flex flex-col gap-4"
+ >
+ {/* name */}
+ <FormField
+ control={form.control}
+ name="name"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>User Name</FormLabel>
+ <FormControl>
+ <Input placeholder="e.g. dujin" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* email */}
+ <FormField
+ control={form.control}
+ name="email"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Email</FormLabel>
+ <FormControl>
+ <Input type="email" placeholder="user@example.com" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 전화번호 - 새로 추가 */}
+ <FormField
+ control={form.control}
+ name="phone"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Phone Number</FormLabel>
+ <FormControl>
+ <Input
+ placeholder={getPhonePlaceholder()}
+ {...field}
+ className={cn(
+ field.value && !validatePhoneNumber(field.value) && "border-red-500"
+ )}
+ />
+ </FormControl>
+ <FormDescription className="text-xs text-muted-foreground">
+ {getPhoneDescription()}
+ </FormDescription>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* roles */}
+ <FormField
+ control={form.control}
+ name="roles"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Roles</FormLabel>
+ <FormControl>
+ <MultiSelect
+ defaultValue={form?.getValues().roles}
+ options={[
+ { value: "999999999", label: "admin" }
+ ]}
+ value={field.value}
+ onValueChange={(vals) => field.onChange(vals)}
+ />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* language */}
+ <FormField
+ control={form.control}
+ name="language"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>Language</FormLabel>
+ <FormControl>
+ <Select
+ onValueChange={field.onChange}
+ value={field.value}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="Select language" />
+ </SelectTrigger>
+ <SelectContent>
+ {languageOptions.map((v, index) => (
+ <SelectItem key={index} value={v.value}>
+ {v.label}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 5) Footer: Cancel, Save */}
+ <SheetFooter className="gap-2 pt-2 sm:space-x-0">
+ <SheetClose asChild>
+ <Button type="button" variant="outline">
+ Cancel
+ </Button>
+ </SheetClose>
+
+ <Button type="submit" disabled={isUpdatePending}>
+ {isUpdatePending && (
+ <Loader
+ className="mr-2 size-4 animate-spin"
+ aria-hidden="true"
+ />
+ )}
+ Save
+ </Button>
+ </SheetFooter>
+ </form>
+ </Form>
+ </SheetContent>
+ </Sheet>
+ )
+} \ No newline at end of file