dating-schema 0.43.1 → 0.44.0

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/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { type AgeRange, ageRangeSchema, emptyStringToUndefined, type Gender, gen
11
11
  export { getFieldMeta, getFieldOptions } from './field-helpers.js';
12
12
  export { type BoostBody, boostBodySchema, type ComplimentBody, complimentBodySchema, type ImageLikeBody, type InteractionListQuery, type InteractionType, imageLikeBodySchema, interactionListQuerySchema, interactionTypeSchema, type RewindBody, rewindBodySchema, type SwipeBody, type SwipeResponse, swipeBodySchema, swipeResponseSchema, } from './interactions.js';
13
13
  export { getOnboardingFieldConfig, ONBOARDING_FIELDS, ONBOARDING_STEP_GROUPS, ONBOARDING_TOTAL_MAIN_STEPS, ONBOARDING_TOTAL_SUB_STEPS, type OnboardingFieldConfig, type OnboardingStepGroup, } from './onboarding-config.js';
14
- export { type BooleanFeatureKey, type EnumFeatureKey, type ExploreAccessLevel, type FeatureDisplayItem, type FeatureKey, type FeatureValue, type FilterLevel, getMinPlanForFeature, getPlanFeatureDisplay, getPlanLimit, getPlanLimits, hasRemainingQuota, isFeatureEnabled, isPaidPlan, type NumericFeatureKey, PAID_PLANS, PLAN_FEATURE_DISPLAY, PLAN_IDS, PLAN_LIMITS, type PlanId, type PlanLimits, PREMIUM_EXPLORE_CATEGORIES, PREMIUM_PLANS, renderFeatureValue, type ScoreBreakdownLevel, TOP_PLANS, type WhoLikedYouLevel, } from './plan-limits.js';
14
+ export { type BooleanFeatureKey, type EnumFeatureKey, type ExploreAccessLevel, type FeatureDisplayItem, type FeatureKey, type FilterLevel, getMinPlanForFeature, getPlanFeatureDisplay, getPlanLimit, getPlanLimits, hasRemainingQuota, isFeatureEnabled, isPaidPlan, type NumericFeatureKey, PAID_PLANS, PLAN_FEATURE_DISPLAY, PLAN_IDS, PLAN_LIMITS, type PlanDisplayValue, type PlanId, type PlanLimits, PREMIUM_EXPLORE_CATEGORIES, PREMIUM_PLANS, renderPlanDisplayValue, type ScoreBreakdownLevel, TOP_PLANS, type WhoLikedYouLevel, } from './plan-limits.js';
15
15
  export { type CreateProfileInput, createProfileSchema, type FullProfileData, fullProfileSchema, getCognitiveBandRank, type OnboardingFormData, onboardingFormSchema, type UpdateProfileInput, updateProfileSchema, } from './profile.js';
16
16
  export { allFieldGroups, basics, career, cognitive, type FieldGroup, type FieldOption, familyHome, favourites, financeLegal, healthWellness, heroIdentity, interestCategories, interests, lifestyle, lookingFor, type MultiSelectField, type OptionCategory, type ProfileField, personality, relationshipIntimacy, religionCommunity, type SelectField, selfAssessment, storyPrompts, values, } from './profile-fields/index.js';
17
17
  export { type BlockBody, blockBodySchema, type ReportBody, type ReportReason, type ReportStatus, reportBodySchema, reportReasonSchema, reportStatusSchema, } from './safety.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ export { getFieldMeta, getFieldOptions } from './field-helpers.js';
19
19
  export { boostBodySchema, complimentBodySchema, imageLikeBodySchema, interactionListQuerySchema, interactionTypeSchema, rewindBodySchema, swipeBodySchema, swipeResponseSchema, } from './interactions.js';
20
20
  export { getOnboardingFieldConfig, ONBOARDING_FIELDS, ONBOARDING_STEP_GROUPS, ONBOARDING_TOTAL_MAIN_STEPS, ONBOARDING_TOTAL_SUB_STEPS, } from './onboarding-config.js';
21
21
  // ─── Plan limits ─────────────────────────────────────────────────────────────
22
- export { getMinPlanForFeature, getPlanFeatureDisplay, getPlanLimit, getPlanLimits, hasRemainingQuota, isFeatureEnabled, isPaidPlan, PAID_PLANS, PLAN_FEATURE_DISPLAY, PLAN_IDS, PLAN_LIMITS, PREMIUM_EXPLORE_CATEGORIES, PREMIUM_PLANS, renderFeatureValue, TOP_PLANS, } from './plan-limits.js';
22
+ export { getMinPlanForFeature, getPlanFeatureDisplay, getPlanLimit, getPlanLimits, hasRemainingQuota, isFeatureEnabled, isPaidPlan, PAID_PLANS, PLAN_FEATURE_DISPLAY, PLAN_IDS, PLAN_LIMITS, PREMIUM_EXPLORE_CATEGORIES, PREMIUM_PLANS, renderPlanDisplayValue, TOP_PLANS, } from './plan-limits.js';
23
23
  // ─── Profile schemas ─────────────────────────────────────────────────────────
24
24
  export { createProfileSchema, fullProfileSchema, getCognitiveBandRank, onboardingFormSchema, updateProfileSchema, } from './profile.js';
25
25
  // ─── Profile field configs (option arrays with labels for UI rendering) ──────
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,OAAO,EACL,aAAa,EAGb,cAAc,EAEd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,OAAO;AAEL,cAAc;AACd,cAAc,EACd,sBAAsB;AAEtB,QAAQ;AACR,YAAY,EAEZ,kBAAkB,EAElB,gBAAgB,EAIhB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EAGrB,gBAAgB,EAChB,WAAW,EAEX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,gFAAgF;AAChF,OAAO,EAEL,eAAe,EAEf,oBAAoB,EAIpB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EAErB,gBAAgB,EAGhB,eAAe,EACf,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,GAG3B,MAAM,wBAAwB,CAAC;AAChC,gFAAgF;AAChF,OAAO,EAQL,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EAEV,UAAU,EACV,oBAAoB,EACpB,QAAQ,EACR,WAAW,EAGX,0BAA0B,EAC1B,aAAa,EACb,kBAAkB,EAElB,SAAS,GAEV,MAAM,kBAAkB,CAAC;AAC1B,gFAAgF;AAChF,OAAO,EAEL,mBAAmB,EAEnB,iBAAiB,EACjB,oBAAoB,EAEpB,oBAAoB,EAEpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,gFAAgF;AAChF,OAAO,EACL,cAAc,EACd,MAAM,EACN,MAAM,EACN,SAAS,EAGT,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,UAAU,EAIV,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EAEjB,cAAc,EACd,YAAY,EACZ,MAAM,GACP,MAAM,2BAA2B,CAAC;AAEnC,gFAAgF;AAChF,OAAO,EAEL,eAAe,EAIf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,OAAO,EAEL,4BAA4B,EAE5B,wBAAwB,EAExB,YAAY,GACb,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * dating-schema — Shared Zod schemas for the Dating feature\n *\n * Single source of truth consumed by both jansathi-frontend and reform-backend.\n * Guarantees identical validation logic and TypeScript types on both sides.\n *\n * @module dating-schema\n */\n\n// ─── Badge schemas ──────────────────────────────────────────────────────────\nexport {\n BADGE_DISPLAY,\n type BadgeDisplayInfo,\n type BadgeKey,\n badgeKeySchema,\n type UpdateBadgesBody,\n updateBadgesBodySchema,\n} from './badges.js';\n\n// ─── Common helpers and enums ────────────────────────────────────────────────\nexport {\n type AgeRange,\n // sub-schemas\n ageRangeSchema,\n emptyStringToUndefined,\n type Gender,\n // enums\n genderSchema,\n type InterestedIn,\n interestedInSchema,\n type LookingFor,\n lookingForSchema,\n type MaritalStatus,\n type MatchStatus,\n type MessageType,\n maritalStatusSchema,\n matchStatusSchema,\n messageTypeSchema,\n optionalTrimmedString,\n type Pagination,\n type Photo,\n paginationSchema,\n photoSchema,\n type SwipeAction,\n swipeActionSchema,\n} from './common.js';\nexport { getFieldMeta, getFieldOptions } from './field-helpers.js';\n// ─── Interaction schemas ─────────────────────────────────────────────────────\nexport {\n type BoostBody,\n boostBodySchema,\n type ComplimentBody,\n complimentBodySchema,\n type ImageLikeBody,\n type InteractionListQuery,\n type InteractionType,\n imageLikeBodySchema,\n interactionListQuerySchema,\n interactionTypeSchema,\n type RewindBody,\n rewindBodySchema,\n type SwipeBody,\n type SwipeResponse,\n swipeBodySchema,\n swipeResponseSchema,\n} from './interactions.js';\nexport {\n getOnboardingFieldConfig,\n ONBOARDING_FIELDS,\n ONBOARDING_STEP_GROUPS,\n ONBOARDING_TOTAL_MAIN_STEPS,\n ONBOARDING_TOTAL_SUB_STEPS,\n type OnboardingFieldConfig,\n type OnboardingStepGroup,\n} from './onboarding-config.js';\n// ─── Plan limits ─────────────────────────────────────────────────────────────\nexport {\n type BooleanFeatureKey,\n type EnumFeatureKey,\n type ExploreAccessLevel,\n type FeatureDisplayItem,\n type FeatureKey,\n type FeatureValue,\n type FilterLevel,\n getMinPlanForFeature,\n getPlanFeatureDisplay,\n getPlanLimit,\n getPlanLimits,\n hasRemainingQuota,\n isFeatureEnabled,\n isPaidPlan,\n type NumericFeatureKey,\n PAID_PLANS,\n PLAN_FEATURE_DISPLAY,\n PLAN_IDS,\n PLAN_LIMITS,\n type PlanId,\n type PlanLimits,\n PREMIUM_EXPLORE_CATEGORIES,\n PREMIUM_PLANS,\n renderFeatureValue,\n type ScoreBreakdownLevel,\n TOP_PLANS,\n type WhoLikedYouLevel,\n} from './plan-limits.js';\n// ─── Profile schemas ─────────────────────────────────────────────────────────\nexport {\n type CreateProfileInput,\n createProfileSchema,\n type FullProfileData,\n fullProfileSchema,\n getCognitiveBandRank,\n type OnboardingFormData,\n onboardingFormSchema,\n type UpdateProfileInput,\n updateProfileSchema,\n} from './profile.js';\n// ─── Profile field configs (option arrays with labels for UI rendering) ──────\nexport {\n allFieldGroups,\n basics,\n career,\n cognitive,\n type FieldGroup,\n type FieldOption,\n familyHome,\n favourites,\n financeLegal,\n healthWellness,\n heroIdentity,\n interestCategories,\n interests,\n lifestyle,\n lookingFor,\n type MultiSelectField,\n type OptionCategory,\n type ProfileField,\n personality,\n relationshipIntimacy,\n religionCommunity,\n type SelectField,\n selfAssessment,\n storyPrompts,\n values,\n} from './profile-fields/index.js';\n\n// ─── Safety schemas ──────────────────────────────────────────────────────────\nexport {\n type BlockBody,\n blockBodySchema,\n type ReportBody,\n type ReportReason,\n type ReportStatus,\n reportBodySchema,\n reportReasonSchema,\n reportStatusSchema,\n} from './safety.js';\n\n// ─── Subscription schemas ────────────────────────────────────────────────────\nexport {\n type CreateSubscriptionBody,\n createSubscriptionBodySchema,\n type SubscriptionStatus,\n subscriptionStatusSchema,\n type Tenure,\n tenureSchema,\n} from './subscription.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,+EAA+E;AAC/E,OAAO,EACL,aAAa,EAGb,cAAc,EAEd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,OAAO;AAEL,cAAc;AACd,cAAc,EACd,sBAAsB;AAEtB,QAAQ;AACR,YAAY,EAEZ,kBAAkB,EAElB,gBAAgB,EAIhB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EAGrB,gBAAgB,EAChB,WAAW,EAEX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACnE,gFAAgF;AAChF,OAAO,EAEL,eAAe,EAEf,oBAAoB,EAIpB,mBAAmB,EACnB,0BAA0B,EAC1B,qBAAqB,EAErB,gBAAgB,EAGhB,eAAe,EACf,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,GAG3B,MAAM,wBAAwB,CAAC;AAChC,gFAAgF;AAChF,OAAO,EAOL,oBAAoB,EACpB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EAEV,UAAU,EACV,oBAAoB,EACpB,QAAQ,EACR,WAAW,EAIX,0BAA0B,EAC1B,aAAa,EACb,sBAAsB,EAEtB,SAAS,GAEV,MAAM,kBAAkB,CAAC;AAC1B,gFAAgF;AAChF,OAAO,EAEL,mBAAmB,EAEnB,iBAAiB,EACjB,oBAAoB,EAEpB,oBAAoB,EAEpB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,gFAAgF;AAChF,OAAO,EACL,cAAc,EACd,MAAM,EACN,MAAM,EACN,SAAS,EAGT,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,SAAS,EACT,UAAU,EAIV,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EAEjB,cAAc,EACd,YAAY,EACZ,MAAM,GACP,MAAM,2BAA2B,CAAC;AAEnC,gFAAgF;AAChF,OAAO,EAEL,eAAe,EAIf,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAErB,gFAAgF;AAChF,OAAO,EAEL,4BAA4B,EAE5B,wBAAwB,EAExB,YAAY,GACb,MAAM,mBAAmB,CAAC","sourcesContent":["/**\n * dating-schema — Shared Zod schemas for the Dating feature\n *\n * Single source of truth consumed by both jansathi-frontend and reform-backend.\n * Guarantees identical validation logic and TypeScript types on both sides.\n *\n * @module dating-schema\n */\n\n// ─── Badge schemas ──────────────────────────────────────────────────────────\nexport {\n BADGE_DISPLAY,\n type BadgeDisplayInfo,\n type BadgeKey,\n badgeKeySchema,\n type UpdateBadgesBody,\n updateBadgesBodySchema,\n} from './badges.js';\n\n// ─── Common helpers and enums ────────────────────────────────────────────────\nexport {\n type AgeRange,\n // sub-schemas\n ageRangeSchema,\n emptyStringToUndefined,\n type Gender,\n // enums\n genderSchema,\n type InterestedIn,\n interestedInSchema,\n type LookingFor,\n lookingForSchema,\n type MaritalStatus,\n type MatchStatus,\n type MessageType,\n maritalStatusSchema,\n matchStatusSchema,\n messageTypeSchema,\n optionalTrimmedString,\n type Pagination,\n type Photo,\n paginationSchema,\n photoSchema,\n type SwipeAction,\n swipeActionSchema,\n} from './common.js';\nexport { getFieldMeta, getFieldOptions } from './field-helpers.js';\n// ─── Interaction schemas ─────────────────────────────────────────────────────\nexport {\n type BoostBody,\n boostBodySchema,\n type ComplimentBody,\n complimentBodySchema,\n type ImageLikeBody,\n type InteractionListQuery,\n type InteractionType,\n imageLikeBodySchema,\n interactionListQuerySchema,\n interactionTypeSchema,\n type RewindBody,\n rewindBodySchema,\n type SwipeBody,\n type SwipeResponse,\n swipeBodySchema,\n swipeResponseSchema,\n} from './interactions.js';\nexport {\n getOnboardingFieldConfig,\n ONBOARDING_FIELDS,\n ONBOARDING_STEP_GROUPS,\n ONBOARDING_TOTAL_MAIN_STEPS,\n ONBOARDING_TOTAL_SUB_STEPS,\n type OnboardingFieldConfig,\n type OnboardingStepGroup,\n} from './onboarding-config.js';\n// ─── Plan limits ─────────────────────────────────────────────────────────────\nexport {\n type BooleanFeatureKey,\n type EnumFeatureKey,\n type ExploreAccessLevel,\n type FeatureDisplayItem,\n type FeatureKey,\n type FilterLevel,\n getMinPlanForFeature,\n getPlanFeatureDisplay,\n getPlanLimit,\n getPlanLimits,\n hasRemainingQuota,\n isFeatureEnabled,\n isPaidPlan,\n type NumericFeatureKey,\n PAID_PLANS,\n PLAN_FEATURE_DISPLAY,\n PLAN_IDS,\n PLAN_LIMITS,\n type PlanDisplayValue,\n type PlanId,\n type PlanLimits,\n PREMIUM_EXPLORE_CATEGORIES,\n PREMIUM_PLANS,\n renderPlanDisplayValue,\n type ScoreBreakdownLevel,\n TOP_PLANS,\n type WhoLikedYouLevel,\n} from './plan-limits.js';\n// ─── Profile schemas ─────────────────────────────────────────────────────────\nexport {\n type CreateProfileInput,\n createProfileSchema,\n type FullProfileData,\n fullProfileSchema,\n getCognitiveBandRank,\n type OnboardingFormData,\n onboardingFormSchema,\n type UpdateProfileInput,\n updateProfileSchema,\n} from './profile.js';\n// ─── Profile field configs (option arrays with labels for UI rendering) ──────\nexport {\n allFieldGroups,\n basics,\n career,\n cognitive,\n type FieldGroup,\n type FieldOption,\n familyHome,\n favourites,\n financeLegal,\n healthWellness,\n heroIdentity,\n interestCategories,\n interests,\n lifestyle,\n lookingFor,\n type MultiSelectField,\n type OptionCategory,\n type ProfileField,\n personality,\n relationshipIntimacy,\n religionCommunity,\n type SelectField,\n selfAssessment,\n storyPrompts,\n values,\n} from './profile-fields/index.js';\n\n// ─── Safety schemas ──────────────────────────────────────────────────────────\nexport {\n type BlockBody,\n blockBodySchema,\n type ReportBody,\n type ReportReason,\n type ReportStatus,\n reportBodySchema,\n reportReasonSchema,\n reportStatusSchema,\n} from './safety.js';\n\n// ─── Subscription schemas ────────────────────────────────────────────────────\nexport {\n type CreateSubscriptionBody,\n createSubscriptionBodySchema,\n type SubscriptionStatus,\n subscriptionStatusSchema,\n type Tenure,\n tenureSchema,\n} from './subscription.js';\n"]}
@@ -1,10 +1,13 @@
1
1
  /**
2
- * Plan feature display data separated to keep plan-limits.ts clean.
3
- * Each plan value uses { qty, text, unit? } so the frontend renders:
4
- * `${qty} ${text} ${unit}` → "10 compliments per day"
5
- * Boolean true = checkmark (show label), false = locked.
2
+ * Plan feature display data -- separated to keep plan-limits.ts clean.
6
3
  *
7
- * 4-tier system: Lite (free) Basic (decoy) → Premium (target) → Black (elite)
4
+ * Each plan value is one of:
5
+ * - false -> locked (show lock icon)
6
+ * - true -> enabled (show label with checkmark)
7
+ * - "10 likes per day" -> show this display text
8
+ * - { text: "...", helpText?: "..." } -> display text + per-plan helpText override
9
+ *
10
+ * 4-tier system: Lite (free) -> Basic (decoy) -> Premium (target) -> Black (elite)
8
11
  */
9
12
  import type { FeatureDisplayItem } from './plan-limits.js';
10
13
  export declare const PLAN_FEATURE_DISPLAY_DATA: FeatureDisplayItem[];
@@ -1 +1 @@
1
- {"version":3,"file":"plan-features-data.d.ts","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAgB,MAAM,kBAAkB,CAAC;AAQzE,eAAO,MAAM,yBAAyB,EAAE,kBAAkB,EAmPzD,CAAC"}
1
+ {"version":3,"file":"plan-features-data.d.ts","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,eAAO,MAAM,yBAAyB,EAAE,kBAAkB,EA4PzD,CAAC"}
@@ -1,16 +1,14 @@
1
1
  /**
2
- * Plan feature display data separated to keep plan-limits.ts clean.
3
- * Each plan value uses { qty, text, unit? } so the frontend renders:
4
- * `${qty} ${text} ${unit}` → "10 compliments per day"
5
- * Boolean true = checkmark (show label), false = locked.
2
+ * Plan feature display data -- separated to keep plan-limits.ts clean.
6
3
  *
7
- * 4-tier system: Lite (free) Basic (decoy) → Premium (target) → Black (elite)
4
+ * Each plan value is one of:
5
+ * - false -> locked (show lock icon)
6
+ * - true -> enabled (show label with checkmark)
7
+ * - "10 likes per day" -> show this display text
8
+ * - { text: "...", helpText?: "..." } -> display text + per-plan helpText override
9
+ *
10
+ * 4-tier system: Lite (free) -> Basic (decoy) -> Premium (target) -> Black (elite)
8
11
  */
9
- /** Shorthand helpers */
10
- const u = (text) => ({ qty: 'Unlimited', text });
11
- const n = (qty, text, unit) => ({ qty, text, unit });
12
- const d = (qty, text) => ({ qty, text });
13
- // prettier-ignore
14
12
  export const PLAN_FEATURE_DISPLAY_DATA = [
15
13
  // ── Core actions ──
16
14
  {
@@ -19,10 +17,10 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
19
17
  available: true,
20
18
  helpText: 'The number of profiles you can like each day. Passing left is always unlimited.',
21
19
  plans: {
22
- lite: n('10', 'likes', 'per day'),
23
- basic: n('50', 'likes', 'per day'),
24
- premium: n('300', 'likes', 'per day'),
25
- black: u('likes'),
20
+ lite: '10 likes per day',
21
+ basic: '50 likes per day',
22
+ premium: '300 likes per day',
23
+ black: 'Unlimited likes',
26
24
  },
27
25
  },
28
26
  {
@@ -31,10 +29,10 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
31
29
  available: true,
32
30
  helpText: 'Send a compliment with a personal note to stand out. They see it even before matching with you.',
33
31
  plans: {
34
- lite: n('1', 'compliment', 'per day'),
35
- basic: n('5', 'compliments', 'per day'),
36
- premium: n('10', 'compliments', 'per day'),
37
- black: u('compliments'),
32
+ lite: '1 compliment per day',
33
+ basic: '5 compliments per day',
34
+ premium: '10 compliments per day',
35
+ black: 'Unlimited compliments',
38
36
  },
39
37
  },
40
38
  {
@@ -44,9 +42,9 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
44
42
  helpText: 'Accidentally passed on someone? Tap rewind to bring their profile back instantly.',
45
43
  plans: {
46
44
  lite: false,
47
- basic: u('rewinds'),
48
- premium: u('rewinds'),
49
- black: u('rewinds'),
45
+ basic: 'Unlimited rewinds',
46
+ premium: 'Unlimited rewinds',
47
+ black: 'Unlimited rewinds',
50
48
  },
51
49
  },
52
50
  // ── Visibility & discovery ──
@@ -61,12 +59,12 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
61
59
  key: 'whoLikedYou',
62
60
  label: 'See who likes you',
63
61
  available: true,
64
- helpText: 'See the list of people who already liked your profile, so you can match with them instantly.',
62
+ helpText: 'See all your interactions in one place: profiles you liked, people who liked you, compliments you sent, and compliments you received.',
65
63
  plans: {
66
64
  lite: false,
67
- basic: d('See who likes you', '(blurred)'),
68
- premium: d('Instant', 'like alerts'),
69
- black: d('Instant', 'like alerts'),
65
+ basic: 'See who likes you (blurred)',
66
+ premium: 'See all interactions',
67
+ black: 'See all interactions',
70
68
  },
71
69
  },
72
70
  {
@@ -75,10 +73,10 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
75
73
  available: true,
76
74
  helpText: 'Filter profiles by age, location, religion, education, profession, and more.',
77
75
  plans: {
78
- lite: d('Basic', 'filters'),
79
- basic: d('Advanced', 'filters'),
80
- premium: d('All', 'filters'),
81
- black: d('All', 'filters'),
76
+ lite: 'Basic filters',
77
+ basic: 'Advanced filters',
78
+ premium: 'All filters',
79
+ black: 'All filters',
82
80
  },
83
81
  },
84
82
  {
@@ -87,10 +85,10 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
87
85
  available: true,
88
86
  helpText: 'See how compatible you are with each profile based on 120+ data points across Social Fit, Personality, and Intimacy.',
89
87
  plans: {
90
- lite: n('3', 'scores', 'per day'),
91
- basic: u('scores'),
92
- premium: u('scores'),
93
- black: u('scores'),
88
+ lite: '3 compatibility scores per day',
89
+ basic: 'Unlimited compatibility scores',
90
+ premium: 'Unlimited compatibility scores',
91
+ black: 'Unlimited compatibility scores',
94
92
  },
95
93
  },
96
94
  {
@@ -101,8 +99,8 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
101
99
  plans: {
102
100
  lite: false,
103
101
  basic: false,
104
- premium: d('Full', 'breakdown'),
105
- black: d('Full', 'breakdown'),
102
+ premium: 'Full compatibility score breakdown',
103
+ black: 'Full compatibility score breakdown',
106
104
  },
107
105
  },
108
106
  {
@@ -136,9 +134,9 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
136
134
  helpText: 'Boost your profile to the top of the discover feed for 30 minutes and get seen by more people.',
137
135
  plans: {
138
136
  lite: false,
139
- basic: n('3', 'boosts', 'per month'),
140
- premium: n('5', 'boosts', 'per month'),
141
- black: n('10', 'boosts', 'per month'),
137
+ basic: '3 boosts per month',
138
+ premium: '5 boosts per month',
139
+ black: '10 boosts per month',
142
140
  },
143
141
  },
144
142
  // ── Communication ──
@@ -153,12 +151,12 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
153
151
  key: 'calls',
154
152
  label: 'Voice & video calls',
155
153
  available: false,
156
- helpText: 'Talk face-to-face or voice-only with your matches directly inside the app, no phone number needed.',
154
+ helpText: 'Talk face-to-face or voice-only with your matches directly inside the app, no phone number needed.',
157
155
  plans: {
158
156
  lite: false,
159
- basic: n('3 voice + 2 video', 'calls', 'per day'),
160
- premium: u('calls'),
161
- black: u('calls'),
157
+ basic: '3 voice + 2 video calls per day',
158
+ premium: 'Unlimited calls',
159
+ black: 'Unlimited calls',
162
160
  },
163
161
  },
