feat: Wabenhain Honig-Shop Anwendung
Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei: Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich (Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung, PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma- Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
This commit is contained in:
1 parent
5c76fcc266
commit
c7927f2883
240 files changed
+26096
-137
No files matched your search
@@ -0,0 +1,49 @@
|
||||
import type { Metadata } from "next";
|
||||
import { getCurrentCustomer } from "@/lib/auth";
|
||||
import { getAddressesForCustomer } from "@/lib/account-data";
|
||||
import { getShippingTiers } from "@/lib/shipping";
|
||||
import { getBulkDiscountTiers } from "@/lib/bulk-discount";
|
||||
import { getLocale } from "@/i18n/locale";
|
||||
import { getDictionary } from "@/i18n/get-dictionary";
|
||||
import { CheckoutForm, type CheckoutInitialValues } from "./checkout-form";
|
||||
|
||||
// Vorausfuellen aus Kundendaten aendert sich pro Nutzer/Anmeldestatus, und
|
||||
// Versandstaffeln koennen sich im Admin-Bereich jederzeit aendern —
|
||||
// Rendering pro Request statt statischem Build entkoppelt zudem den
|
||||
// Docker-Build-Schritt von einer zur Build-Zeit erreichbaren Datenbank.
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function generateMetadata(): Promise<Metadata> {
|
||||
const t = getDictionary(await getLocale());
|
||||
return { title: t.checkoutPage.eyebrow };
|
||||
}
|
||||
|
||||
export default async function CheckoutPage() {
|
||||
const [tiers, bulkDiscountTiers] = await Promise.all([getShippingTiers(), getBulkDiscountTiers()]);
|
||||
const tierValues = tiers.map((t) => ({
|
||||
minQuantity: t.minQuantity,
|
||||
maxQuantity: t.maxQuantity,
|
||||
priceCents: t.priceCents,
|
||||
}));
|
||||
|
||||
const customer = await getCurrentCustomer();
|
||||
if (!customer) return <CheckoutForm tiers={tierValues} bulkDiscountTiers={bulkDiscountTiers} />;
|
||||
|
||||
// getAddressesForCustomer sortiert Standardadresse (isDefault) zuerst, sonst
|
||||
// die zuletzt angelegte — die erste Adresse in der Liste ist also immer die
|
||||
// sinnvollste Vorbelegung fuer den Checkout.
|
||||
const addresses = await getAddressesForCustomer(customer.id);
|
||||
const defaultAddress = addresses[0];
|
||||
|
||||
const initialValues: CheckoutInitialValues = {
|
||||
firstName: customer.firstName,
|
||||
lastName: customer.lastName,
|
||||
email: customer.email,
|
||||
phone: customer.phone ?? "",
|
||||
street: defaultAddress?.street ?? "",
|
||||
zip: defaultAddress?.zip ?? "",
|
||||
city: defaultAddress?.city ?? "",
|
||||
};
|
||||
|
||||
return <CheckoutForm initialValues={initialValues} tiers={tierValues} bulkDiscountTiers={bulkDiscountTiers} />;
|
||||
}
|
||||
Reference in new issue
Block a user