feat: discount toggle flag, hide price from success popup

- Admin: "Добавить скидку" toggle — OFF hides discount fields and sets to 0
- Public: discount line hidden when discountPrice=0
- Success popup: removed price/booking count info
This commit is contained in:
2026-03-24 23:07:06 +03:00
parent eb6ec5aeb6
commit d0fad4aae5
3 changed files with 57 additions and 41 deletions

View File

@@ -2,7 +2,7 @@
import { useState, useEffect, useMemo, useCallback } from "react"; import { useState, useEffect, useMemo, useCallback } from "react";
import { import {
Plus, X, Loader2, Calendar, Trash2, Ban, CheckCircle2, RotateCcw, Plus, X, Loader2, Calendar, Trash2, Ban, CheckCircle2, RotateCcw, Sparkles,
} from "lucide-react"; } from "lucide-react";
import { adminFetch } from "@/lib/csrf"; import { adminFetch } from "@/lib/csrf";
import { ParticipantLimits } from "../_components/FormField"; import { ParticipantLimits } from "../_components/FormField";
@@ -100,34 +100,55 @@ function EventSettings({
/> />
</div> </div>
<div className="grid gap-4 sm:grid-cols-3"> <div>
<div> <label className="block text-sm text-neutral-400 mb-1.5">Цена за занятие (BYN)</label>
<label className="block text-sm text-neutral-400 mb-1.5">Цена за занятие (BYN)</label> <input
<input type="number"
type="number" value={event.pricePerClass}
value={event.pricePerClass} onChange={(e) => onChange({ pricePerClass: parseInt(e.target.value) || 0 })}
onChange={(e) => onChange({ pricePerClass: parseInt(e.target.value) || 0 })} className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors sm:max-w-xs"
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors" />
/> </div>
</div>
<div> {/* Discount toggle + fields */}
<label className="block text-sm text-neutral-400 mb-1.5">Цена со скидкой (BYN)</label> <div>
<input <button
type="number" type="button"
value={event.discountPrice} onClick={() => {
onChange={(e) => onChange({ discountPrice: parseInt(e.target.value) || 0 })} if (event.discountPrice > 0) onChange({ discountPrice: 0, discountThreshold: 0 });
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors" else onChange({ discountPrice: event.pricePerClass - 5, discountThreshold: 3 });
/> }}
</div> className={`flex items-center gap-2 rounded-full px-4 py-2 text-sm font-medium transition-all ${
<div> event.discountPrice > 0
<label className="block text-sm text-neutral-400 mb-1.5">От N занятий</label> ? "bg-gold/15 text-gold border border-gold/30"
<input : "bg-neutral-800 text-neutral-400 border border-white/10 hover:text-white"
type="number" }`}
value={event.discountThreshold} >
onChange={(e) => onChange({ discountThreshold: parseInt(e.target.value) || 1 })} <Sparkles size={14} />
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors" {event.discountPrice > 0 ? "Скидка включена" : "Добавить скидку"}
/> </button>
</div> {event.discountPrice > 0 && (
<div className="grid gap-4 sm:grid-cols-2 mt-3">
<div>
<label className="block text-sm text-neutral-400 mb-1.5">Цена со скидкой (BYN)</label>
<input
type="number"
value={event.discountPrice}
onChange={(e) => onChange({ discountPrice: parseInt(e.target.value) || 0 })}
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors"
/>
</div>
<div>
<label className="block text-sm text-neutral-400 mb-1.5">От N занятий</label>
<input
type="number"
value={event.discountThreshold}
onChange={(e) => onChange({ discountThreshold: parseInt(e.target.value) || 1 })}
className="w-full rounded-lg border border-white/10 bg-neutral-800 px-4 py-2.5 text-white outline-none focus:border-gold transition-colors"
/>
</div>
</div>
)}
</div> </div>
<ParticipantLimits <ParticipantLimits
@@ -151,7 +172,7 @@ function EventSettings({
{event.active ? "Опубликовано" : "Черновик"} {event.active ? "Опубликовано" : "Черновик"}
</button> </button>
<span className="text-xs text-neutral-500"> <span className="text-xs text-neutral-500">
{event.pricePerClass} BYN / занятие, от {event.discountThreshold} {event.discountPrice} BYN {event.pricePerClass} BYN / занятие{event.discountPrice > 0 && event.discountThreshold > 0 && `, от ${event.discountThreshold}${event.discountPrice} BYN`}
</span> </span>
</div> </div>
</div> </div>

View File

@@ -67,10 +67,12 @@ export function OpenDay({ data }: OpenDayProps) {
<p className="text-lg font-semibold text-white"> <p className="text-lg font-semibold text-white">
{event.pricePerClass} BYN <span className="text-neutral-400 font-normal text-sm">за занятие</span> {event.pricePerClass} BYN <span className="text-neutral-400 font-normal text-sm">за занятие</span>
</p> </p>
<p className="text-sm text-gold"> {event.discountPrice > 0 && event.discountThreshold > 0 && (
<Sparkles size={12} className="inline mr-1" /> <p className="text-sm text-gold">
От {event.discountThreshold} занятий {event.discountPrice} BYN за каждое! <Sparkles size={12} className="inline mr-1" />
</p> От {event.discountThreshold} занятий {event.discountPrice} BYN за каждое!
</p>
)}
</div> </div>
</Reveal> </Reveal>

View File

@@ -178,13 +178,6 @@ export function SignupModal({
{successMessage || "Вы записаны!"} {successMessage || "Вы записаны!"}
</h3> </h3>
{subtitle && <p className="mt-1 text-sm text-neutral-400">{subtitle}</p>} {subtitle && <p className="mt-1 text-sm text-neutral-400">{subtitle}</p>}
{successData?.totalBookings !== undefined && (
<p className="mt-3 text-sm text-white">
Вы записаны на <span className="text-gold font-semibold">{String(successData.totalBookings)}</span> занятий.
<br />
Стоимость: <span className="text-gold font-semibold">{String(successData.pricePerClass)} BYN</span> за занятие
</p>
)}
</> </>
)} )}
<button <button