164
162
  {
@@ -171,7 +169,7 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
171
169
  {
172
170
  key: 'messageBeforeMatch',
173
171
  label: 'Send a message first',
174
- available: false,
172
+ available: true,
175
173
  helpText: 'Introduce yourself with a message before the other person swipes on you.',
176
174
  plans: { lite: false, basic: false, premium: true, black: true },
177
175
  },
@@ -202,19 +200,22 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
202
200
  key: 'travelMode',
203
201
  label: 'Teleport Mode',
204
202
  available: true,
205
- helpText: 'Browse profiles in any city, district, or state without physically being there.',
203
+ helpText: 'Browse profiles in any city, district, or state without physically being there.',
206
204
  plans: { lite: false, basic: false, premium: true, black: true },
207
205
  },
208
206
  {
209
207
  key: 'seePublicBlackProfiles',
210
208
  label: 'Discover Black Circle profiles',
211
209
  available: true,
212
- helpText: 'Premium members can see Black Circle profiles that are publicly discoverable. Black Circle members get full unrestricted access to all Black Circle profiles.',
210
+ helpText: 'See profiles of Black Circle members who have chosen to be publicly discoverable.',
213
211
  plans: {
214
212
  lite: false,
215
213
  basic: false,
216
- premium: d('Public', 'profiles only'),
217
- black: d('Full', 'access to all'),
214
+ premium: true,
215
+ black: {
216
+ text: 'Discover Black Circle profiles',
217
+ helpText: 'As a Black Circle member, you have unrestricted access to all Black Circle profiles, not just publicly discoverable ones.',
218
+ },
218
219
  },
219
220
  },
