Rewrite guest confirmation text; add discount and multi-day checkout

Copy button text now matches the exact guest-facing template
requested — "Ваше бронирование подтверждено!", Гость/Номер для
связи/Объект бронирования/Количество гостей/Дополнительные
пожелания/Скидка — dropping the internal-only fields (source, who
booked it) since this text gets pasted straight to the client, not
kept for internal records (those still show on the on-screen summary
card).

New checkOutDate column (nullable — null means same-day, the common
case) lets a booking span multiple days; the Google Calendar link and
copy text both show the date range when set. New discount column
(same shape as prepayment) feeds the new "Скидка" line.

Statistics page gains a money row for the selected month: total
booked, prepayments collected, amount still outstanding, and total
discount given.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gh2UXUQUVBWroWEnn1FLFG
This commit is contained in:
ogrechkoandClaude Sonnet 5 committed 2026-09-13 19:49:21 +00:00
1 parent 4f206c2ddc
commit 006d108f54
15 files changed
+600 -35

No files matched your search

+51 -4
View File
@@ -9,15 +9,43 @@ function formatMonthLabel(monthKey: string): string {
return `${labels[m - 1]} ${y}`;
}
export function StatisticsView({ monthKey, stats }: { monthKey: string; stats: { name: string; count: number }[] }) {
interface MonthlyMoneyStats {
totalCost: number;
totalPrepayment: number;
totalDiscount: number;
totalOutstanding: number;
}
function fmtMoney(n: number): string {
return n.toLocaleString("ru-RU");
}
export function StatisticsView({
monthKey,
stats,
money,
}: {
monthKey: string;
stats: { name: string; count: number }[];
money: MonthlyMoneyStats;
}) {
const router = useRouter();
const pathname = usePathname();
const total = stats.reduce((s, r) => s + r.count, 0);
const max = Math.max(1, ...stats.map((r) => r.count));
const summaryText = [`Статистика по бронированиям на ${formatMonthLabel(monthKey)}:`, "", ...stats.map((r) => `${r.name}: ${r.count}`)].join(
"\n",
);
const summaryText = [
`Статистика по бронированиям на ${formatMonthLabel(monthKey)}:`,
"",
...stats.map((r) => `${r.name}: ${r.count}`),
"",
`Сумма бронирований: ${fmtMoney(money.totalCost)} ₽`,
`Собрано предоплат: ${fmtMoney(money.totalPrepayment)} ₽`,
`Остаток к оплате: ${fmtMoney(money.totalOutstanding)} ₽`,
money.totalDiscount > 0 ? `Скидок дано: ${fmtMoney(money.totalDiscount)} ₽` : null,
]
.filter((l) => l !== null)
.join("\n");
return (
<div className="flex flex-col gap-4">
@@ -32,6 +60,25 @@ export function StatisticsView({ monthKey, stats }: { monthKey: string; stats: {
{stats.length > 0 && <CopyButton text={summaryText} label="Скопировать статистику" size="lg" />}
</div>
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
<div className="card p-3">
<p className="mb-1 text-xs font-medium text-text-muted">Сумма бронирований</p>
<p className="font-mono text-base font-semibold">{fmtMoney(money.totalCost)} ₽</p>
</div>
<div className="card p-3">
<p className="mb-1 text-xs font-medium text-text-muted">Собрано предоплат</p>
<p className="font-mono text-base font-semibold text-success">{fmtMoney(money.totalPrepayment)} ₽</p>
</div>
<div className="card p-3">
<p className="mb-1 text-xs font-medium text-text-muted">Остаток к оплате</p>
<p className="font-mono text-base font-semibold text-danger">{fmtMoney(money.totalOutstanding)} ₽</p>
</div>
<div className="card p-3">
<p className="mb-1 text-xs font-medium text-text-muted">Скидок дано</p>
<p className="font-mono text-base font-semibold">{fmtMoney(money.totalDiscount)} ₽</p>
</div>
</div>
<div className="card p-4">
{stats.length === 0 ? (
<p className="text-sm text-text-muted">За этот месяц бронирований нет.</p>