Updated subscriptions
This commit is contained in:
+6
-3
@@ -29,9 +29,12 @@ STRIPE_PRICE_HOUSEHOLD_CONURE_YEARLY=
|
|||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK=
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK=
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY=
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY=
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY=
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY=
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW=
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY=
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY=
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY=
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY=
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY=
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW=
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY=
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY=
|
||||||
STRIPE_CHECKOUT_SUCCESS_URL=http://localhost:3000/?billing=success
|
STRIPE_CHECKOUT_SUCCESS_URL=http://localhost:3000/?billing=success
|
||||||
STRIPE_CHECKOUT_CANCEL_URL=http://localhost:3000/?billing=cancelled
|
STRIPE_CHECKOUT_CANCEL_URL=http://localhost:3000/?billing=cancelled
|
||||||
STRIPE_PORTAL_RETURN_URL=http://localhost:3000/?billing=portal
|
STRIPE_PORTAL_RETURN_URL=http://localhost:3000/?billing=portal
|
||||||
|
|||||||
@@ -203,8 +203,10 @@ Set these when the Stripe Checkout, Customer Portal, and webhook flow is enabled
|
|||||||
- `STRIPE_PRICE_HOUSEHOLD_CONURE_YEARLY`
|
- `STRIPE_PRICE_HOUSEHOLD_CONURE_YEARLY`
|
||||||
- `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY` or `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK`
|
- `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY` or `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK`
|
||||||
- `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY`
|
- `STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY`
|
||||||
- `STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY` or `STRIPE_PRICE_HOUSEHOLD_MACAW`
|
- `STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY` or `STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY`
|
||||||
- `STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY`
|
- `STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY`
|
||||||
|
- `STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY` or `STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW`
|
||||||
|
- `STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY`
|
||||||
- `STRIPE_CHECKOUT_SUCCESS_URL`
|
- `STRIPE_CHECKOUT_SUCCESS_URL`
|
||||||
- `STRIPE_CHECKOUT_CANCEL_URL`
|
- `STRIPE_CHECKOUT_CANCEL_URL`
|
||||||
- `STRIPE_PORTAL_RETURN_URL`
|
- `STRIPE_PORTAL_RETURN_URL`
|
||||||
@@ -221,7 +223,7 @@ Recommended defaults:
|
|||||||
- Enable the proration behavior you want in the Customer Portal configuration. FlockPal treats Stripe as the source of truth for upgrade timing and proration outcomes.
|
- Enable the proration behavior you want in the Customer Portal configuration. FlockPal treats Stripe as the source of truth for upgrade timing and proration outcomes.
|
||||||
- Point the Stripe webhook endpoint at `https://your-backend-host/api/billing/stripe/webhook`.
|
- Point the Stripe webhook endpoint at `https://your-backend-host/api/billing/stripe/webhook`.
|
||||||
- Subscribe the webhook endpoint to at least `checkout.session.completed`, `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`.
|
- Subscribe the webhook endpoint to at least `checkout.session.completed`, `customer.subscription.created`, `customer.subscription.updated`, and `customer.subscription.deleted`.
|
||||||
- Use one Stripe Price per plan and billing interval. FlockPal maps Stripe price IDs back to `household_basic`, `household_plus`, and `household_macaw`.
|
- Use one Stripe Price per plan and billing interval. FlockPal maps Stripe price IDs back to `household_basic`, `household_plus`, `household_macaw`, and `household_hyacinth_macaw`.
|
||||||
- After Stripe redirects back to the app, FlockPal now performs a direct billing sync against Stripe and then refreshes the active session. Webhooks are still required so asynchronous subscription changes stay in sync later.
|
- After Stripe redirects back to the app, FlockPal now performs a direct billing sync against Stripe and then refreshes the active session. Webhooks are still required so asynchronous subscription changes stay in sync later.
|
||||||
|
|
||||||
For local development with the Stripe CLI:
|
For local development with the Stripe CLI:
|
||||||
|
|||||||
+26
-7
@@ -199,7 +199,7 @@ const switchWorkspaceSchema = z.object({
|
|||||||
|
|
||||||
const workspaceTypeSchema = z.enum(['standard', 'rescue']);
|
const workspaceTypeSchema = z.enum(['standard', 'rescue']);
|
||||||
const workspaceRoleSchema = z.enum(['owner', 'assistant', 'caregiver', 'viewer']);
|
const workspaceRoleSchema = z.enum(['owner', 'assistant', 'caregiver', 'viewer']);
|
||||||
const billingPlanSchema = z.enum(['household_basic', 'household_plus', 'household_macaw']);
|
const billingPlanSchema = z.enum(['household_basic', 'household_plus', 'household_macaw', 'household_hyacinth_macaw']);
|
||||||
const billingIntervalSchema = z.enum(['monthly', 'yearly']);
|
const billingIntervalSchema = z.enum(['monthly', 'yearly']);
|
||||||
const integrationTokenScopeSchema = z.enum(['read_only', 'read_write']);
|
const integrationTokenScopeSchema = z.enum(['read_only', 'read_write']);
|
||||||
const birdGenderSchema = z.enum(['unknown', 'male', 'female']);
|
const birdGenderSchema = z.enum(['unknown', 'male', 'female']);
|
||||||
@@ -383,12 +383,16 @@ const createCodeChallenge = (verifier: string) => crypto.createHash('sha256').up
|
|||||||
|
|
||||||
const resolveBillingPlan = (
|
const resolveBillingPlan = (
|
||||||
workspaceType: WorkspaceType,
|
workspaceType: WorkspaceType,
|
||||||
requestedPlan?: BillingPlan | 'household_basic' | 'household_plus' | 'household_macaw',
|
requestedPlan?: BillingPlan | 'household_basic' | 'household_plus' | 'household_macaw' | 'household_hyacinth_macaw',
|
||||||
) => {
|
) => {
|
||||||
if (workspaceType === 'rescue') {
|
if (workspaceType === 'rescue') {
|
||||||
return 'rescue_free' as const;
|
return 'rescue_free' as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestedPlan === 'household_hyacinth_macaw') {
|
||||||
|
return 'household_hyacinth_macaw';
|
||||||
|
}
|
||||||
|
|
||||||
if (requestedPlan === 'household_macaw') {
|
if (requestedPlan === 'household_macaw') {
|
||||||
return 'household_macaw';
|
return 'household_macaw';
|
||||||
}
|
}
|
||||||
@@ -440,8 +444,18 @@ const stripePriceByBillingPlanAndInterval: Partial<Record<Exclude<BillingPlan, '
|
|||||||
yearly: process.env.STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY?.trim() ?? '',
|
yearly: process.env.STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY?.trim() ?? '',
|
||||||
},
|
},
|
||||||
household_macaw: {
|
household_macaw: {
|
||||||
monthly: process.env.STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY?.trim() || process.env.STRIPE_PRICE_HOUSEHOLD_MACAW?.trim() || '',
|
monthly:
|
||||||
yearly: process.env.STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY?.trim() ?? '',
|
process.env.STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY?.trim() ||
|
||||||
|
process.env.STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY?.trim() ||
|
||||||
|
'',
|
||||||
|
yearly: process.env.STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY?.trim() ?? '',
|
||||||
|
},
|
||||||
|
household_hyacinth_macaw: {
|
||||||
|
monthly:
|
||||||
|
process.env.STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY?.trim() ||
|
||||||
|
process.env.STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW?.trim() ||
|
||||||
|
'',
|
||||||
|
yearly: process.env.STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY?.trim() ?? '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const stripePriceEnvNamesByBillingPlanAndInterval: Record<Exclude<BillingPlan, 'rescue_free'>, Record<BillingInterval, string[]>> = {
|
const stripePriceEnvNamesByBillingPlanAndInterval: Record<Exclude<BillingPlan, 'rescue_free'>, Record<BillingInterval, string[]>> = {
|
||||||
@@ -454,14 +468,19 @@ const stripePriceEnvNamesByBillingPlanAndInterval: Record<Exclude<BillingPlan, '
|
|||||||
yearly: ['STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY'],
|
yearly: ['STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY'],
|
||||||
},
|
},
|
||||||
household_macaw: {
|
household_macaw: {
|
||||||
monthly: ['STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY', 'STRIPE_PRICE_HOUSEHOLD_MACAW'],
|
monthly: ['STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY', 'STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY'],
|
||||||
yearly: ['STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY'],
|
yearly: ['STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY'],
|
||||||
|
},
|
||||||
|
household_hyacinth_macaw: {
|
||||||
|
monthly: ['STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY', 'STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW'],
|
||||||
|
yearly: ['STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const stripePricePlanLabels: Record<Exclude<BillingPlan, 'rescue_free'>, string> = {
|
const stripePricePlanLabels: Record<Exclude<BillingPlan, 'rescue_free'>, string> = {
|
||||||
household_basic: 'Conure',
|
household_basic: 'Conure',
|
||||||
household_plus: 'Indian Ringneck',
|
household_plus: 'Indian Ringneck',
|
||||||
household_macaw: 'Macaw',
|
household_macaw: 'African Grey',
|
||||||
|
household_hyacinth_macaw: 'Hyacinth Macaw',
|
||||||
};
|
};
|
||||||
const stripe = stripeSecretKey ? new Stripe(stripeSecretKey) : null;
|
const stripe = stripeSecretKey ? new Stripe(stripeSecretKey) : null;
|
||||||
const adminEmails = new Set(
|
const adminEmails = new Set(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export type WorkspaceType = 'standard' | 'rescue';
|
export type WorkspaceType = 'standard' | 'rescue';
|
||||||
export type WorkspaceRole = 'owner' | 'assistant' | 'caregiver' | 'viewer';
|
export type WorkspaceRole = 'owner' | 'assistant' | 'caregiver' | 'viewer';
|
||||||
export type BillingPlan = 'rescue_free' | 'household_basic' | 'household_plus' | 'household_macaw';
|
export type BillingPlan = 'rescue_free' | 'household_basic' | 'household_plus' | 'household_macaw' | 'household_hyacinth_macaw';
|
||||||
export type BillingInterval = 'monthly' | 'yearly';
|
export type BillingInterval = 'monthly' | 'yearly';
|
||||||
export type SubscriptionStatus = 'active' | 'trialing' | 'past_due' | 'canceled' | 'unpaid' | 'none';
|
export type SubscriptionStatus = 'active' | 'trialing' | 'past_due' | 'canceled' | 'unpaid' | 'none';
|
||||||
export type RescueVerificationStatus = 'not_required' | 'pending' | 'approved' | 'rejected';
|
export type RescueVerificationStatus = 'not_required' | 'pending' | 'approved' | 'rejected';
|
||||||
|
|||||||
@@ -73,9 +73,12 @@ services:
|
|||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW: ${STRIPE_PRICE_HOUSEHOLD_MACAW:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY:-}
|
||||||
STRIPE_CHECKOUT_SUCCESS_URL: ${STRIPE_CHECKOUT_SUCCESS_URL:-${FRONTEND_URL}/?billing=success}
|
STRIPE_CHECKOUT_SUCCESS_URL: ${STRIPE_CHECKOUT_SUCCESS_URL:-${FRONTEND_URL}/?billing=success}
|
||||||
STRIPE_CHECKOUT_CANCEL_URL: ${STRIPE_CHECKOUT_CANCEL_URL:-${FRONTEND_URL}/?billing=cancelled}
|
STRIPE_CHECKOUT_CANCEL_URL: ${STRIPE_CHECKOUT_CANCEL_URL:-${FRONTEND_URL}/?billing=cancelled}
|
||||||
STRIPE_PORTAL_RETURN_URL: ${STRIPE_PORTAL_RETURN_URL:-${FRONTEND_URL}/?billing=portal}
|
STRIPE_PORTAL_RETURN_URL: ${STRIPE_PORTAL_RETURN_URL:-${FRONTEND_URL}/?billing=portal}
|
||||||
|
|||||||
+6
-3
@@ -71,9 +71,12 @@ services:
|
|||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_MONTHLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY:-}
|
STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_INDIANRINGNECK_YEARLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW: ${STRIPE_PRICE_HOUSEHOLD_MACAW:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_MACAW_MONTHLY:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_MONTHLY:-}
|
||||||
STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_MACAW_YEARLY:-}
|
STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_AFRICAN_GREY_YEARLY:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_MONTHLY:-}
|
||||||
|
STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY: ${STRIPE_PRICE_HOUSEHOLD_HYACINTH_MACAW_YEARLY:-}
|
||||||
STRIPE_CHECKOUT_SUCCESS_URL: ${STRIPE_CHECKOUT_SUCCESS_URL:-http://localhost:3000/?billing=success}
|
STRIPE_CHECKOUT_SUCCESS_URL: ${STRIPE_CHECKOUT_SUCCESS_URL:-http://localhost:3000/?billing=success}
|
||||||
STRIPE_CHECKOUT_CANCEL_URL: ${STRIPE_CHECKOUT_CANCEL_URL:-http://localhost:3000/?billing=cancelled}
|
STRIPE_CHECKOUT_CANCEL_URL: ${STRIPE_CHECKOUT_CANCEL_URL:-http://localhost:3000/?billing=cancelled}
|
||||||
STRIPE_PORTAL_RETURN_URL: ${STRIPE_PORTAL_RETURN_URL:-http://localhost:3000/?billing=portal}
|
STRIPE_PORTAL_RETURN_URL: ${STRIPE_PORTAL_RETURN_URL:-http://localhost:3000/?billing=portal}
|
||||||
|
|||||||
@@ -653,7 +653,7 @@ Request body:
|
|||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- `workspaceType` must be `standard` or `rescue`
|
- `workspaceType` must be `standard` or `rescue`
|
||||||
- `billingPlan` may be `household_basic`, `household_plus`, or `household_macaw`
|
- `billingPlan` may be `household_basic`, `household_plus`, `household_macaw`, or `household_hyacinth_macaw`
|
||||||
- rescue workspaces are forced to `rescue_free`
|
- rescue workspaces are forced to `rescue_free`
|
||||||
|
|
||||||
Response `201`:
|
Response `201`:
|
||||||
|
|||||||
+35
-13
@@ -5,7 +5,7 @@ import defaultBirdPhoto from './assets/yoda-default.png';
|
|||||||
import { findParrotWeightReference, parrotSpeciesOptions, type ParrotWeightReference } from './parrotWeightReference';
|
import { findParrotWeightReference, parrotSpeciesOptions, type ParrotWeightReference } from './parrotWeightReference';
|
||||||
import QRCode from 'qrcode';
|
import QRCode from 'qrcode';
|
||||||
|
|
||||||
type BillingPlan = 'rescue_free' | 'household_basic' | 'household_plus' | 'household_macaw';
|
type BillingPlan = 'rescue_free' | 'household_basic' | 'household_plus' | 'household_macaw' | 'household_hyacinth_macaw';
|
||||||
type HouseholdBillingPlan = Exclude<BillingPlan, 'rescue_free'>;
|
type HouseholdBillingPlan = Exclude<BillingPlan, 'rescue_free'>;
|
||||||
type BillingInterval = 'monthly' | 'yearly';
|
type BillingInterval = 'monthly' | 'yearly';
|
||||||
type WorkspaceType = 'standard' | 'rescue';
|
type WorkspaceType = 'standard' | 'rescue';
|
||||||
@@ -978,7 +978,7 @@ const oauthStartUrl = (providerKey: AuthProvider['providerKey']) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isHouseholdPlan = (billingPlan: BillingPlan): billingPlan is HouseholdBillingPlan =>
|
const isHouseholdPlan = (billingPlan: BillingPlan): billingPlan is HouseholdBillingPlan =>
|
||||||
billingPlan === 'household_basic' || billingPlan === 'household_plus' || billingPlan === 'household_macaw';
|
billingPlan === 'household_basic' || billingPlan === 'household_plus' || billingPlan === 'household_macaw' || billingPlan === 'household_hyacinth_macaw';
|
||||||
|
|
||||||
const formatBillingIntervalName = (billingInterval: BillingInterval) => (billingInterval === 'yearly' ? 'Annual' : 'Monthly');
|
const formatBillingIntervalName = (billingInterval: BillingInterval) => (billingInterval === 'yearly' ? 'Annual' : 'Monthly');
|
||||||
|
|
||||||
@@ -995,7 +995,11 @@ const formatBillingPlanName = (billingPlan: BillingPlan) => {
|
|||||||
return 'Indian Ringneck';
|
return 'Indian Ringneck';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Macaw';
|
if (billingPlan === 'household_macaw') {
|
||||||
|
return 'African Grey';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Hyacinth Macaw';
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatBillingPlanCapacity = (billingPlan: BillingPlan) => {
|
const formatBillingPlanCapacity = (billingPlan: BillingPlan) => {
|
||||||
@@ -1008,10 +1012,14 @@ const formatBillingPlanCapacity = (billingPlan: BillingPlan) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (billingPlan === 'household_plus') {
|
if (billingPlan === 'household_plus') {
|
||||||
return 'Permits 5 to 10 birds in the flock.';
|
return 'Permits 5 to 9 birds in the flock.';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Permits 11 or more birds in the flock.';
|
if (billingPlan === 'household_macaw') {
|
||||||
|
return 'Permits 11 to 16 birds in the flock.';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Permits 17 or more birds in the flock.';
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatBillingPlanDropdownLabel = (billingPlan: HouseholdBillingPlan) => {
|
const formatBillingPlanDropdownLabel = (billingPlan: HouseholdBillingPlan) => {
|
||||||
@@ -1020,10 +1028,14 @@ const formatBillingPlanDropdownLabel = (billingPlan: HouseholdBillingPlan) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (billingPlan === 'household_plus') {
|
if (billingPlan === 'household_plus') {
|
||||||
return 'Indian Ringneck (10 birds)';
|
return 'Indian Ringneck (5-9 birds)';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Macaw (11+)';
|
if (billingPlan === 'household_macaw') {
|
||||||
|
return 'African Grey (11-16 birds)';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Hyacinth Macaw (17+)';
|
||||||
};
|
};
|
||||||
|
|
||||||
const householdPlanPrices: Record<HouseholdBillingPlan, Record<BillingInterval, string>> = {
|
const householdPlanPrices: Record<HouseholdBillingPlan, Record<BillingInterval, string>> = {
|
||||||
@@ -1039,6 +1051,10 @@ const householdPlanPrices: Record<HouseholdBillingPlan, Record<BillingInterval,
|
|||||||
monthly: '$15.99/month',
|
monthly: '$15.99/month',
|
||||||
yearly: '$160/year',
|
yearly: '$160/year',
|
||||||
},
|
},
|
||||||
|
household_hyacinth_macaw: {
|
||||||
|
monthly: '$49.99/month',
|
||||||
|
yearly: '$500/year',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatBillingIntervalDropdownLabel = (billingPlan: HouseholdBillingPlan, billingInterval: BillingInterval) =>
|
const formatBillingIntervalDropdownLabel = (billingPlan: HouseholdBillingPlan, billingInterval: BillingInterval) =>
|
||||||
@@ -1050,11 +1066,15 @@ const formatBillingPlanBirdLimit = (billingPlan: BillingPlan) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (billingPlan === 'household_plus') {
|
if (billingPlan === 'household_plus') {
|
||||||
return '10';
|
return '9';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (billingPlan === 'household_macaw') {
|
if (billingPlan === 'household_macaw') {
|
||||||
return '11+';
|
return '16';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (billingPlan === 'household_hyacinth_macaw') {
|
||||||
|
return '17+';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -6432,8 +6452,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option value="household_basic">Conure (4 birds)</option>
|
<option value="household_basic">Conure (4 birds)</option>
|
||||||
<option value="household_plus">Indian Ringneck (10 birds)</option>
|
<option value="household_plus">Indian Ringneck (5-9 birds)</option>
|
||||||
<option value="household_macaw">Macaw (11+)</option>
|
<option value="household_macaw">African Grey (11-16 birds)</option>
|
||||||
|
<option value="household_hyacinth_macaw">Hyacinth Macaw (17+)</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
@@ -6570,8 +6591,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<option value="household_basic">Conure (4 birds)</option>
|
<option value="household_basic">Conure (4 birds)</option>
|
||||||
<option value="household_plus">Indian Ringneck (10 birds)</option>
|
<option value="household_plus">Indian Ringneck (5-9 birds)</option>
|
||||||
<option value="household_macaw">Macaw (11+)</option>
|
<option value="household_macaw">African Grey (11-16 birds)</option>
|
||||||
|
<option value="household_hyacinth_macaw">Hyacinth Macaw (17+)</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
Reference in New Issue
Block a user