220
221
  // ── Black exclusive ──
@@ -1 +1 @@
1
- {"version":3,"file":"plan-features-data.js","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan feature display data — separated to keep plan-limits.ts clean.\n * Each plan value uses { qty, text, unit? } so the frontend renders:\n * `${qty} ${text} ${unit}` → \"10 compliments per day\"\n * Boolean true = checkmark (show label), false = locked.\n *\n * 4-tier system: Lite (free) → Basic (decoy) → Premium (target) → Black (elite)\n */\n\nimport type { FeatureDisplayItem, FeatureValue } from './plan-limits.js';\n\n/** Shorthand helpers */\nconst u = (text: string): FeatureValue => ({ qty: 'Unlimited', text });\nconst n = (qty: string, text: string, unit: string): FeatureValue => ({ qty, text, unit });\nconst d = (qty: string, text: string): FeatureValue => ({ qty, text });\n\n// prettier-ignore\nexport const PLAN_FEATURE_DISPLAY_DATA: FeatureDisplayItem[] = [\n // ── Core actions ──\n {\n key: 'dailyLikes',\n label: 'Likes per day',\n available: true,\n helpText: 'The number of profiles you can like each day. Passing left is always unlimited.',\n plans: {\n lite: n('10', 'likes', 'per day'),\n basic: n('50', 'likes', 'per day'),\n premium: n('300', 'likes', 'per day'),\n black: u('likes'),\n },\n },\n {\n key: 'dailyCompliments',\n label: 'Compliments',\n available: true,\n helpText:\n 'Send a compliment with a personal note to stand out. They see it even before matching with you.',\n plans: {\n lite: n('1', 'compliment', 'per day'),\n basic: n('5', 'compliments', 'per day'),\n premium: n('10', 'compliments', 'per day'),\n black: u('compliments'),\n },\n },\n {\n key: 'dailyRewinds',\n label: 'Rewind',\n available: true,\n helpText: 'Accidentally passed on someone? Tap rewind to bring their profile back instantly.',\n plans: {\n lite: false,\n basic: u('rewinds'),\n premium: u('rewinds'),\n black: u('rewinds'),\n },\n },\n // ── Visibility & discovery ──\n {\n key: 'showAds',\n label: 'Ad-free experience',\n available: true,\n helpText: 'Browse profiles, chat, and explore without any ads interrupting your experience.',\n plans: { lite: false, basic: true, premium: true, black: true },\n },\n {\n key: 'whoLikedYou',\n label: 'See who likes you',\n available: true,\n helpText:\n 'See the list of people who already liked your profile, so you can match with them instantly.',\n plans: {\n lite: false,\n basic: d('See who likes you', '(blurred)'),\n premium: d('Instant', 'like alerts'),\n black: d('Instant', 'like alerts'),\n },\n },\n {\n key: 'filterLevel',\n label: 'Search filters',\n available: true,\n helpText: 'Filter profiles by age, location, religion, education, profession, and more.',\n plans: {\n lite: d('Basic', 'filters'),\n basic: d('Advanced', 'filters'),\n premium: d('All', 'filters'),\n black: d('All', 'filters'),\n },\n },\n {\n key: 'scoreVisibleProfiles',\n label: 'Compatibility scores',\n available: true,\n helpText:\n 'See how compatible you are with each profile based on 120+ data points across Social Fit, Personality, and Intimacy.',\n plans: {\n lite: n('3', 'scores', 'per day'),\n basic: u('scores'),\n premium: u('scores'),\n black: u('scores'),\n },\n },\n {\n key: 'scoreBreakdown',\n label: 'Compatibility score breakdown',\n available: true,\n helpText:\n 'See the detailed compatibility breakdown across Social Fit, Personality, and Intimacy dimensions for every profile.',\n plans: {\n lite: false,\n basic: false,\n premium: d('Full', 'breakdown'),\n black: d('Full', 'breakdown'),\n },\n },\n {\n key: 'dimensionControl',\n label: 'Compatibility dimension control',\n available: true,\n helpText:\n 'Control which compatibility dimensions (Social Fit, Personality, Intimacy) matter most to you. Your discover feed re-ranks profiles based on your priorities.',\n plans: {\n lite: false,\n basic: false,\n premium: true,\n black: true,\n },\n },\n {\n key: 'premiumExplore',\n label: 'Premium Explore categories',\n available: true,\n helpText:\n 'Access exclusive Explore categories like High IQ Dating, IIT/IIM Dating, Casual Dating, Elite Black Circle, and more curated collections.',\n plans: {\n lite: false,\n basic: false,\n premium: true,\n black: true,\n },\n },\n {\n key: 'monthlyBoosts',\n label: 'Profile boosts',\n available: true,\n helpText:\n 'Boost your profile to the top of the discover feed for 30 minutes and get seen by more people.',\n plans: {\n lite: false,\n basic: n('3', 'boosts', 'per month'),\n premium: n('5', 'boosts', 'per month'),\n black: n('10', 'boosts', 'per month'),\n },\n },\n // ── Communication ──\n {\n key: 'readReceipts',\n label: 'Read receipts',\n available: true,\n helpText: 'Know exactly when someone has read your message. No more guessing.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'calls',\n label: 'Voice & video calls',\n available: false,\n helpText:\n 'Talk face-to-face or voice-only with your matches — directly inside the app, no phone number needed.',\n plans: {\n lite: false,\n basic: n('3 voice + 2 video', 'calls', 'per day'),\n premium: u('calls'),\n black: u('calls'),\n },\n },\n {\n key: 'voiceMessages',\n label: 'Voice messages in chat',\n available: false,\n helpText: 'Record and send short voice clips in chat instead of typing.',\n plans: { lite: false, basic: true, premium: true, black: true },\n },\n {\n key: 'messageBeforeMatch',\n label: 'Send a message first',\n available: false,\n helpText: 'Introduce yourself with a message before the other person swipes on you.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n // ── Insights ──\n {\n key: 'photoInsights',\n label: 'Photo Insights',\n available: true,\n helpText:\n 'See which of your photos gets the most likes and attention, and get tips to improve.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'viewContactNumber',\n label: 'View contact number',\n available: true,\n helpText:\n 'See the phone number of profiles who have chosen to share it. Both the user and their family contact if shared.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n // ── Premium perks ──\n {\n key: 'incognitoMode',\n label: 'Incognito Mode',\n available: true,\n helpText:\n 'Go invisible. Your profile is hidden from everyone except the people you choose to like.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'travelMode',\n label: 'Teleport Mode',\n available: true,\n helpText: 'Browse profiles in any city, district, or state — without physically being there.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'seePublicBlackProfiles',\n label: 'Discover Black Circle profiles',\n available: true,\n helpText:\n 'Premium members can see Black Circle profiles that are publicly discoverable. Black Circle members get full unrestricted access to all Black Circle profiles.',\n plans: {\n lite: false,\n basic: false,\n premium: d('Public', 'profiles only'),\n black: d('Full', 'access to all'),\n },\n },\n // ── Black exclusive ──\n {\n key: 'exclusiveLeague',\n label: 'The Black Circle',\n available: true,\n helpText:\n 'An exclusive community of celebrities, founders, and high-net-worth individuals. Your profile is only visible to other verified Black Circle members.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n {\n key: 'verifiedBadge',\n label: 'Verified Elite badge',\n available: true,\n helpText:\n 'A distinctive badge on your profile, granted after admin verification. Signals you are a verified Black Circle member.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n {\n key: 'vipSupport',\n label: 'Dedicated concierge',\n available: true,\n helpText:\n 'A personal matchmaking concierge who helps curate your matches and provides priority support.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n];\n"]}
1
+ {"version":3,"file":"plan-features-data.js","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plan feature display data -- separated to keep plan-limits.ts clean.\n *\n * Each plan value is one of:\n * - false -> locked (show lock icon)\n * - true -> enabled (show label with checkmark)\n * - \"10 likes per day\" -> show this display text\n * - { text: \"...\", helpText?: \"...\" } -> display text + per-plan helpText override\n *\n * 4-tier system: Lite (free) -> Basic (decoy) -> Premium (target) -> Black (elite)\n */\n\nimport type { FeatureDisplayItem } from './plan-limits.js';\n\nexport const PLAN_FEATURE_DISPLAY_DATA: FeatureDisplayItem[] = [\n // ── Core actions ──\n {\n key: 'dailyLikes',\n label: 'Likes per day',\n available: true,\n helpText: 'The number of profiles you can like each day. Passing left is always unlimited.',\n plans: {\n lite: '10 likes per day',\n basic: '50 likes per day',\n premium: '300 likes per day',\n black: 'Unlimited likes',\n },\n },\n {\n key: 'dailyCompliments',\n label: 'Compliments',\n available: true,\n helpText:\n 'Send a compliment with a personal note to stand out. They see it even before matching with you.',\n plans: {\n lite: '1 compliment per day',\n basic: '5 compliments per day',\n premium: '10 compliments per day',\n black: 'Unlimited compliments',\n },\n },\n {\n key: 'dailyRewinds',\n label: 'Rewind',\n available: true,\n helpText: 'Accidentally passed on someone? Tap rewind to bring their profile back instantly.',\n plans: {\n lite: false,\n basic: 'Unlimited rewinds',\n premium: 'Unlimited rewinds',\n black: 'Unlimited rewinds',\n },\n },\n\n // ── Visibility & discovery ──\n {\n key: 'showAds',\n label: 'Ad-free experience',\n available: true,\n helpText: 'Browse profiles, chat, and explore without any ads interrupting your experience.',\n plans: { lite: false, basic: true, premium: true, black: true },\n },\n {\n key: 'whoLikedYou',\n label: 'See who likes you',\n available: true,\n helpText:\n 'See all your interactions in one place: profiles you liked, people who liked you, compliments you sent, and compliments you received.',\n plans: {\n lite: false,\n basic: 'See who likes you (blurred)',\n premium: 'See all interactions',\n black: 'See all interactions',\n },\n },\n {\n key: 'filterLevel',\n label: 'Search filters',\n available: true,\n helpText: 'Filter profiles by age, location, religion, education, profession, and more.',\n plans: {\n lite: 'Basic filters',\n basic: 'Advanced filters',\n premium: 'All filters',\n black: 'All filters',\n },\n },\n {\n key: 'scoreVisibleProfiles',\n label: 'Compatibility scores',\n available: true,\n helpText:\n 'See how compatible you are with each profile based on 120+ data points across Social Fit, Personality, and Intimacy.',\n plans: {\n lite: '3 compatibility scores per day',\n basic: 'Unlimited compatibility scores',\n premium: 'Unlimited compatibility scores',\n black: 'Unlimited compatibility scores',\n },\n },\n {\n key: 'scoreBreakdown',\n label: 'Compatibility score breakdown',\n available: true,\n helpText:\n 'See the detailed compatibility breakdown across Social Fit, Personality, and Intimacy dimensions for every profile.',\n plans: {\n lite: false,\n basic: false,\n premium: 'Full compatibility score breakdown',\n black: 'Full compatibility score breakdown',\n },\n },\n {\n key: 'dimensionControl',\n label: 'Compatibility dimension control',\n available: true,\n helpText:\n 'Control which compatibility dimensions (Social Fit, Personality, Intimacy) matter most to you. Your discover feed re-ranks profiles based on your priorities.',\n plans: {\n lite: false,\n basic: false,\n premium: true,\n black: true,\n },\n },\n {\n key: 'premiumExplore',\n label: 'Premium Explore categories',\n available: true,\n helpText:\n 'Access exclusive Explore categories like High IQ Dating, IIT/IIM Dating, Casual Dating, Elite Black Circle, and more curated collections.',\n plans: {\n lite: false,\n basic: false,\n premium: true,\n black: true,\n },\n },\n {\n key: 'monthlyBoosts',\n label: 'Profile boosts',\n available: true,\n helpText:\n 'Boost your profile to the top of the discover feed for 30 minutes and get seen by more people.',\n plans: {\n lite: false,\n basic: '3 boosts per month',\n premium: '5 boosts per month',\n black: '10 boosts per month',\n },\n },\n\n // ── Communication ──\n {\n key: 'readReceipts',\n label: 'Read receipts',\n available: true,\n helpText: 'Know exactly when someone has read your message. No more guessing.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'calls',\n label: 'Voice & video calls',\n available: false,\n helpText:\n 'Talk face-to-face or voice-only with your matches directly inside the app, no phone number needed.',\n plans: {\n lite: false,\n basic: '3 voice + 2 video calls per day',\n premium: 'Unlimited calls',\n black: 'Unlimited calls',\n },\n },\n {\n key: 'voiceMessages',\n label: 'Voice messages in chat',\n available: false,\n helpText: 'Record and send short voice clips in chat instead of typing.',\n plans: { lite: false, basic: true, premium: true, black: true },\n },\n {\n key: 'messageBeforeMatch',\n label: 'Send a message first',\n available: true,\n helpText: 'Introduce yourself with a message before the other person swipes on you.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n\n // ── Insights ──\n {\n key: 'photoInsights',\n label: 'Photo Insights',\n available: true,\n helpText:\n 'See which of your photos gets the most likes and attention, and get tips to improve.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'viewContactNumber',\n label: 'View contact number',\n available: true,\n helpText:\n 'See the phone number of profiles who have chosen to share it. Both the user and their family contact if shared.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n\n // ── Premium perks ──\n {\n key: 'incognitoMode',\n label: 'Incognito Mode',\n available: true,\n helpText:\n 'Go invisible. Your profile is hidden from everyone except the people you choose to like.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'travelMode',\n label: 'Teleport Mode',\n available: true,\n helpText: 'Browse profiles in any city, district, or state without physically being there.',\n plans: { lite: false, basic: false, premium: true, black: true },\n },\n {\n key: 'seePublicBlackProfiles',\n label: 'Discover Black Circle profiles',\n available: true,\n helpText:\n 'See profiles of Black Circle members who have chosen to be publicly discoverable.',\n plans: {\n lite: false,\n basic: false,\n premium: true,\n black: {\n text: 'Discover Black Circle profiles',\n helpText:\n 'As a Black Circle member, you have unrestricted access to all Black Circle profiles, not just publicly discoverable ones.',\n },\n },\n },\n\n // ── Black exclusive ──\n {\n key: 'exclusiveLeague',\n label: 'The Black Circle',\n available: true,\n helpText:\n 'An exclusive community of celebrities, founders, and high-net-worth individuals. Your profile is only visible to other verified Black Circle members.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n {\n key: 'verifiedBadge',\n label: 'Verified Elite badge',\n available: true,\n helpText:\n 'A distinctive badge on your profile, granted after admin verification. Signals you are a verified Black Circle member.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n {\n key: 'vipSupport',\n label: 'Dedicated concierge',\n available: true,\n helpText:\n 'A personal matchmaking concierge who helps curate your matches and provides priority support.',\n plans: { lite: false, basic: false, premium: false, black: true },\n },\n];\n"]}
@@ -77,17 +77,18 @@ export declare const TOP_PLANS: PlanId[];
77
77
  /** Check if a plan is paid (not Lite). */
