trial choice

This commit is contained in:
dev.daminik00 2025-10-23 02:20:09 +02:00
parent c7d6f049b0
commit aa683cc574
3 changed files with 60 additions and 6 deletions

View File

@ -6,6 +6,8 @@ import {
PaymentPlacementProvider,
TrialVariantSelectionProvider,
} from "../src/entities/session/payment";
import type { IFunnelPaymentPlacement } from "../src/entities/session/funnel/types";
import { Currency } from "../src/shared/types";
const geistSans = Geist({
variable: "--font-geist-sans",
@ -35,6 +37,24 @@ const poppins = Poppins({
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
});
// Storybook mock placement to avoid network calls
const storybookPlacement: IFunnelPaymentPlacement = {
currency: Currency.USD,
billingPeriod: "WEEK",
billingInterval: 1,
trialPeriod: "DAY",
trialInterval: 7,
placementId: "plc_story",
paywallId: "pw_story",
paymentUrl: "https://example.com/pay",
variants: [
{ id: "v1", key: "basic", type: "subscription", price: 1499, trialPrice: 100, title: "Basic" },
{ id: "v2", key: "standard", type: "subscription", price: 1499, trialPrice: 499, title: "Standard" },
{ id: "v3", key: "popular", type: "subscription", price: 1499, trialPrice: 899, title: "Popular", accent: true },
{ id: "v4", key: "premium", type: "subscription", price: 1499, trialPrice: 1367, title: "Premium" },
],
};
const preview: Preview = {
parameters: {
controls: {
@ -62,7 +82,11 @@ const preview: Preview = {
},
decorators: [
(Story) => (
<PaymentPlacementProvider>
<PaymentPlacementProvider
initialCache={[
{ funnelKey: "storybook-funnel", paymentId: "main", placement: storybookPlacement },
]}
>
<TrialVariantSelectionProvider>
<div
className={`${geistSans.variable} ${geistMono.variable} ${manrope.variable} ${inter.variable} ${poppins.variable} flex items-center justify-center size-full max-w-[560px] min-w-xs mx-auto antialiased`}

View File

@ -22,15 +22,28 @@ const PaymentPlacementContext = createContext<PaymentPlacementContextValue | nul
null
);
type PreloadedPlacement = {
funnelKey: string;
paymentId: string;
placement: IFunnelPaymentPlacement;
};
export function PaymentPlacementProvider({
children,
initialCache,
}: {
children: React.ReactNode;
initialCache?: PreloadedPlacement[];
}) {
// Cache: Map<"funnelKey:paymentId", PlacementCacheEntry>
const [cache, setCache] = useState<Map<string, PlacementCacheEntry>>(
new Map()
);
const [cache, setCache] = useState<Map<string, PlacementCacheEntry>>(() => {
const map = new Map<string, PlacementCacheEntry>();
initialCache?.forEach(({ funnelKey, paymentId, placement }) => {
const key = `${funnelKey}:${paymentId}`;
map.set(key, { placement, isLoading: false, error: null });
});
return map;
});
const getCacheKey = (funnelKey: string, paymentId: string) =>
`${funnelKey}:${paymentId}`;

View File

@ -8,8 +8,25 @@ export const useClientToken = () => {
useEffect(() => {
(async () => {
const token = await getAuthTokenFromCookie();
setToken(token);
try {
const token = await getAuthTokenFromCookie();
// If server returned undefined, fall back to a stable mock in Storybook
if (!token && typeof window !== "undefined") {
const w = window as Window & { __STORYBOOK_ADDONS?: unknown };
const isStorybook = Boolean(w.__STORYBOOK_ADDONS) ||
/:\/\/.*(:6006|storybook)/i.test(w.location.href);
setToken(isStorybook ? "storybook-token" : undefined);
} else {
setToken(token);
}
} catch {
// In Storybook or non-Next runtime, server action may fail; use mock token
if (typeof window !== "undefined") {
setToken("storybook-token");
} else {
setToken(undefined);
}
}
})();
}, []);