@funnelsgrove/cli 0.1.231 → 0.1.237
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/cli.js +10 -0
- package/dist/localeContentSource.d.ts +13 -0
- package/dist/localeContentSource.js +117 -0
- package/dist/localeFilePlan.d.ts +4 -0
- package/dist/localeFilePlan.js +63 -0
- package/dist/localeModuleEdits.d.ts +19 -0
- package/dist/localeModuleEdits.js +97 -0
- package/dist/locales.d.ts +6 -0
- package/dist/locales.js +92 -0
- package/funnel-contract-compatibility.json +38 -38
- package/package.json +4 -4
- package/template_docs/.funnelsgrove-docs.json +5 -5
- package/template_docs/AGENTS.md +1 -0
- package/template_docs/docs/funnelsgrove/contracts/content-answers.md +69 -0
- package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
- package/template_docs/funnel-docs.config.json +1 -1
- package/template_scaffold/.funnelsgrove-docs.json +5 -5
- package/template_scaffold/.funnelsgrove-scaffold.json +35 -15
- package/template_scaffold/AGENTS.md +1 -0
- package/template_scaffold/docs/funnelsgrove/contracts/content-answers.md +69 -0
- package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +1 -1
- package/template_scaffold/funnel-docs.config.json +1 -1
- package/template_scaffold/package-lock.json +15 -15
- package/template_scaffold/package.json +3 -3
- package/template_scaffold/src/app/subscription-dashboard/page.tsx +22 -19
- package/template_scaffold/src/components/FunnelFlow.tsx +11 -5
- package/template_scaffold/src/components/paywall/PaywallRenewalDisclaimer.tsx +23 -0
- package/template_scaffold/src/components/paywall/localize-paywall-plan-labels.ts +15 -0
- package/template_scaffold/src/config/billing.plans.ts +11 -10
- package/template_scaffold/src/config/billing.test.plans.ts +11 -10
- package/template_scaffold/src/steps/content/runtime.content.ts +22 -0
- package/template_scaffold/src/steps/content/step-32-paywall.content.ts +41 -1
- package/template_scaffold/src/steps/content/subscription-dashboard.content.ts +54 -0
- package/template_scaffold/src/steps/step-32-paywall.tsx +12 -22
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { LocalizedStepContent } from '@funnelsgrove/runtime';
|
|
2
|
+
|
|
3
|
+
export type SubscriptionDashboardContent = {
|
|
4
|
+
brand: string;
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
loading: string;
|
|
8
|
+
userId: string;
|
|
9
|
+
email: string;
|
|
10
|
+
status: string;
|
|
11
|
+
events: string;
|
|
12
|
+
notProvided: string;
|
|
13
|
+
unknown: string;
|
|
14
|
+
empty: string;
|
|
15
|
+
cancelAtEnd: string;
|
|
16
|
+
autoRenew: string;
|
|
17
|
+
periodEnds: string;
|
|
18
|
+
updating: string;
|
|
19
|
+
renew: string;
|
|
20
|
+
cancel: string;
|
|
21
|
+
refresh: string;
|
|
22
|
+
loadError: string;
|
|
23
|
+
cancelError: string;
|
|
24
|
+
renewError: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const subscriptionDashboardContent = {
|
|
28
|
+
defaultLocale: 'en',
|
|
29
|
+
locales: {
|
|
30
|
+
en: {
|
|
31
|
+
"brand": "App Deals",
|
|
32
|
+
"title": "Manage Subscription",
|
|
33
|
+
"description": "View active plans and manage cancellation or renewal.",
|
|
34
|
+
"loading": "Loading subscription data...",
|
|
35
|
+
"userId": "User ID:",
|
|
36
|
+
"email": "Email:",
|
|
37
|
+
"status": "Status:",
|
|
38
|
+
"events": "Tracked events:",
|
|
39
|
+
"notProvided": "Not provided",
|
|
40
|
+
"unknown": "unknown",
|
|
41
|
+
"empty": "No subscriptions found for this user.",
|
|
42
|
+
"cancelAtEnd": "Will cancel at period end",
|
|
43
|
+
"autoRenew": "Auto-renew is active",
|
|
44
|
+
"periodEnds": "Current period ends:",
|
|
45
|
+
"updating": "Updating...",
|
|
46
|
+
"renew": "Renew",
|
|
47
|
+
"cancel": "Cancel",
|
|
48
|
+
"refresh": "Refresh",
|
|
49
|
+
"loadError": "Failed to load subscriptions",
|
|
50
|
+
"cancelError": "Failed to cancel subscription",
|
|
51
|
+
"renewError": "Failed to renew subscription"
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
} as const satisfies LocalizedStepContent<SubscriptionDashboardContent>;
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState, type FormEvent } from 'react';
|
|
4
4
|
import Image from 'next/image';
|
|
5
|
+
import { localizePaywallPlanLabels } from '@/components/paywall/localize-paywall-plan-labels';
|
|
6
|
+
import { PaywallRenewalDisclaimer } from '@/components/paywall/PaywallRenewalDisclaimer';
|
|
5
7
|
import { checkoutRuntimeConfig } from '@/runtime/checkout-runtime-config';
|
|
6
8
|
import {
|
|
7
9
|
billingDiscountStorageKeys,
|
|
@@ -33,7 +35,6 @@ import {
|
|
|
33
35
|
advancePaywallDiscountState,
|
|
34
36
|
buildBillingDiscountCatalog,
|
|
35
37
|
buildDiscountedPaywallPlans,
|
|
36
|
-
buildPaywallRenewalDisclaimer,
|
|
37
38
|
getDefaultPlanId,
|
|
38
39
|
getPaywallPromoDisplayName,
|
|
39
40
|
resolvePaywallDiscountState,
|
|
@@ -226,8 +227,8 @@ function StepPaywallRuntime({
|
|
|
226
227
|
plans: availablePlans,
|
|
227
228
|
couponId: activeCouponId,
|
|
228
229
|
discountPercent: discountState.discountPercent,
|
|
229
|
-
}),
|
|
230
|
-
[activeCouponId, availablePlans, discountState.discountPercent],
|
|
230
|
+
}).map((plan) => localizePaywallPlanLabels(plan, content.catalogLabels)),
|
|
231
|
+
[activeCouponId, availablePlans, discountState.discountPercent, content.catalogLabels],
|
|
231
232
|
);
|
|
232
233
|
const selectedPlan = useMemo(() => {
|
|
233
234
|
if (availablePlans.length === 0) {
|
|
@@ -252,7 +253,7 @@ function StepPaywallRuntime({
|
|
|
252
253
|
return displayPlans.find((plan) => plan.id === selectedPlanId) ?? displayPlans[0];
|
|
253
254
|
}, [displayPlans, initialPlanId, selectedPlanId]);
|
|
254
255
|
const checkoutSummaryLabel =
|
|
255
|
-
selectedDisplayPlan?.checkoutSummaryLabel?.trim() || selectedDisplayPlan?.title ||
|
|
256
|
+
selectedDisplayPlan?.checkoutSummaryLabel?.trim() || selectedDisplayPlan?.title || content.selectedPlanLabel;
|
|
256
257
|
const checkoutProvider = activeBillingRuntime.provider;
|
|
257
258
|
const storyOptions = useMemo<readonly StoryOption[]>(
|
|
258
259
|
() =>
|
|
@@ -286,17 +287,6 @@ function StepPaywallRuntime({
|
|
|
286
287
|
|
|
287
288
|
return getPaywallPromoDisplayName(activeDiscountStartedAtMs);
|
|
288
289
|
}, [activeDiscountStartedAtMs, discountState.status]);
|
|
289
|
-
const paymentDisclaimer = useMemo(() => {
|
|
290
|
-
if (!selectedPlan) {
|
|
291
|
-
return '';
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return buildPaywallRenewalDisclaimer({
|
|
295
|
-
plan: selectedPlan,
|
|
296
|
-
hasActiveDiscount: Boolean(activeCouponId),
|
|
297
|
-
productName: 'the app',
|
|
298
|
-
});
|
|
299
|
-
}, [activeCouponId, selectedPlan]);
|
|
300
290
|
const appliedDiscountAmountCents = useMemo(() => {
|
|
301
291
|
if (!selectedDisplayPlan) {
|
|
302
292
|
return 0;
|
|
@@ -934,7 +924,7 @@ function StepPaywallRuntime({
|
|
|
934
924
|
<div className='paywall-v2-top-controls'>
|
|
935
925
|
<div
|
|
936
926
|
className='paywall-v2-countdown'
|
|
937
|
-
aria-label={
|
|
927
|
+
aria-label={content.countdownAriaTemplate.replace('{minutes}', String(minutes).padStart(2, '0')).replace('{seconds}', String(seconds).padStart(2, '0'))}
|
|
938
928
|
>
|
|
939
929
|
<p className='paywall-v2-countdown-value'>
|
|
940
930
|
<span className='paywall-v2-countdown-segment'>
|
|
@@ -1011,7 +1001,7 @@ function StepPaywallRuntime({
|
|
|
1011
1001
|
</span>
|
|
1012
1002
|
) : null}
|
|
1013
1003
|
<span className='paywall-v2-promo-upgrade-badge-main'>
|
|
1014
|
-
{discountState.discountPercent}
|
|
1004
|
+
{content.checkout.discountLabelTemplate.replace('{percent}', String(discountState.discountPercent))}
|
|
1015
1005
|
</span>
|
|
1016
1006
|
</div>
|
|
1017
1007
|
<p className='paywall-v2-promo-upgrade-label'>{content.promo.upgradedLabel}</p>
|
|
@@ -1041,7 +1031,7 @@ function StepPaywallRuntime({
|
|
|
1041
1031
|
<p className='paywall-v2-highlight-copy'>{content.highlight.description}</p>
|
|
1042
1032
|
</section>
|
|
1043
1033
|
|
|
1044
|
-
<section id='paywall-v2-plans' className='paywall-v2-plan-list' aria-label=
|
|
1034
|
+
<section id='paywall-v2-plans' className='paywall-v2-plan-list' aria-label={content.plans.title}>
|
|
1045
1035
|
<h2 className='paywall-v2-title'>{content.plans.title}</h2>
|
|
1046
1036
|
|
|
1047
1037
|
{displayPlans.map((plan) => (
|
|
@@ -1089,7 +1079,7 @@ function StepPaywallRuntime({
|
|
|
1089
1079
|
) : null}
|
|
1090
1080
|
<span className='paywall-v2-plan-per-day-amount'>{plan.perDayAmount}</span>
|
|
1091
1081
|
</p>
|
|
1092
|
-
<p className='paywall-v2-plan-per-day-label'>{
|
|
1082
|
+
<p className='paywall-v2-plan-per-day-label'>{content.plans.perDayLabel}</p>
|
|
1093
1083
|
</div>
|
|
1094
1084
|
</div>
|
|
1095
1085
|
</div>
|
|
@@ -1130,7 +1120,7 @@ function StepPaywallRuntime({
|
|
|
1130
1120
|
{content.plans.cardButtonLabel}
|
|
1131
1121
|
</button>
|
|
1132
1122
|
<p className='paywall-v2-alt-meta'>{content.plans.metaLabels.join(' · ')}</p>
|
|
1133
|
-
<
|
|
1123
|
+
<PaywallRenewalDisclaimer plan={selectedPlan} hasActiveDiscount={Boolean(activeCouponId)} copy={content.checkout} catalogLabels={content.catalogLabels} />
|
|
1134
1124
|
<p className='paywall-v2-support'>
|
|
1135
1125
|
{content.checkout.supportText}{' '}
|
|
1136
1126
|
<a href={`mailto:${supportEmail}`}>{supportEmail}</a>
|
|
@@ -1226,9 +1216,9 @@ function StepPaywallRuntime({
|
|
|
1226
1216
|
<p className='paywall-v2-guarantee-text'>
|
|
1227
1217
|
{content.guarantee.description}{' '}
|
|
1228
1218
|
<a href={content.guarantee.links[0]?.href || '/refund-policy'}>
|
|
1229
|
-
{content.guarantee.links[0]?.label ||
|
|
1219
|
+
{content.guarantee.links[0]?.label || content.refundPolicyLabel}
|
|
1230
1220
|
</a>{' '}
|
|
1231
|
-
|
|
1221
|
+
{content.guarantee.detailsSuffix}
|
|
1232
1222
|
</p>
|
|
1233
1223
|
</div>
|
|
1234
1224
|
</section>
|