first commit

This commit is contained in:
Samandar Turgunboyev
2025-10-18 17:14:59 +05:00
parent edf364b389
commit 036a36ce90
92 changed files with 14614 additions and 135 deletions

View File

@@ -0,0 +1,195 @@
"use client";
import { Button } from "@/shared/ui/button";
import {
Form,
FormControl,
FormField,
FormItem,
FormMessage,
} from "@/shared/ui/form";
import { Input } from "@/shared/ui/input";
import { Label } from "@/shared/ui/label";
import { Textarea } from "@/shared/ui/textarea";
import { zodResolver } from "@hookform/resolvers/zod";
import { PlusCircle, Trash2, XIcon } from "lucide-react";
import type { Dispatch, SetStateAction } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import z from "zod";
const newsItemSchema = z.object({
desc: z.string().min(2, {
message: "Yangilik matni kamida 2 belgidan iborat bolishi kerak",
}),
banner: z.string().min(1, { message: "Banner rasmi majburiy" }),
});
const newsListSchema = z.object({
items: z
.array(newsItemSchema)
.min(1, { message: "Kamida 1 ta yangilik kerak" }),
});
type NewsFormType = z.infer<typeof newsListSchema>;
const StepTwo = ({
setStep,
isEditMode,
}: {
setStep: Dispatch<SetStateAction<number>>;
isEditMode: boolean;
}) => {
const form = useForm<NewsFormType>({
resolver: zodResolver(newsListSchema),
defaultValues: {
items: [{ desc: "", banner: "" }],
},
});
const { fields, append, remove } = useFieldArray({
control: form.control,
name: "items",
});
const navigator = useNavigate();
function onSubmit() {
navigator("/news");
}
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="space-y-8 bg-gray-900 p-6 rounded-2xl text-white"
>
<h2 className="text-2xl font-semibold">Yangiliklar royxati</h2>
{fields.map((field, index) => (
<div
key={field.id}
className="relative border border-gray-700 bg-gray-800 rounded-xl p-4 space-y-4"
>
{/* O'chirish tugmasi */}
{fields.length > 1 && (
<button
type="button"
onClick={() => remove(index)}
className="absolute top-3 right-3 text-red-400 hover:text-red-500"
>
<Trash2 className="size-5" />
</button>
)}
{/* DESC FIELD */}
<FormField
control={form.control}
name={`items.${index}.desc`}
render={({ field }) => (
<FormItem>
<Label className="text-md">Yangilik haqida</Label>
<FormControl>
<Textarea
placeholder="Yangilik haqida"
{...field}
className="min-h-48 max-h-56 !text-md bg-gray-800 border-gray-700 text-white"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* BANNER FIELD */}
<FormField
control={form.control}
name={`items.${index}.banner`}
render={() => (
<FormItem>
<Label className="text-md">Banner rasmi</Label>
<FormControl>
<div className="flex flex-col gap-3 w-full">
<Input
type="file"
id={`file-${index}`}
accept="image/*"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
const url = URL.createObjectURL(file);
form.setValue(`items.${index}.banner`, url);
}
}}
className="hidden"
/>
<label
htmlFor={`file-${index}`}
className="w-full border-2 border-dashed h-40 border-gray-600 hover:border-gray-500 transition-all flex flex-col items-center gap-2 justify-center py-4 rounded-2xl cursor-pointer"
>
<p className="font-semibold text-xl text-white">
Drag or select files
</p>
<p className="text-gray-300 text-sm">
Drop files here or click to browse
</p>
</label>
{form.watch(`items.${index}.banner`) && (
<div className="relative size-24 rounded-md overflow-hidden border border-gray-700">
<img
src={form.watch(`items.${index}.banner`)}
alt="Banner preview"
className="object-cover w-full h-full"
/>
<button
type="button"
onClick={() =>
form.setValue(`items.${index}.banner`, "")
}
className="absolute top-1 right-1 bg-white/80 rounded-full p-1 shadow hover:bg-white"
>
<XIcon className="size-4 text-destructive" />
</button>
</div>
)}
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
))}
<div className="flex justify-end">
<Button
type="button"
onClick={() => append({ desc: "", banner: "" })}
className="flex items-center px-6 py-5 text-lg gap-2 bg-gray-600 hover:bg-gray-700 text-white cursor-pointer"
>
<PlusCircle className="size-5" />
Qoshish
</Button>
</div>
{/* Navigatsiya tugmalari */}
<div className="w-full flex justify-between pt-4">
<Button
type="button"
onClick={() => setStep(1)}
className="bg-gray-600 hover:bg-gray-700 text-white"
>
Orqaga
</Button>
<Button
type="submit"
className="bg-blue-600 hover:bg-blue-700 text-white"
>
{isEditMode ? "Yangiliklarni saqlash" : "Saqlash"}
</Button>
</div>
</form>
</Form>
);
};
export default StepTwo;