From 95c33391e5b3e807589a087b24b862e202aece0e Mon Sep 17 00:00:00 2001 From: "diana.dolgolyova" Date: Thu, 26 Mar 2026 00:48:00 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20pricing=20admin=20=E2=80=94=20collapsib?= =?UTF-8?q?le=20sections,=20card=20collapse,=20remove=20contact=20toggle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/admin/pricing/page.tsx | 327 +++++++++++++++++++-------------- 1 file changed, 188 insertions(+), 139 deletions(-) diff --git a/src/app/admin/pricing/page.tsx b/src/app/admin/pricing/page.tsx index c6ca414..6be3a39 100644 --- a/src/app/admin/pricing/page.tsx +++ b/src/app/admin/pricing/page.tsx @@ -1,5 +1,7 @@ "use client"; +import { useState } from "react"; +import { ChevronDown } from "lucide-react"; import { SectionEditor } from "../_components/SectionEditor"; import { InputField, SelectField } from "../_components/FormField"; import { ArrayEditor } from "../_components/ArrayEditor"; @@ -23,7 +25,6 @@ interface PricingData { } function PriceField({ label, value, onChange }: { label: string; value: string; onChange: (v: string) => void }) { - // Strip "BYN" suffix for editing, add back on save const raw = value.replace(/\s*BYN\s*$/i, "").trim(); return ( @@ -48,157 +49,205 @@ function PriceField({ label, value, onChange }: { label: string; value: string; ); } +function CollapsibleSection({ + title, + count, + defaultOpen = true, + children, +}: { + title: string; + count?: number; + defaultOpen?: boolean; + children: React.ReactNode; +}) { + const [open, setOpen] = useState(defaultOpen); + + return ( +
+ +
+
+
+ {children} +
+
+
+
+ ); +} + export default function PricingEditorPage() { return ( sectionKey="pricing" title="Цены"> {(data, update) => ( - <> - update({ ...data, title: v })} - /> - update({ ...data, subtitle: v })} - /> +
+
+ update({ ...data, title: v })} + /> + update({ ...data, subtitle: v })} + /> +
- + {/* Абонементы */} + + {(() => { + const itemOptions = data.items + .map((it, idx) => ({ value: String(idx), label: it.name })) + .filter((o) => o.label.trim() !== ""); + const noneOption = { value: "", label: "— Нет —" }; + const featuredIdx = data.items.findIndex((it) => it.featured); - {/* Featured selector */} - {(() => { - const itemOptions = data.items - .map((it, idx) => ({ value: String(idx), label: it.name })) - .filter((o) => o.label.trim() !== ""); - const noneOption = { value: "", label: "— Нет —" }; - const featuredIdx = data.items.findIndex((it) => it.featured); + return ( + = 0 ? String(featuredIdx) : ""} + onChange={(v) => { + const items = data.items.map((it, idx) => ({ + ...it, + featured: v ? idx === Number(v) : false, + })); + update({ ...data, items }); + }} + options={[noneOption, ...itemOptions]} + placeholder="Выберите..." + /> + ); + })()} - return ( - = 0 ? String(featuredIdx) : ""} - onChange={(v) => { - const items = data.items.map((it, idx) => ({ - ...it, - featured: v ? idx === Number(v) : false, - })); - update({ ...data, items }); - }} - options={[noneOption, ...itemOptions]} - placeholder="Выберите..." - /> - ); - })()} - - update({ ...data, items })} - renderItem={(item, _i, updateItem) => ( -
-
- updateItem({ ...item, name: v })} - /> - updateItem({ ...item, price: v })} - /> + update({ ...data, items })} + collapsible + getItemTitle={(item) => item.name || "Без названия"} + getItemBadge={(item) => + item.popular ? ( + + Популярный + + ) : null + } + renderItem={(item, _i, updateItem) => ( +
+
+ updateItem({ ...item, name: v })} + /> + updateItem({ ...item, price: v })} + /> +
updateItem({ ...item, note: v })} + onChange={(v) => updateItem({ ...item, note: v || undefined })} + placeholder="Например: 8 занятий, срок 30 дней" + /> + +
+ )} + createItem={() => ({ name: "", price: "", note: "" })} + addLabel="Добавить абонемент" + /> + + + {/* Аренда */} + + update({ ...data, rentalTitle: v })} + /> + + update({ ...data, rentalItems })} + collapsible + getItemTitle={(item) => item.name || "Без названия"} + renderItem={(item, _i, updateItem) => ( +
+
+ updateItem({ ...item, name: v })} + /> + updateItem({ ...item, price: v })} + /> +
+ updateItem({ ...item, note: v || undefined })} + placeholder="Например: за 1 час" />
- -
- )} - createItem={() => ({ name: "", price: "", note: "" })} - addLabel="Добавить абонемент" - /> + )} + createItem={() => ({ name: "", price: "", note: "" })} + addLabel="Добавить вариант аренды" + /> + - update({ ...data, rentalTitle: v })} - /> - - update({ ...data, rentalItems })} - renderItem={(item, _i, updateItem) => ( -
- updateItem({ ...item, name: v })} - /> - updateItem({ ...item, price: v })} - /> - updateItem({ ...item, note: v })} - /> -
- )} - createItem={() => ({ name: "", price: "", note: "" })} - addLabel="Добавить вариант аренды" - /> - - update({ ...data, rules })} - renderItem={(rule, _i, updateItem) => ( - - )} - createItem={() => ""} - addLabel="Добавить правило" - /> - + {/* Правила */} + + update({ ...data, rules })} + renderItem={(rule, _i, updateItem) => ( + + )} + createItem={() => ""} + addLabel="Добавить правило" + /> + +
)} );