Files
simple-admin/src/pages/users/ui/Edit.tsx
Samandar Turgunboyev 64f8467f41 bug fix loading
2025-11-11 16:05:22 +05:00

270 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { getUserDetail, updateUser } from "@/pages/users/lib/api";
import { useMutation, useQuery } from "@tanstack/react-query";
import formatPhone from "@/shared/lib/formatPhone";
import onlyNumber from "@/shared/lib/onlyNumber";
import { Button } from "@/shared/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/shared/ui/form";
import { Input } from "@/shared/ui/input";
import { ArrowLeft, Loader2, Mail, Phone, Save, User } from "lucide-react";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate, useParams } from "react-router-dom";
const formSchema = z
.object({
first_name: z
.string()
.min(3, "Ism kamida 3 ta belgidan iborat bolishi kerak")
.nonempty("Ism majburiy"),
last_name: z
.string()
.min(3, "Familiya kamida 3 ta belgidan iborat bolishi kerak")
.nonempty("Familiya majburiy"),
email: z.string().email("Email formati notogri").or(z.literal("")),
phone: z.string().min(9, "Telefon raqam toliq emas").or(z.literal("+998")),
})
.refine((data) => data.email || data.phone, {
message: "Email yoki telefon raqami kiritilishi shart",
path: ["contact"],
});
export default function EditUser() {
const navigate = useNavigate();
const { id } = useParams();
const { t } = useTranslation();
const { data } = useQuery({
queryKey: ["user_detail", id],
queryFn: () => getUserDetail({ id: Number(id) }),
});
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
first_name: "",
last_name: "",
email: "",
phone: "+998",
},
});
useEffect(() => {
if (data) {
const u = data.data.data;
form.reset({
first_name: u.first_name,
last_name: u.last_name,
email: u.email || "",
phone: formatPhone(u.phone),
});
}
}, [data, form]);
const { mutate, isPending } = useMutation({
mutationFn: ({
body,
id,
}: {
body: {
first_name: string;
last_name: string;
email: string | null;
phone: string | null;
};
id: number;
}) => updateUser({ body, id }),
onSuccess: () => navigate("/user"),
});
const onSubmit = (values: z.infer<typeof formSchema>) => {
if (data) {
mutate({
body: {
first_name: values.first_name,
last_name: values.last_name,
email: values.email.length === 0 ? null : values.email,
phone: values.phone.length === 0 ? null : onlyNumber(values.phone),
},
id: data.data.data.id,
});
}
};
return (
<div className="min-h-screen w-full bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 p-4 md:p-8">
<div className="w-full mx-auto">
{/* Header */}
<div className="mb-6">
<Button
variant="ghost"
onClick={() => navigate(-1)}
className="mb-4 -ml-2 text-slate-400 cursor-pointer hover:text-slate-100 hover:bg-slate-800/50"
>
<ArrowLeft className="w-4 h-4 mr-2" />
{t("Orqaga")}
</Button>
<div className="flex items-center gap-3">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-emerald-600 to-teal-700 flex items-center justify-center shadow-lg shadow-emerald-500/20">
<User className="w-6 h-6 text-white" />
</div>
<div>
<h1 className="text-2xl font-bold text-slate-100">
{t("Tahrirlash")}
</h1>
<p className="text-slate-400 text-sm">
{t("Ma'lumotlarni yangilang")}
</p>
</div>
</div>
</div>
{/* Form */}
<div className="bg-slate-900/50 backdrop-blur-sm rounded-2xl shadow-xl border border-slate-800/50 p-6 md:p-8">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-5">
{/* First Name */}
<FormField
control={form.control}
name="first_name"
render={({ field }) => (
<FormItem>
<FormLabel className="text-slate-300">
{t("Ismi")}
</FormLabel>
<FormControl>
<div className="relative">
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
<Input
{...field}
placeholder="John"
className="pl-10 h-11 bg-slate-800/50 text-slate-200 border-slate-700/50 focus:border-emerald-500"
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Last Name */}
<FormField
control={form.control}
name="last_name"
render={({ field }) => (
<FormItem>
<FormLabel className="text-slate-300">
{t("Familiyasi")}
</FormLabel>
<FormControl>
<div className="relative">
<User className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
<Input
{...field}
placeholder="Doe"
className="pl-10 h-11 bg-slate-800/50 text-slate-200 border-slate-700/50 focus:border-emerald-500"
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Email */}
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel className="text-slate-300">
{t("Email")}
</FormLabel>
<FormControl>
<div className="relative">
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
<Input
{...field}
placeholder="email@example.com"
className="pl-10 h-11 bg-slate-800/50 text-slate-200 border-slate-700/50 focus:border-emerald-500"
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Phone */}
<FormField
control={form.control}
name="phone"
render={({ field }) => (
<FormItem>
<FormLabel className="text-slate-300">
{t("Telefon raqami")}
</FormLabel>
<FormControl>
<div className="relative">
<Phone className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-500" />
<Input
{...field}
value={formatPhone(field.value)}
onChange={(e) => field.onChange(e.target.value)}
placeholder="+998 90 123 45 67"
className="pl-10 h-11 bg-slate-800/50 text-slate-200 border-slate-700/50 focus:border-emerald-500"
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Submit buttons */}
<div className="flex gap-3 pt-4">
<Button
type="button"
variant="outline"
onClick={() => navigate(-1)}
className="flex-1 h-11 rounded-lg border-slate-700/50 bg-slate-800/50 hover:bg-slate-700/50 text-slate-300 hover:text-slate-100 font-medium"
>
{t("Bekor qilish")}
</Button>
<Button
type="submit"
disabled={isPending}
className="flex-1 h-11 rounded-lg bg-gradient-to-r from-emerald-600 to-teal-700 hover:from-emerald-700 hover:to-teal-800 text-white font-medium"
>
{isPending ? (
<Loader2 className="animate-spin" />
) : (
<>
<Save className="w-5 h-5 mr-2" />
{t("Yangilash")}
</>
)}
</Button>
</div>
</form>
</Form>
</div>
</div>
</div>
);
}