feat: upgrade pricing admin with popular/featured selects and price input with BYN badge
Replace per-item toggles with top-level dropdown selects for popular and featured items. Add PriceField component with inline gold BYN suffix badge. Public Pricing component now uses dynamic popular/featured flags from data. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import { SectionEditor } from "../_components/SectionEditor";
|
||||
import { InputField } from "../_components/FormField";
|
||||
import { InputField, SelectField } from "../_components/FormField";
|
||||
import { ArrayEditor } from "../_components/ArrayEditor";
|
||||
|
||||
interface PricingItem {
|
||||
name: string;
|
||||
price: string;
|
||||
note?: string;
|
||||
popular?: boolean;
|
||||
featured?: boolean;
|
||||
}
|
||||
|
||||
interface PricingData {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
items: { name: string; price: string; note?: string }[];
|
||||
items: PricingItem[];
|
||||
rentalTitle: string;
|
||||
rentalItems: { name: string; price: string; note?: string }[];
|
||||
rules: string[];
|
||||
}
|
||||
|
||||
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 (
|
||||
<div>
|
||||
<label className="block text-sm text-neutral-400 mb-1.5">{label}</label>
|
||||
<div className="flex rounded-lg border border-white/10 bg-neutral-800 focus-within:border-gold transition-colors">
|
||||
<input
|
||||
type="text"
|
||||
value={raw}
|
||||
onChange={(e) => {
|
||||
const v = e.target.value;
|
||||
onChange(v ? `${v} BYN` : "");
|
||||
}}
|
||||
placeholder="0"
|
||||
className="flex-1 bg-transparent px-4 py-2.5 text-white placeholder-neutral-500 outline-none min-w-0"
|
||||
/>
|
||||
<span className="flex items-center pr-4 text-sm font-medium text-gold select-none">
|
||||
BYN
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PricingEditorPage() {
|
||||
return (
|
||||
<SectionEditor<PricingData> sectionKey="pricing" title="Цены">
|
||||
@@ -29,6 +63,48 @@ export default function PricingEditorPage() {
|
||||
onChange={(v) => update({ ...data, subtitle: v })}
|
||||
/>
|
||||
|
||||
{/* Popular & Featured selectors */}
|
||||
{(() => {
|
||||
const itemOptions = data.items
|
||||
.map((it, idx) => ({ value: String(idx), label: it.name }))
|
||||
.filter((o) => o.label.trim() !== "");
|
||||
const noneOption = { value: "", label: "— Нет —" };
|
||||
|
||||
const popularIdx = data.items.findIndex((it) => it.popular);
|
||||
const featuredIdx = data.items.findIndex((it) => it.featured);
|
||||
|
||||
return (
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<SelectField
|
||||
label="Популярный абонемент"
|
||||
value={popularIdx >= 0 ? String(popularIdx) : ""}
|
||||
onChange={(v) => {
|
||||
const items = data.items.map((it, idx) => ({
|
||||
...it,
|
||||
popular: v ? idx === Number(v) : false,
|
||||
}));
|
||||
update({ ...data, items });
|
||||
}}
|
||||
options={[noneOption, ...itemOptions]}
|
||||
placeholder="Выберите..."
|
||||
/>
|
||||
<SelectField
|
||||
label="Выделенный абонемент (безлимит)"
|
||||
value={featuredIdx >= 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="Выберите..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<ArrayEditor
|
||||
label="Абонементы"
|
||||
items={data.items}
|
||||
@@ -40,7 +116,7 @@ export default function PricingEditorPage() {
|
||||
value={item.name}
|
||||
onChange={(v) => updateItem({ ...item, name: v })}
|
||||
/>
|
||||
<InputField
|
||||
<PriceField
|
||||
label="Цена"
|
||||
value={item.price}
|
||||
onChange={(v) => updateItem({ ...item, price: v })}
|
||||
@@ -73,7 +149,7 @@ export default function PricingEditorPage() {
|
||||
value={item.name}
|
||||
onChange={(v) => updateItem({ ...item, name: v })}
|
||||
/>
|
||||
<InputField
|
||||
<PriceField
|
||||
label="Цена"
|
||||
value={item.price}
|
||||
onChange={(v) => updateItem({ ...item, price: v })}
|
||||
|
||||
Reference in New Issue
Block a user