in apps/payments/next/app/[locale]/[offeringId]/[interval]/checkout/[cartId]/layout.tsx [34:172]
export default async function CheckoutLayout({
children,
params,
}: {
children: React.ReactNode;
params: CheckoutParams;
}) {
const { locale } = params;
const acceptLanguage = headers().get('accept-language');
const cmsDataPromise = fetchCMSData(
params.offeringId,
acceptLanguage,
locale
);
const cartDataPromise = getCartAction(params.cartId);
const sessionPromise = auth();
const l10n = getApp().getL10n(acceptLanguage, locale);
const [cms, cart, session] = await Promise.all([
cmsDataPromise,
cartDataPromise,
sessionPromise,
]);
const purchaseDetails =
cms.defaultPurchase.purchaseDetails.localizations.at(0) ||
cms.defaultPurchase.purchaseDetails;
return (
<MetricsWrapper cart={cart}>
<Header
auth={{
user: session?.user,
signOut: async () => {
'use server';
await signOut({ redirect: false });
},
}}
cart={cart}
/>
{session?.user?.email && (
<div className="mb-8 tablet:hidden">
<SignedIn email={session.user.email} />
</div>
)}
<div className="mx-7 tablet:grid tablet:grid-cols-[minmax(min-content,500px)_minmax(20rem,1fr)] tablet:grid-rows-[min-content] tablet:gap-x-8 tablet:mb-auto desktop:grid-cols-[600px_1fr]">
<SubscriptionTitle cart={cart} l10n={l10n} />
<section
className="mb-6 tablet:mt-6 tablet:min-w-[18rem] tablet:max-w-xs tablet:col-start-2 tablet:col-end-auto tablet:row-start-1 tablet:row-end-3"
aria-label="Purchase details"
>
<PurchaseDetails
invoice={cart.upcomingInvoicePreview}
purchaseDetails={purchaseDetails}
priceInterval={
<PriceInterval
l10n={l10n}
amount={cart.upcomingInvoicePreview.listAmount}
currency={cart.upcomingInvoicePreview.currency}
interval={cart.interval}
/>
}
totalPrice={
<PriceInterval
l10n={l10n}
amount={cart.upcomingInvoicePreview.totalAmount}
currency={cart.upcomingInvoicePreview.currency}
interval={cart.interval}
/>
}
/>
{cart.state === CartState.START && (
<div
className="bg-white rounded-b-lg shadow-sm shadow-grey-300 mt-6 p-4 rounded-t-lg text-base tablet:my-8"
aria-label="Tax location form"
>
<h2 className="m-0 mb-4 font-semibold text-grey-600">
{l10n.getString('select-tax-location-title', 'Location')}
</h2>
<SelectTaxLocation
saveAction={async (countryCode, postalCode) => {
'use server';
const result = await updateTaxAddressAction(
cart.id,
cart.version,
params.offeringId,
{
countryCode,
postalCode,
},
session?.user?.id
);
if (result.ok) {
return {
ok: true,
data: result.taxAddress,
};
} else {
return {
ok: false,
error: result.error,
};
}
}}
cmsCountries={cms.countries}
locale={locale.substring(0, 2)}
productName={purchaseDetails.productName}
unsupportedLocations={
config.location.subscriptionsUnsupportedLocations
}
countryCode={cart.taxAddress?.countryCode}
postalCode={cart.taxAddress?.postalCode}
currentCurrency={cart.currency}
showNewTaxRateInfoMessage={cart.hasActiveSubscriptions}
/>
</div>
)}
<CouponForm
cartId={cart.id}
cartVersion={cart.version}
promoCode={cart.couponCode}
readOnly={cart.state === CartState.START ? false : true}
/>
</section>
<div className="bg-white rounded-b-lg shadow-sm shadow-grey-300 border-t-0 mb-6 pt-4 px-4 pb-14 rounded-t-lg text-grey-600 tablet:clip-shadow tablet:rounded-t-none desktop:px-12 desktop:pb-12">
{children}
<TermsAndPrivacy
l10n={l10n}
{...cart}
{...purchaseDetails}
{...(cms.commonContent.localizations.at(0) || cms.commonContent)}
contentServerUrl={config.contentServerUrl}
showFXALinks={true}
/>
</div>
</div>
</MetricsWrapper>
);
}