initial booking
This commit is contained in:
129
src/app/[locale]/booking/[number]/page.tsx
Normal file
129
src/app/[locale]/booking/[number]/page.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import { setRequestLocale, getTranslations } from 'next-intl/server';
|
||||
import { notFound } from 'next/navigation';
|
||||
import { prisma } from '@/lib/prisma';
|
||||
import { Header } from '@/components/Header';
|
||||
import { formatOre } from '@/lib/money';
|
||||
import { Link } from '@/i18n/routing';
|
||||
|
||||
export default async function BookingConfirmedPage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ locale: string; number: string }>;
|
||||
}) {
|
||||
const { locale, number } = await params;
|
||||
setRequestLocale(locale);
|
||||
const t = await getTranslations();
|
||||
|
||||
const booking = await prisma.booking.findUnique({
|
||||
where: { bookingNumber: number },
|
||||
include: { items: true, pickupSlot: true },
|
||||
});
|
||||
if (!booking) notFound();
|
||||
|
||||
const loc = locale as 'sv' | 'en';
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-ink-50">
|
||||
<Header />
|
||||
<main className="mx-auto max-w-3xl px-4 py-8 sm:py-12">
|
||||
<div className="card overflow-hidden">
|
||||
<div className="bg-brand-600 px-6 py-5 text-white">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="h-5 w-5"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20zm4.7-12.3a1 1 0 0 0-1.4-1.4L11 12.6 8.7 10.3a1 1 0 1 0-1.4 1.4l3 3a1 1 0 0 0 1.4 0l5-5z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<span>{t('booking.success.title')}</span>
|
||||
</div>
|
||||
<div className="mt-3 text-2xl font-semibold">
|
||||
{t('booking.success.bookingNumber', { number: booking.bookingNumber })}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-white/80">
|
||||
{t('booking.success.subtitle', { email: booking.email })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6 p-6">
|
||||
<div>
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-ink-500">
|
||||
{t('email.orderSummary')}
|
||||
</h2>
|
||||
<table className="mt-2 w-full text-sm">
|
||||
<tbody className="divide-y divide-ink-100">
|
||||
{booking.items.map((it) => (
|
||||
<tr key={it.id}>
|
||||
<td className="py-2">
|
||||
{loc === 'sv' ? it.nameSv : it.nameEn}
|
||||
<span className="ml-2 text-ink-400">×{it.quantity}</span>
|
||||
</td>
|
||||
<td className="py-2 text-right tabular-nums">
|
||||
{formatOre(it.lineTotalOre, loc)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr className="border-t border-ink-200">
|
||||
<td className="pt-2 text-ink-600">
|
||||
{t('common.subtotal')}
|
||||
</td>
|
||||
<td className="pt-2 text-right tabular-nums">
|
||||
{formatOre(booking.subtotalOre, loc)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="text-ink-500">{t('common.ofWhichVat')}</td>
|
||||
<td className="text-right tabular-nums text-ink-500">
|
||||
{formatOre(booking.vatOre, loc)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="pt-1 font-semibold">{t('common.total')}</td>
|
||||
<td className="pt-1 text-right font-semibold tabular-nums">
|
||||
{formatOre(booking.totalOre, loc)}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{booking.pickupSlot && (
|
||||
<div>
|
||||
<h2 className="text-xs font-medium uppercase tracking-wide text-ink-500">
|
||||
{t('email.pickup')}
|
||||
</h2>
|
||||
<p className="mt-1 text-sm">
|
||||
{loc === 'sv'
|
||||
? booking.pickupSlot.labelSv
|
||||
: booking.pickupSlot.labelEn}{' '}
|
||||
·{' '}
|
||||
{booking.pickupSlot.startsAt.toLocaleString(
|
||||
loc === 'sv' ? 'sv-SE' : 'en-SE',
|
||||
{ dateStyle: 'medium', timeStyle: 'short' },
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="rounded-lg bg-ink-50 p-4 text-sm text-ink-600">
|
||||
{t('email.invoiceInfo')}
|
||||
</div>
|
||||
|
||||
<Link href="/" className="btn-secondary w-full justify-center">
|
||||
{t('booking.success.newOrder')}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user