diff --git a/src/pages/landing-hero/HeroSliderPage.tsx b/src/pages/landing-hero/HeroSliderPage.tsx index d071f13..d67efc8 100644 --- a/src/pages/landing-hero/HeroSliderPage.tsx +++ b/src/pages/landing-hero/HeroSliderPage.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useForm, useFieldArray } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; @@ -10,6 +10,7 @@ import { LandingHeroData, HeroImage } from "./core/_models"; import { LoadingSpinner } from "@/components/ui/LoadingSpinner"; import { PlusCircle, Trash2, Save } from "lucide-react"; import { useFileUpload, useFileDelete } from "@/hooks/useFileUpload"; +import { Modal } from "@/components/ui/Modal"; const heroImageSchema = yup.object({ alt_text: yup.string().required("متن ALT الزامی است"), @@ -28,6 +29,7 @@ const landingHeroSchema = yup.object({ export const HeroSliderPage = () => { const { data, isLoading } = useLandingHero(); const { mutate: updateHero, isPending: isSaving } = useUpdateLandingHero(); + const [preview, setPreview] = useState<{ url: string; alt: string } | null>(null); const { control, @@ -35,6 +37,7 @@ export const HeroSliderPage = () => { formState: { errors, isDirty, isValid }, reset, setValue, + watch, } = useForm({ resolver: yupResolver(landingHeroSchema) as any, mode: "onChange", @@ -97,35 +100,55 @@ export const HeroSliderPage = () => { return (
-

مدیریت اسلایدر صفحه اصلی

+

مدیریت اسلایدر صفحه اصلی

{/* Main slide */}
-

اسلاید اصلی

+

اسلاید اصلی

- + {watch("main.url") && ( +
+ {watch("main.alt_text") setPreview({ url: watch("main.url") as string, alt: (watch("main.alt_text") as string) || "" })} + /> + +
+ )} + + {!watch("main.url") && ( + + )}
{/* Side slides */}
-

اسلایدهای جانبی

+

اسلایدهای جانبی

+
+ )} + + {!watch(`side.${index}.url` as const) && ( + + )}
))}
@@ -179,6 +222,11 @@ export const HeroSliderPage = () => { + setPreview(null)} title={preview?.alt || "مشاهده تصویر"}> + {preview && ( + {preview.alt} + )} + ); }; diff --git a/src/pages/landing-hero/core/_requests.ts b/src/pages/landing-hero/core/_requests.ts index da0328b..deccc98 100644 --- a/src/pages/landing-hero/core/_requests.ts +++ b/src/pages/landing-hero/core/_requests.ts @@ -11,10 +11,14 @@ import { } from "./_models"; export const getLandingHero = async () => { - const response = await httpGetRequest( + const response = await httpGetRequest( APIUrlGenerator(API_ROUTES.GET_LANDING_HERO) ); - return response.data.data; + const root = response.data; + const setting = root?.setting ?? root; + const data: LandingHeroData = setting?.data ?? + root?.data ?? { main: { alt_text: "", url: "", thumbnail: "" }, side: [] }; + return data; }; export const updateLandingHero = async (data: LandingHeroData) => { diff --git a/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx b/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx index 57af3da..ba5d45e 100644 --- a/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx +++ b/src/pages/product-options/product-option-form/ProductOptionFormPage.tsx @@ -15,7 +15,7 @@ import { FormHeader, PageContainer, SectionTitle, Label } from '../../../compone const maintenanceSchema = yup.object({ title: yup.string().required('عنوان نگهداری الزامی است'), - description: yup.string().required('توضیحات نگهداری الزامی است'), + description: yup.string(), content: yup.string().required('محتوای نگهداری الزامی است'), image: yup.string().required('تصویر نگهداری الزامی است'), }); @@ -28,7 +28,7 @@ const optionSchema = yup.object({ const productOptionSchema = yup.object({ title: yup.string().required('عنوان الزامی است').min(2, 'عنوان باید حداقل 2 کاراکتر باشد'), - description: yup.string().required('توضیحات الزامی است'), + description: yup.string(), maintenance: maintenanceSchema.required('اطلاعات نگهداری الزامی است'), options: yup.array().of(optionSchema).min(1, 'حداقل یک گزینه باید وارد شود').required('گزینه‌ها الزامی است'), }); diff --git a/src/pages/products/core/_requests.ts b/src/pages/products/core/_requests.ts index ccc3d86..71f3a14 100644 --- a/src/pages/products/core/_requests.ts +++ b/src/pages/products/core/_requests.ts @@ -49,8 +49,28 @@ export const getProducts = async (filters?: ProductFilters) => { response.data.products && Array.isArray(response.data.products) ) { + // Normalize products for UI consumption + const normalizedProducts = response.data.products.map((p: any) => { + // Derive price from first variant if direct price is absent + const firstVariant = (p.product_variants || p.variants || [])[0] || {}; + const price = p.price ?? firstVariant.price_amount ?? 0; + + // Determine primary category + const primaryCategory = (p.product_categories || p.categories || [])[0]; + + // Map enabled boolean to status string expected by UI components + const status = p.status ?? (p.enabled ? "active" : "inactive"); + + return { + ...p, + price, + category: primaryCategory, + status, + }; + }); + return { - products: response.data.products, + products: normalizedProducts, total: response.data.total, page: response.data.page, per_page: response.data.per_page,