78
78
  export declare function isPaidPlan(planId: PlanId): boolean;
79
79
  /** Premium explore categories that require Premium+ to access. */
80
- export declare const PREMIUM_EXPLORE_CATEGORIES: readonly ["high-iq", "elite-institute", "nri-dating", "senior-dating", "lgbtq", "second-innings"];
81
- /** How a feature appears in UI — per-plan value can be a string (quantity), true (check), or false (locked). */
82
- /** Structured value for numeric/descriptive plan features */
83
- export interface FeatureValue {
84
- /** Quantity e.g. "10", "Unlimited", "3", "All 147", "Blurred preview" */
85
- qty: string;
86
- /** Feature noun e.g. "compliments", "swipes", "filters", "of likes" */
80
+ export declare const PREMIUM_EXPLORE_CATEGORIES: readonly ["high-iq", "elite-institute", "nri-dating", "senior-dating", "lgbtq", "second-innings", "casual-dating", "black-circle"];
81
+ /**
82
+ * Per-plan display value for a feature:
83
+ * - false -> locked (show lock icon)
84
+ * - true -> enabled (show label with checkmark)
85
+ * - "10 likes per day" -> show this display text
86
+ * - { text, helpText? } -> display text + per-plan helpText override
87
+ */
88
+ export type PlanDisplayValue = false | true | string | {
87
89
  text: string;
88
- /** Time/frequency unit — e.g. "per day", "per month". Omit if not applicable. */
89
- unit?: string;
90
- }
90
+ helpText?: string;
91
+ };
91
92
  export interface FeatureDisplayItem {
92
93
  /** Unique key matching a FeatureKey or custom display key */
93
94
  key: string;
@@ -97,11 +98,11 @@ export interface FeatureDisplayItem {
97
98
  helpText: string;
98
99
  /** Whether this feature is live. If false, hidden from UI entirely (not yet rolled out). */
99
100
  available: boolean;
100
- /** Per-plan display value: FeatureValue = structured text, true = checkmark, false = locked */
101
- plans: Record<PlanId, FeatureValue | boolean>;
101
+ /** Per-plan display value */
102
+ plans: Record<PlanId, PlanDisplayValue>;
102
103
  }
103
- /** Render a plan feature value to a single display string */
104
- export declare function renderFeatureValue(value: FeatureValue | boolean | undefined, label: string): string;
104
+ /** Render a plan display value to a single display string */
105
+ export declare function renderPlanDisplayValue(value: PlanDisplayValue | undefined, label: string): string;
105
106
  /**
106
107
  * Master feature list for plan comparison UI.
107
108
  * Now in plan-features-data.ts for cleaner separation.
@@ -1 +1 @@
1
- {"version":3,"file":"plan-limits.d.ts","sourceRoot":"","sources":["../src/plan-limits.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plan-limits.d.ts","sourceRoot":"","sources":["../src/plan-limits.ts"],"names":[],"mappings":"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"}
@@ -171,15 +171,16 @@ export const PREMIUM_EXPLORE_CATEGORIES = [
171
171
  'senior-dating',
172
172
  'lgbtq',
173
173
  'second-innings',
174
+ 'casual-dating',
175
+ 'black-circle',
174
176
  ];
175
- /** Render a plan feature value to a single display string */
176
- export function renderFeatureValue(value, label) {
177
+ /** Render a plan display value to a single display string */
178
+ export function renderPlanDisplayValue(value, label) {
177
179
  if (value == null || value === true || value === false)
178
180
  return label;
179
- const parts = [value.qty, value.text];
180
- if (value.unit)
181
- parts.push(value.unit);
182
- return parts.join(' ');
181
+ if (typeof value === 'string')
182
+ return value;
183
+ return value.text;
183
184
  }
184
185
  /**
185
186
  * Master feature list for plan comparison UI.
@@ -205,12 +206,16 @@ export function getPlanFeatureDisplay(planId) {
205
206
  else if (val === true) {
206
207
  included.push({ key: f.key, label: f.label, helpText: f.helpText, value: true });
207
208
  }
209
+ else if (typeof val === 'string') {
210
+ included.push({ key: f.key, label: f.label, helpText: f.helpText, value: val });
211
+ }
208
212
  else {
213
+ // Object with text and optional per-plan helpText override
209
214
  included.push({
210
215
  key: f.key,
211
216
  label: f.label,
212
- helpText: f.helpText,
213
- value: renderFeatureValue(val, f.label),
217
+ helpText: val.helpText ?? f.helpText,
218
+ value: val.text,
214
219
  });
215
220
  }
216
221
  }
@@ -1 +1 @@
1
- {"version":3,"file":"plan-limits.js","sourceRoot":"","sources":["../src/plan-limits.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * dating-schema — Plan limits configuration\n *\n * Single source of truth for feature gating by pricing plan.\n * Both backend middleware and frontend UI read from this config.\n *\n * 4-tier system: Lite (free) → Basic (decoy) → Premium (target) → Black (elite)\n *\n * To add/remove a gated feature:\n * 1. Add/remove the key in PlanLimits interface\n * 2. Set values for each plan in PLAN_LIMITS\n * 3. Backend: add enforceDatingPlanLimit('featureKey') middleware to the route\n * That's it — no scattered if-checks needed.\n *\n * @module dating-schema/plan-limits\n */\n\nimport { PLAN_FEATURE_DISPLAY_DATA as PLAN_FEATURE_DISPLAY_ITEMS } from './plan-features-data.js';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** The 4 pricing plans. Black is the exclusive celebrity/HNI tier. */\nexport type PlanId = 'lite' | 'basic' | 'premium' | 'black';\n\n/** Filter capability levels by plan. */\nexport type FilterLevel = 'basic' | 'advanced' | 'full';\n\n/** \"Who liked you\" visibility levels by plan. */\nexport type WhoLikedYouLevel = 'none' | 'blurred' | 'full' | 'realtime';\n\n/** Explore category access levels by plan. */\nexport type ExploreAccessLevel = 'basic' | 'premium';\n\n/** Compatibility score breakdown visibility by plan. */\nexport type ScoreBreakdownLevel = 'none' | 'score' | 'breakdown';\n\n/** All numeric limit keys (daily/periodic counters enforced server-side). */\nexport type NumericFeatureKey =\n | 'dailyLikes'\n | 'dailyCompliments'\n | 'dailyRewinds'\n | 'dailyProfileVisits'\n | 'monthlyNewChatThreads'\n | 'monthlyBoosts'\n | 'dailyVoiceCalls'\n | 'dailyVideoCalls'\n | 'voiceCallDurationMin'\n | 'videoCallDurationMin'\n | 'monthlyIntentChanges'\n | 'scoreVisibleProfiles';\n\n/** All boolean feature keys (on/off per plan). */\nexport type BooleanFeatureKey =\n | 'readReceipts'\n | 'incognitoMode'\n | 'voiceMessages'\n | 'voiceCalls'\n | 'videoCalls'\n | 'showAds'\n | 'seeProfileViewers'\n | 'messageBeforeMatch'\n | 'travelMode'\n | 'profileContentUnlock'\n | 'photoInsights'\n | 'viewContactNumber'\n | 'exclusiveLeague'\n | 'seePublicBlackProfiles';\n\n/** All string-enum feature keys. */\nexport type EnumFeatureKey = 'filterLevel' | 'whoLikedYou' | 'exploreAccess' | 'scoreBreakdown';\n\n/** Union of all feature keys that can be gated. */\nexport type FeatureKey = NumericFeatureKey | BooleanFeatureKey | EnumFeatureKey;\n\n/** Complete plan limits definition. */\nexport interface PlanLimits {\n // ── Numeric limits (daily/periodic) ──\n dailyLikes: number;\n dailyCompliments: number;\n dailyRewinds: number;\n dailyProfileVisits: number;\n monthlyNewChatThreads: number;\n monthlyBoosts: number;\n\n dailyVoiceCalls: number;\n dailyVideoCalls: number;\n voiceCallDurationMin: number;\n videoCallDurationMin: number;\n monthlyIntentChanges: number;\n scoreVisibleProfiles: number;\n\n // ── Enum limits ──\n filterLevel: FilterLevel;\n whoLikedYou: WhoLikedYouLevel;\n exploreAccess: ExploreAccessLevel;\n scoreBreakdown: ScoreBreakdownLevel;\n\n // ── Boolean flags ──\n readReceipts: boolean;\n incognitoMode: boolean;\n voiceMessages: boolean;\n voiceCalls: boolean;\n videoCalls: boolean;\n showAds: boolean;\n seeProfileViewers: boolean;\n messageBeforeMatch: boolean;\n travelMode: boolean;\n profileContentUnlock: boolean;\n photoInsights: boolean;\n viewContactNumber: boolean;\n exclusiveLeague: boolean;\n seePublicBlackProfiles: boolean;\n}\n\n// ─── Plan Limits Config ──────────────────────────────────────────────────────\n\nexport const PLAN_LIMITS: Record<PlanId, PlanLimits> = {\n // ── Lite (Free) — Hook users, limited enough to upgrade ──\n lite: {\n dailyLikes: 10,\n dailyCompliments: 1,\n dailyRewinds: 0,\n dailyProfileVisits: 20,\n monthlyNewChatThreads: Infinity, // no chat cap — matches can always chat\n monthlyBoosts: 0,\n\n dailyVoiceCalls: 0,\n dailyVideoCalls: 0,\n voiceCallDurationMin: 0,\n videoCallDurationMin: 0,\n monthlyIntentChanges: 2,\n scoreVisibleProfiles: 3,\n\n filterLevel: 'basic',\n whoLikedYou: 'none',\n exploreAccess: 'basic',\n scoreBreakdown: 'none',\n\n readReceipts: false,\n incognitoMode: false,\n voiceMessages: false,\n voiceCalls: false,\n videoCalls: false,\n showAds: true,\n seeProfileViewers: false,\n messageBeforeMatch: false,\n travelMode: false,\n profileContentUnlock: false,\n photoInsights: false,\n viewContactNumber: false,\n exclusiveLeague: false,\n seePublicBlackProfiles: false,\n },\n\n // ── Basic (DECOY) — Good enough to taste, limited enough to push Premium ──\n basic: {\n dailyLikes: 50,\n dailyCompliments: 5,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 3,\n\n dailyVoiceCalls: 3, // hidden feature — not yet rolled out\n dailyVideoCalls: 2, // hidden feature — not yet rolled out\n voiceCallDurationMin: 15, // hidden feature — not yet rolled out\n videoCallDurationMin: 10, // hidden feature — not yet rolled out\n monthlyIntentChanges: 8,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'advanced',\n whoLikedYou: 'blurred',\n exploreAccess: 'basic', // NO premium explore — key decoy differentiator\n scoreBreakdown: 'score',\n\n readReceipts: false, // key decoy limitation — only Premium gets this\n incognitoMode: false,\n voiceMessages: true, // hidden feature — not yet rolled out\n voiceCalls: true, // hidden feature — not yet rolled out\n videoCalls: true, // hidden feature — not yet rolled out\n showAds: false, // ad-free\n seeProfileViewers: false,\n messageBeforeMatch: false,\n travelMode: false,\n profileContentUnlock: true,\n photoInsights: false,\n viewContactNumber: false,\n exclusiveLeague: false,\n seePublicBlackProfiles: false,\n },\n\n // ── Premium — The aspirational tier, almost everything unlocked ──\n premium: {\n dailyLikes: 300,\n dailyCompliments: 10,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 5,\n\n dailyVoiceCalls: Infinity, // hidden feature — not yet rolled out\n dailyVideoCalls: Infinity, // hidden feature — not yet rolled out\n voiceCallDurationMin: Infinity, // hidden feature — not yet rolled out\n videoCallDurationMin: Infinity, // hidden feature — not yet rolled out\n monthlyIntentChanges: Infinity,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'full',\n whoLikedYou: 'realtime',\n exploreAccess: 'premium',\n scoreBreakdown: 'breakdown',\n\n readReceipts: true,\n incognitoMode: true,\n voiceMessages: true, // hidden feature — not yet rolled out\n voiceCalls: true, // hidden feature — not yet rolled out\n videoCalls: true, // hidden feature — not yet rolled out\n showAds: false,\n seeProfileViewers: true,\n messageBeforeMatch: true,\n travelMode: true,\n profileContentUnlock: true,\n photoInsights: true,\n viewContactNumber: true,\n exclusiveLeague: false,\n seePublicBlackProfiles: true,\n },\n\n // ── Black — Exclusive league for celebrities & HNIs ──\n black: {\n dailyLikes: Infinity,\n dailyCompliments: Infinity,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 10,\n\n dailyVoiceCalls: Infinity,\n dailyVideoCalls: Infinity,\n voiceCallDurationMin: Infinity,\n videoCallDurationMin: Infinity,\n monthlyIntentChanges: Infinity,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'full',\n whoLikedYou: 'realtime',\n exploreAccess: 'premium',\n scoreBreakdown: 'breakdown',\n\n readReceipts: true,\n incognitoMode: true,\n voiceMessages: true,\n voiceCalls: true,\n videoCalls: true,\n showAds: false,\n seeProfileViewers: true,\n messageBeforeMatch: true,\n travelMode: true,\n profileContentUnlock: true,\n photoInsights: true,\n viewContactNumber: true,\n exclusiveLeague: true,\n seePublicBlackProfiles: true,\n },\n} as const;\n\n// ─── Plan Tier Helpers ──────────────────────────────────────────────────────\n\n/** All valid plan IDs in tier order. */\nexport const PLAN_IDS: PlanId[] = ['lite', 'basic', 'premium', 'black'];\n\n/** Paid plans (Basic and above). */\nexport const PAID_PLANS: PlanId[] = ['basic', 'premium', 'black'];\n\n/** Premium plans (Premium and above). */\nexport const PREMIUM_PLANS: PlanId[] = ['premium', 'black'];\n\n/** Top-tier plans (Black only). */\nexport const TOP_PLANS: PlanId[] = ['black'];\n\n/** Check if a plan is paid (not Lite). */\nexport function isPaidPlan(planId: PlanId): boolean {\n return planId !== 'lite';\n}\n\n/** Premium explore categories that require Premium+ to access. */\nexport const PREMIUM_EXPLORE_CATEGORIES = [\n 'high-iq',\n 'elite-institute',\n 'nri-dating',\n 'senior-dating',\n 'lgbtq',\n 'second-innings',\n] as const;\n\n// ─── Feature Display Config (UI source of truth) ────────────────────────────\n\n/** How a feature appears in UI — per-plan value can be a string (quantity), true (check), or false (locked). */\n/** Structured value for numeric/descriptive plan features */\nexport interface FeatureValue {\n /** Quantity — e.g. \"10\", \"Unlimited\", \"3\", \"All 147\", \"Blurred preview\" */\n qty: string;\n /** Feature noun — e.g. \"compliments\", \"swipes\", \"filters\", \"of likes\" */\n text: string;\n /** Time/frequency unit — e.g. \"per day\", \"per month\". Omit if not applicable. */\n unit?: string;\n}\n\nexport interface FeatureDisplayItem {\n /** Unique key matching a FeatureKey or custom display key */\n key: string;\n /** Short, clear label shown when feature is locked */\n label: string;\n /** Tooltip help text explaining what this feature does */\n helpText: string;\n /** Whether this feature is live. If false, hidden from UI entirely (not yet rolled out). */\n available: boolean;\n /** Per-plan display value: FeatureValue = structured text, true = checkmark, false = locked */\n plans: Record<PlanId, FeatureValue | boolean>;\n}\n\n/** Render a plan feature value to a single display string */\nexport function renderFeatureValue(value: FeatureValue | boolean | undefined, label: string): string {\n if (value == null || value === true || value === false) return label;\n const parts = [value.qty, value.text];\n if (value.unit) parts.push(value.unit);\n return parts.join(' ');\n}\n\n/**\n * Master feature list for plan comparison UI.\n * Now in plan-features-data.ts for cleaner separation.\n */\nexport { PLAN_FEATURE_DISPLAY_DATA as PLAN_FEATURE_DISPLAY } from './plan-features-data.js';\n\n/**\n * Get features for a plan, split into included (with values) and locked.\n * Included features come first, locked features last.\n * Only includes features where `available: true` (hides unreleased features).\n */\nexport function getPlanFeatureDisplay(planId: PlanId): {\n included: { key: string; label: string; helpText: string; value: string | true }[];\n locked: { key: string; label: string; helpText: string }[];\n} {\n const included: { key: string; label: string; helpText: string; value: string | true }[] = [];\n const locked: { key: string; label: string; helpText: string }[] = [];\n\n for (const f of PLAN_FEATURE_DISPLAY_ITEMS) {\n // Skip features not yet rolled out\n if (!f.available) continue;\n\n const val = f.plans[planId];\n if (val == null || val === false) {\n locked.push({ key: f.key, label: f.label, helpText: f.helpText });\n } else if (val === true) {\n included.push({ key: f.key, label: f.label, helpText: f.helpText, value: true });\n } else {\n included.push({\n key: f.key,\n label: f.label,\n helpText: f.helpText,\n value: renderFeatureValue(val, f.label),\n });\n }\n }\n\n return { included, locked };\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Get the limits object for a plan. */\nexport function getPlanLimits(planId: PlanId): PlanLimits {\n return PLAN_LIMITS[planId];\n}\n\n/** Get a specific limit value for a plan + feature. */\nexport function getPlanLimit<K extends FeatureKey>(planId: PlanId, feature: K): PlanLimits[K] {\n return PLAN_LIMITS[planId][feature];\n}\n\n/**\n * Check if a boolean feature is enabled for a plan.\n * Returns `false` for non-boolean features.\n */\nexport function isFeatureEnabled(planId: PlanId, feature: BooleanFeatureKey): boolean {\n return PLAN_LIMITS[planId][feature];\n}\n\n/**\n * Check if a numeric feature has remaining capacity.\n * Returns `true` if the limit is Infinity or greater than current usage.\n */\nexport function hasRemainingQuota(\n planId: PlanId,\n feature: NumericFeatureKey,\n currentUsage: number,\n): boolean {\n const limit = PLAN_LIMITS[planId][feature];\n return limit === Infinity || currentUsage < limit;\n}\n\n/**\n * Get the minimum plan required for a boolean feature.\n * Returns undefined if no plan enables it.\n */\nexport function getMinPlanForFeature(feature: BooleanFeatureKey): PlanId | undefined {\n return PLAN_IDS.find((id) => PLAN_LIMITS[id][feature] === true);\n}\n"]}
1
+ {"version":3,"file":"plan-limits.js","sourceRoot":"","sources":["../src/plan-limits.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * dating-schema — Plan limits configuration\n *\n * Single source of truth for feature gating by pricing plan.\n * Both backend middleware and frontend UI read from this config.\n *\n * 4-tier system: Lite (free) → Basic (decoy) → Premium (target) → Black (elite)\n *\n * To add/remove a gated feature:\n * 1. Add/remove the key in PlanLimits interface\n * 2. Set values for each plan in PLAN_LIMITS\n * 3. Backend: add enforceDatingPlanLimit('featureKey') middleware to the route\n * That's it — no scattered if-checks needed.\n *\n * @module dating-schema/plan-limits\n */\n\nimport { PLAN_FEATURE_DISPLAY_DATA as PLAN_FEATURE_DISPLAY_ITEMS } from './plan-features-data.js';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\n/** The 4 pricing plans. Black is the exclusive celebrity/HNI tier. */\nexport type PlanId = 'lite' | 'basic' | 'premium' | 'black';\n\n/** Filter capability levels by plan. */\nexport type FilterLevel = 'basic' | 'advanced' | 'full';\n\n/** \"Who liked you\" visibility levels by plan. */\nexport type WhoLikedYouLevel = 'none' | 'blurred' | 'full' | 'realtime';\n\n/** Explore category access levels by plan. */\nexport type ExploreAccessLevel = 'basic' | 'premium';\n\n/** Compatibility score breakdown visibility by plan. */\nexport type ScoreBreakdownLevel = 'none' | 'score' | 'breakdown';\n\n/** All numeric limit keys (daily/periodic counters enforced server-side). */\nexport type NumericFeatureKey =\n | 'dailyLikes'\n | 'dailyCompliments'\n | 'dailyRewinds'\n | 'dailyProfileVisits'\n | 'monthlyNewChatThreads'\n | 'monthlyBoosts'\n | 'dailyVoiceCalls'\n | 'dailyVideoCalls'\n | 'voiceCallDurationMin'\n | 'videoCallDurationMin'\n | 'monthlyIntentChanges'\n | 'scoreVisibleProfiles';\n\n/** All boolean feature keys (on/off per plan). */\nexport type BooleanFeatureKey =\n | 'readReceipts'\n | 'incognitoMode'\n | 'voiceMessages'\n | 'voiceCalls'\n | 'videoCalls'\n | 'showAds'\n | 'seeProfileViewers'\n | 'messageBeforeMatch'\n | 'travelMode'\n | 'profileContentUnlock'\n | 'photoInsights'\n | 'viewContactNumber'\n | 'exclusiveLeague'\n | 'seePublicBlackProfiles';\n\n/** All string-enum feature keys. */\nexport type EnumFeatureKey = 'filterLevel' | 'whoLikedYou' | 'exploreAccess' | 'scoreBreakdown';\n\n/** Union of all feature keys that can be gated. */\nexport type FeatureKey = NumericFeatureKey | BooleanFeatureKey | EnumFeatureKey;\n\n/** Complete plan limits definition. */\nexport interface PlanLimits {\n // ── Numeric limits (daily/periodic) ──\n dailyLikes: number;\n dailyCompliments: number;\n dailyRewinds: number;\n dailyProfileVisits: number;\n monthlyNewChatThreads: number;\n monthlyBoosts: number;\n\n dailyVoiceCalls: number;\n dailyVideoCalls: number;\n voiceCallDurationMin: number;\n videoCallDurationMin: number;\n monthlyIntentChanges: number;\n scoreVisibleProfiles: number;\n\n // ── Enum limits ──\n filterLevel: FilterLevel;\n whoLikedYou: WhoLikedYouLevel;\n exploreAccess: ExploreAccessLevel;\n scoreBreakdown: ScoreBreakdownLevel;\n\n // ── Boolean flags ──\n readReceipts: boolean;\n incognitoMode: boolean;\n voiceMessages: boolean;\n voiceCalls: boolean;\n videoCalls: boolean;\n showAds: boolean;\n seeProfileViewers: boolean;\n messageBeforeMatch: boolean;\n travelMode: boolean;\n profileContentUnlock: boolean;\n photoInsights: boolean;\n viewContactNumber: boolean;\n exclusiveLeague: boolean;\n seePublicBlackProfiles: boolean;\n}\n\n// ─── Plan Limits Config ──────────────────────────────────────────────────────\n\nexport const PLAN_LIMITS: Record<PlanId, PlanLimits> = {\n // ── Lite (Free) — Hook users, limited enough to upgrade ──\n lite: {\n dailyLikes: 10,\n dailyCompliments: 1,\n dailyRewinds: 0,\n dailyProfileVisits: 20,\n monthlyNewChatThreads: Infinity, // no chat cap — matches can always chat\n monthlyBoosts: 0,\n\n dailyVoiceCalls: 0,\n dailyVideoCalls: 0,\n voiceCallDurationMin: 0,\n videoCallDurationMin: 0,\n monthlyIntentChanges: 2,\n scoreVisibleProfiles: 3,\n\n filterLevel: 'basic',\n whoLikedYou: 'none',\n exploreAccess: 'basic',\n scoreBreakdown: 'none',\n\n readReceipts: false,\n incognitoMode: false,\n voiceMessages: false,\n voiceCalls: false,\n videoCalls: false,\n showAds: true,\n seeProfileViewers: false,\n messageBeforeMatch: false,\n travelMode: false,\n profileContentUnlock: false,\n photoInsights: false,\n viewContactNumber: false,\n exclusiveLeague: false,\n seePublicBlackProfiles: false,\n },\n\n // ── Basic (DECOY) — Good enough to taste, limited enough to push Premium ──\n basic: {\n dailyLikes: 50,\n dailyCompliments: 5,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 3,\n\n dailyVoiceCalls: 3, // hidden feature — not yet rolled out\n dailyVideoCalls: 2, // hidden feature — not yet rolled out\n voiceCallDurationMin: 15, // hidden feature — not yet rolled out\n videoCallDurationMin: 10, // hidden feature — not yet rolled out\n monthlyIntentChanges: 8,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'advanced',\n whoLikedYou: 'blurred',\n exploreAccess: 'basic', // NO premium explore — key decoy differentiator\n scoreBreakdown: 'score',\n\n readReceipts: false, // key decoy limitation — only Premium gets this\n incognitoMode: false,\n voiceMessages: true, // hidden feature — not yet rolled out\n voiceCalls: true, // hidden feature — not yet rolled out\n videoCalls: true, // hidden feature — not yet rolled out\n showAds: false, // ad-free\n seeProfileViewers: false,\n messageBeforeMatch: false,\n travelMode: false,\n profileContentUnlock: true,\n photoInsights: false,\n viewContactNumber: false,\n exclusiveLeague: false,\n seePublicBlackProfiles: false,\n },\n\n // ── Premium — The aspirational tier, almost everything unlocked ──\n premium: {\n dailyLikes: 300,\n dailyCompliments: 10,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 5,\n\n dailyVoiceCalls: Infinity, // hidden feature — not yet rolled out\n dailyVideoCalls: Infinity, // hidden feature — not yet rolled out\n voiceCallDurationMin: Infinity, // hidden feature — not yet rolled out\n videoCallDurationMin: Infinity, // hidden feature — not yet rolled out\n monthlyIntentChanges: Infinity,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'full',\n whoLikedYou: 'realtime',\n exploreAccess: 'premium',\n scoreBreakdown: 'breakdown',\n\n readReceipts: true,\n incognitoMode: true,\n voiceMessages: true, // hidden feature — not yet rolled out\n voiceCalls: true, // hidden feature — not yet rolled out\n videoCalls: true, // hidden feature — not yet rolled out\n showAds: false,\n seeProfileViewers: true,\n messageBeforeMatch: true,\n travelMode: true,\n profileContentUnlock: true,\n photoInsights: true,\n viewContactNumber: true,\n exclusiveLeague: false,\n seePublicBlackProfiles: true,\n },\n\n // ── Black — Exclusive league for celebrities & HNIs ──\n black: {\n dailyLikes: Infinity,\n dailyCompliments: Infinity,\n dailyRewinds: Infinity,\n dailyProfileVisits: Infinity,\n monthlyNewChatThreads: Infinity,\n monthlyBoosts: 10,\n\n dailyVoiceCalls: Infinity,\n dailyVideoCalls: Infinity,\n voiceCallDurationMin: Infinity,\n videoCallDurationMin: Infinity,\n monthlyIntentChanges: Infinity,\n scoreVisibleProfiles: Infinity,\n\n filterLevel: 'full',\n whoLikedYou: 'realtime',\n exploreAccess: 'premium',\n scoreBreakdown: 'breakdown',\n\n readReceipts: true,\n incognitoMode: true,\n voiceMessages: true,\n voiceCalls: true,\n videoCalls: true,\n showAds: false,\n seeProfileViewers: true,\n messageBeforeMatch: true,\n travelMode: true,\n profileContentUnlock: true,\n photoInsights: true,\n viewContactNumber: true,\n exclusiveLeague: true,\n seePublicBlackProfiles: true,\n },\n} as const;\n\n// ─── Plan Tier Helpers ──────────────────────────────────────────────────────\n\n/** All valid plan IDs in tier order. */\nexport const PLAN_IDS: PlanId[] = ['lite', 'basic', 'premium', 'black'];\n\n/** Paid plans (Basic and above). */\nexport const PAID_PLANS: PlanId[] = ['basic', 'premium', 'black'];\n\n/** Premium plans (Premium and above). */\nexport const PREMIUM_PLANS: PlanId[] = ['premium', 'black'];\n\n/** Top-tier plans (Black only). */\nexport const TOP_PLANS: PlanId[] = ['black'];\n\n/** Check if a plan is paid (not Lite). */\nexport function isPaidPlan(planId: PlanId): boolean {\n return planId !== 'lite';\n}\n\n/** Premium explore categories that require Premium+ to access. */\nexport const PREMIUM_EXPLORE_CATEGORIES = [\n 'high-iq',\n 'elite-institute',\n 'nri-dating',\n 'senior-dating',\n 'lgbtq',\n 'second-innings',\n 'casual-dating',\n 'black-circle',\n] as const;\n\n// ─── Feature Display Config (UI source of truth) ────────────────────────────\n\n/**\n * Per-plan display value for a feature:\n * - false -> locked (show lock icon)\n * - true -> enabled (show label with checkmark)\n * - \"10 likes per day\" -> show this display text\n * - { text, helpText? } -> display text + per-plan helpText override\n */\nexport type PlanDisplayValue = false | true | string | { text: string; helpText?: string };\n\nexport interface FeatureDisplayItem {\n /** Unique key matching a FeatureKey or custom display key */\n key: string;\n /** Short, clear label shown when feature is locked */\n label: string;\n /** Tooltip help text explaining what this feature does */\n helpText: string;\n /** Whether this feature is live. If false, hidden from UI entirely (not yet rolled out). */\n available: boolean;\n /** Per-plan display value */\n plans: Record<PlanId, PlanDisplayValue>;\n}\n\n/** Render a plan display value to a single display string */\nexport function renderPlanDisplayValue(value: PlanDisplayValue | undefined, label: string): string {\n if (value == null || value === true || value === false) return label;\n if (typeof value === 'string') return value;\n return value.text;\n}\n\n/**\n * Master feature list for plan comparison UI.\n * Now in plan-features-data.ts for cleaner separation.\n */\nexport { PLAN_FEATURE_DISPLAY_DATA as PLAN_FEATURE_DISPLAY } from './plan-features-data.js';\n\n/**\n * Get features for a plan, split into included (with values) and locked.\n * Included features come first, locked features last.\n * Only includes features where `available: true` (hides unreleased features).\n */\nexport function getPlanFeatureDisplay(planId: PlanId): {\n included: { key: string; label: string; helpText: string; value: string | true }[];\n locked: { key: string; label: string; helpText: string }[];\n} {\n const included: { key: string; label: string; helpText: string; value: string | true }[] = [];\n const locked: { key: string; label: string; helpText: string }[] = [];\n\n for (const f of PLAN_FEATURE_DISPLAY_ITEMS) {\n // Skip features not yet rolled out\n if (!f.available) continue;\n\n const val = f.plans[planId];\n if (val == null || val === false) {\n locked.push({ key: f.key, label: f.label, helpText: f.helpText });\n } else if (val === true) {\n included.push({ key: f.key, label: f.label, helpText: f.helpText, value: true });\n } else if (typeof val === 'string') {\n included.push({ key: f.key, label: f.label, helpText: f.helpText, value: val });\n } else {\n // Object with text and optional per-plan helpText override\n included.push({\n key: f.key,\n label: f.label,\n helpText: val.helpText ?? f.helpText,\n value: val.text,\n });\n }\n }\n\n return { included, locked };\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Get the limits object for a plan. */\nexport function getPlanLimits(planId: PlanId): PlanLimits {\n return PLAN_LIMITS[planId];\n}\n\n/** Get a specific limit value for a plan + feature. */\nexport function getPlanLimit<K extends FeatureKey>(planId: PlanId, feature: K): PlanLimits[K] {\n return PLAN_LIMITS[planId][feature];\n}\n\n/**\n * Check if a boolean feature is enabled for a plan.\n * Returns `false` for non-boolean features.\n */\nexport function isFeatureEnabled(planId: PlanId, feature: BooleanFeatureKey): boolean {\n return PLAN_LIMITS[planId][feature];\n}\n\n/**\n * Check if a numeric feature has remaining capacity.\n * Returns `true` if the limit is Infinity or greater than current usage.\n */\nexport function hasRemainingQuota(\n planId: PlanId,\n feature: NumericFeatureKey,\n currentUsage: number,\n): boolean {\n const limit = PLAN_LIMITS[planId][feature];\n return limit === Infinity || currentUsage < limit;\n}\n\n/**\n * Get the minimum plan required for a boolean feature.\n * Returns undefined if no plan enables it.\n */\nexport function getMinPlanForFeature(feature: BooleanFeatureKey): PlanId | undefined {\n return PLAN_IDS.find((id) => PLAN_LIMITS[id][feature] === true);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dating-schema",
3
- "version": "0.43.1",
3
+ "version": "0.44.0",
4
4
  "description": "Shared Zod schemas for the Dating feature — single source of truth for API contracts, validation, and TypeScript types (frontend + backend).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",