gymmonk-schema 0.61.0 → 0.62.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/plan-features-data.d.ts +32 -31
- package/dist/plan-features-data.d.ts.map +1 -1
- package/dist/plan-features-data.js +100 -205
- package/dist/plan-features-data.js.map +1 -1
- package/dist/plan-limits.d.ts +125 -31
- package/dist/plan-limits.d.ts.map +1 -1
- package/dist/plan-limits.js +86 -53
- package/dist/plan-limits.js.map +1 -1
- package/dist/saas-catalog.d.ts +190 -58
- package/dist/saas-catalog.d.ts.map +1 -1
- package/dist/saas-catalog.js +201 -81
- package/dist/saas-catalog.js.map +1 -1
- package/dist/subscription.d.ts +2 -3
- package/dist/subscription.d.ts.map +1 -1
- package/dist/subscription.js +17 -0
- package/dist/subscription.js.map +1 -1
- package/package.json +1 -1
|
@@ -6,42 +6,43 @@
|
|
|
6
6
|
*
|
|
7
7
|
* The split is not tidiness. The two lists are different sizes and always will
|
|
8
8
|
* be: some rows cover several limits at once (one "staff you can add" line
|
|
9
|
-
* stands for four per-role caps), and
|
|
9
|
+
* stands for four per-role caps), and MOST limits never earn a row at all.
|
|
10
10
|
* Forcing one array to be both produces either a card full of plumbing or an
|
|
11
11
|
* enforcement set with holes in it.
|
|
12
12
|
*
|
|
13
|
-
* ──
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
13
|
+
* ── THIS LIST IS A PRODUCT DECISION, NOT AN INVENTORY ───────────────────────
|
|
14
|
+
* ⚠️ It is DELIBERATELY SHORT, and it was cut down on purpose. Do not add a row
|
|
15
|
+
* because the product happens to have the feature.
|
|
16
|
+
*
|
|
17
|
+
* It previously carried 28 rows — the member app, QR check-in, self-join,
|
|
18
|
+
* search discovery, the public gym page, custom exercises, branches, staff
|
|
19
|
+
* duty/pay, the equipment register, the live dashboard, expiring-membership
|
|
20
|
+
* alerts, peak-load alerts, equipment usage, the trial and support tiers. Every
|
|
21
|
+
* one of them is real and shipped. None of them was on the list the product
|
|
22
|
+
* owner asked to sell on, and together they buried the four lines that actually
|
|
23
|
+
* decide the sale.
|
|
24
|
+
*
|
|
25
|
+
* The rule is now explicit: a row exists here ONLY if it is on that list. If
|
|
26
|
+
* you think something else deserves selling, that is a conversation with the
|
|
27
|
+
* product owner, not an edit to this array.
|
|
27
28
|
*
|
|
28
29
|
* ── ORDER IS THE ARGUMENT ───────────────────────────────────────────────────
|
|
29
|
-
* Rows render in array order
|
|
30
|
-
* you
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
30
|
+
* Rows render in array order: who your members are, what you can do with them,
|
|
31
|
+
* what you can build, who helps you run it, what you can see, how you talk to
|
|
32
|
+
* them. The first three lines carry the whole board — nothing is metered, thirty
|
|
33
|
+
* are workable for free, and the tools arrive with the subscription.
|
|
34
|
+
*
|
|
35
|
+
* ── EVERY ROW APPEARS ON EVERY CARD ─────────────────────────────────────────
|
|
36
|
+
* `getPlanFeatureDisplay` splits them into included and locked. A card that
|
|
37
|
+
* listed only what a tier includes would state the overlap and hide the gap, so
|
|
38
|
+
* the upgrade case would have to be made on a comparison page nobody opens.
|
|
39
|
+
*
|
|
40
|
+
* ⚠️ Two rows below are NOT BUILT — diet plans and the advanced-stats bundle's
|
|
41
|
+
* equipment usage. They are shown because the tiers are designed around them
|
|
42
|
+
* and they are committed work. Flip `available` to `false` and a row vanishes
|
|
43
|
+
* from every card at once, which is the lever to pull if either slips: a card
|
|
44
|
+
* promising a feature the customer cannot open is the fastest route to a refund
|
|
45
|
+
* request, and the refund policy is already published.
|
|
45
46
|
*
|
|
46
47
|
* @module gymmonk-schema/plan-features-data
|
|
47
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-features-data.d.ts","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"plan-features-data.d.ts","sourceRoot":"","sources":["../src/plan-features-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,eAAO,MAAM,yBAAyB,EAAE,kBAAkB,EA0LzD,CAAC"}
|
|
@@ -6,42 +6,43 @@
|
|
|
6
6
|
*
|
|
7
7
|
* The split is not tidiness. The two lists are different sizes and always will
|
|
8
8
|
* be: some rows cover several limits at once (one "staff you can add" line
|
|
9
|
-
* stands for four per-role caps), and
|
|
9
|
+
* stands for four per-role caps), and MOST limits never earn a row at all.
|
|
10
10
|
* Forcing one array to be both produces either a card full of plumbing or an
|
|
11
11
|
* enforcement set with holes in it.
|
|
12
12
|
*
|
|
13
|
-
* ──
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* it is worth.
|
|
13
|
+
* ── THIS LIST IS A PRODUCT DECISION, NOT AN INVENTORY ───────────────────────
|
|
14
|
+
* ⚠️ It is DELIBERATELY SHORT, and it was cut down on purpose. Do not add a row
|
|
15
|
+
* because the product happens to have the feature.
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* the
|
|
25
|
-
*
|
|
26
|
-
*
|
|
17
|
+
* It previously carried 28 rows — the member app, QR check-in, self-join,
|
|
18
|
+
* search discovery, the public gym page, custom exercises, branches, staff
|
|
19
|
+
* duty/pay, the equipment register, the live dashboard, expiring-membership
|
|
20
|
+
* alerts, peak-load alerts, equipment usage, the trial and support tiers. Every
|
|
21
|
+
* one of them is real and shipped. None of them was on the list the product
|
|
22
|
+
* owner asked to sell on, and together they buried the four lines that actually
|
|
23
|
+
* decide the sale.
|
|
24
|
+
*
|
|
25
|
+
* The rule is now explicit: a row exists here ONLY if it is on that list. If
|
|
26
|
+
* you think something else deserves selling, that is a conversation with the
|
|
27
|
+
* product owner, not an edit to this array.
|
|
27
28
|
*
|
|
28
29
|
* ── ORDER IS THE ARGUMENT ───────────────────────────────────────────────────
|
|
29
|
-
* Rows render in array order
|
|
30
|
-
* you
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* take payment — what it cannot do is see the aggregate.
|
|
30
|
+
* Rows render in array order: who your members are, what you can do with them,
|
|
31
|
+
* what you can build, who helps you run it, what you can see, how you talk to
|
|
32
|
+
* them. The first three lines carry the whole board — nothing is metered, thirty
|
|
33
|
+
* are workable for free, and the tools arrive with the subscription.
|
|
34
34
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* ── EVERY ROW APPEARS ON EVERY CARD ─────────────────────────────────────────
|
|
36
|
+
* `getPlanFeatureDisplay` splits them into included and locked. A card that
|
|
37
|
+
* listed only what a tier includes would state the overlap and hide the gap, so
|
|
38
|
+
* the upgrade case would have to be made on a comparison page nobody opens.
|
|
39
39
|
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
40
|
+
* ⚠️ Two rows below are NOT BUILT — diet plans and the advanced-stats bundle's
|
|
41
|
+
* equipment usage. They are shown because the tiers are designed around them
|
|
42
|
+
* and they are committed work. Flip `available` to `false` and a row vanishes
|
|
43
|
+
* from every card at once, which is the lever to pull if either slips: a card
|
|
44
|
+
* promising a feature the customer cannot open is the fastest route to a refund
|
|
45
|
+
* request, and the refund policy is already published.
|
|
45
46
|
*
|
|
46
47
|
* @module gymmonk-schema/plan-features-data
|
|
47
48
|
*/
|
|
@@ -49,265 +50,159 @@ export const PLAN_FEATURE_DISPLAY_DATA = [
|
|
|
49
50
|
// ═══ Your members ═══════════════════════════════════════════════════════
|
|
50
51
|
{
|
|
51
52
|
key: 'members',
|
|
52
|
-
label: '
|
|
53
|
+
label: 'Add unlimited members',
|
|
53
54
|
helpText: 'Members are never counted for billing, on any plan. Growing your gym never increases what you pay us.',
|
|
54
55
|
available: true,
|
|
55
56
|
plans: {
|
|
56
57
|
free: {
|
|
57
|
-
text: '
|
|
58
|
-
helpText: 'Never metered. A fair-use policy applies above 500 active members,
|
|
58
|
+
text: 'Add unlimited members*',
|
|
59
|
+
helpText: 'Never metered, and nothing ever stops you adding one — not even on the free plan. A fair-use policy applies above 500 active members, which is a conversation and not a cut-off.',
|
|
59
60
|
},
|
|
60
|
-
|
|
61
|
-
pro: 'Unlimited members',
|
|
61
|
+
pro: 'Add unlimited members',
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
|
-
key: '
|
|
66
|
-
label: '
|
|
67
|
-
helpText: '
|
|
68
|
-
available: true,
|
|
69
|
-
plans: { free: true, starter: true, pro: true },
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
key: 'selfJoin',
|
|
73
|
-
label: 'Members join themselves by QR or gym code',
|
|
74
|
-
helpText: 'You create the record, they claim it with their own login. No data entry for you, and no password of theirs for you to hold.',
|
|
65
|
+
key: 'manageableMembers',
|
|
66
|
+
label: 'Manage unlimited members',
|
|
67
|
+
helpText: 'How many of your members you can open, edit, collect from and track. Everyone you add always keeps their app, their ID card and their check-in — this is about what YOU can work with.',
|
|
75
68
|
available: true,
|
|
76
|
-
plans: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
plans: {
|
|
70
|
+
free: {
|
|
71
|
+
text: 'Manage up to 30 members',
|
|
72
|
+
helpText: 'Your first 30 members by join date are fully workable. Members past the thirtieth still join, still check in and still use the app in full — you just cannot open them from the console until you subscribe. Nothing is deleted, and they all appear the moment you do.',
|
|
73
|
+
},
|
|
74
|
+
pro: {
|
|
75
|
+
text: 'Manage unlimited members',
|
|
76
|
+
helpText: 'Your whole roster, however large, open and workable from the console.',
|
|
77
|
+
},
|
|
78
|
+
},
|
|
84
79
|
},
|
|
85
80
|
{
|
|
86
|
-
key: '
|
|
87
|
-
label: '
|
|
88
|
-
helpText: '
|
|
81
|
+
key: 'memberDirectoryTools',
|
|
82
|
+
label: 'Advanced member filters',
|
|
83
|
+
helpText: 'Cut the roster the way you actually work instead of scrolling it: filter by due date, overdue, membership plan, status or joining date, sort by due date, join date or name, and search by name or phone. This is what turns a long roster into a morning’s work.',
|
|
89
84
|
available: true,
|
|
90
85
|
plans: {
|
|
91
|
-
free:
|
|
92
|
-
|
|
93
|
-
pro: '1 year of attendance history',
|
|
86
|
+
free: false,
|
|
87
|
+
pro: 'Advanced member filters',
|
|
94
88
|
},
|
|
95
89
|
},
|
|
96
|
-
// ═══
|
|
90
|
+
// ═══ Attendance ═════════════════════════════════════════════════════════
|
|
97
91
|
{
|
|
98
|
-
key: '
|
|
99
|
-
label: '
|
|
100
|
-
helpText: '
|
|
92
|
+
key: 'attendanceTracking',
|
|
93
|
+
label: 'Attendance tracking',
|
|
94
|
+
helpText: 'Who trained and when, per member and per day, from QR check-ins at the door. Your members always see their own attendance in the app whatever your plan — this row is the OWNER’S record of it.',
|
|
101
95
|
available: true,
|
|
102
96
|
plans: {
|
|
103
97
|
free: false,
|
|
104
|
-
|
|
105
|
-
pro: 'Recommended in GymMonk search',
|
|
98
|
+
pro: 'Attendance tracking',
|
|
106
99
|
},
|
|
107
100
|
},
|
|
108
101
|
{
|
|
109
|
-
key: '
|
|
110
|
-
label: '
|
|
111
|
-
helpText: 'A
|
|
112
|
-
// ⚠️ NOT BUILT — shown deliberately. No public routes, no SEO metadata, no
|
|
113
|
-
// LocalBusiness markup exist yet. Listed because the paid tiers are being
|
|
114
|
-
// designed around it and the public gym pages are a committed build. It MUST
|
|
115
|
-
// ship before this board is public.
|
|
102
|
+
key: 'attendanceHistoryMonths',
|
|
103
|
+
label: '1 year of attendance history',
|
|
104
|
+
helpText: 'A full year back, which covers every renewal conversation you will ever have: who has stopped coming, who came all year, and who lapsed the month before they cancelled. Older records are hidden, never deleted — they come back in full the moment you upgrade.',
|
|
116
105
|
available: true,
|
|
117
106
|
plans: {
|
|
118
107
|
free: false,
|
|
119
|
-
|
|
120
|
-
pro: 'Found in Google and AI search',
|
|
108
|
+
pro: '1 year of attendance history',
|
|
121
109
|
},
|
|
122
110
|
},
|
|
123
111
|
// ═══ What you can build ═════════════════════════════════════════════════
|
|
124
112
|
{
|
|
125
113
|
key: 'membershipPlans',
|
|
126
|
-
label: '
|
|
127
|
-
helpText: '
|
|
114
|
+
label: 'Add unlimited membership plans',
|
|
115
|
+
helpText: 'The plans your members buy — monthly, quarterly, annual, personal training, whatever you price. Each carries its own duration, fee and joining fee.',
|
|
128
116
|
available: true,
|
|
129
117
|
plans: {
|
|
130
|
-
free:
|
|
131
|
-
|
|
132
|
-
pro: 'Unlimited membership plans',
|
|
118
|
+
free: false,
|
|
119
|
+
pro: 'Add unlimited membership plans',
|
|
133
120
|
},
|
|
134
121
|
},
|
|
135
122
|
{
|
|
136
123
|
key: 'workoutPlans',
|
|
137
|
-
label: '
|
|
138
|
-
helpText: 'Build
|
|
124
|
+
label: 'Create unlimited custom workout plans',
|
|
125
|
+
helpText: 'Build your own routines from the exercise library, assign them to a member, and they appear in that member’s app with videos and set-by-set tracking.',
|
|
139
126
|
available: true,
|
|
140
127
|
plans: {
|
|
141
128
|
free: false,
|
|
142
|
-
|
|
143
|
-
pro: 'Unlimited custom workout plans',
|
|
129
|
+
pro: 'Create unlimited custom workout plans',
|
|
144
130
|
},
|
|
145
131
|
},
|
|
146
132
|
{
|
|
147
133
|
key: 'dietPlans',
|
|
148
|
-
label: '
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// Listed because diet plans are a committed part of the product and the
|
|
152
|
-
// Starter allowance is designed around them. MUST ship before launch.
|
|
153
|
-
available: true,
|
|
154
|
-
plans: {
|
|
155
|
-
free: false,
|
|
156
|
-
starter: '3 custom diet plans',
|
|
157
|
-
pro: 'Unlimited custom diet plans',
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
key: 'customExercises',
|
|
162
|
-
label: 'Your own custom exercises',
|
|
163
|
-
helpText: 'Add the movements your gym runs that the GymMonk library does not carry, and use them in your plans.',
|
|
134
|
+
label: 'Create unlimited custom diet plans',
|
|
135
|
+
// ⚠️ NOT BUILT. Committed work — see the module note.
|
|
136
|
+
helpText: 'Build meal plans from the food library with calories and macros worked out for you, and assign them to a member alongside their training.',
|
|
164
137
|
available: true,
|
|
165
138
|
plans: {
|
|
166
139
|
free: false,
|
|
167
|
-
|
|
168
|
-
pro: 'Unlimited custom exercises',
|
|
140
|
+
pro: 'Create unlimited custom diet plans',
|
|
169
141
|
},
|
|
170
142
|
},
|
|
171
|
-
// ═══
|
|
172
|
-
{
|
|
173
|
-
key: 'centers',
|
|
174
|
-
label: 'Centers',
|
|
175
|
-
helpText: 'Branches under one gym account, each with its own roster, staff, QR poster and numbers.',
|
|
176
|
-
available: true,
|
|
177
|
-
plans: { free: '1 center', starter: '1 center', pro: '2 centers' },
|
|
178
|
-
},
|
|
143
|
+
// ═══ Who runs it with you ═══════════════════════════════════════════════
|
|
179
144
|
{
|
|
180
145
|
key: 'staff',
|
|
181
|
-
label: '
|
|
182
|
-
helpText: '
|
|
146
|
+
label: 'Add unlimited staff members',
|
|
147
|
+
helpText: 'Trainers, managers, front desk and cleaning staff, each with their own login and only the access their role needs. Nobody shares the owner’s account.',
|
|
183
148
|
available: true,
|
|
184
149
|
plans: {
|
|
185
150
|
free: false,
|
|
186
|
-
|
|
187
|
-
text: '1 trainer and 1 manager',
|
|
188
|
-
helpText: 'Two logins beside yours. Reception and cleaning staff need Pro — worth knowing, because the front desk is often who most wants one.',
|
|
189
|
-
},
|
|
190
|
-
pro: 'Unlimited trainers, managers, reception and cleaning staff',
|
|
151
|
+
pro: 'Add unlimited staff members',
|
|
191
152
|
},
|
|
192
153
|
},
|
|
193
|
-
{
|
|
194
|
-
key: 'staffOperations',
|
|
195
|
-
label: 'Staff duty clock, attendance and pay',
|
|
196
|
-
helpText: 'Who is on the floor right now, who worked which days, and what each of them is owed.',
|
|
197
|
-
available: true,
|
|
198
|
-
plans: { free: false, starter: true, pro: true },
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
key: 'equipmentRegister',
|
|
202
|
-
label: 'Equipment register',
|
|
203
|
-
helpText: 'What each center holds, by category, with quantity and condition, so you know what needs servicing and what needs replacing.',
|
|
204
|
-
available: true,
|
|
205
|
-
plans: { free: false, starter: true, pro: true },
|
|
206
|
-
},
|
|
207
154
|
// ═══ Your numbers ═══════════════════════════════════════════════════════
|
|
208
|
-
{
|
|
209
|
-
key: 'liveDashboard',
|
|
210
|
-
label: 'Live dashboard: members, who is in right now, birthdays',
|
|
211
|
-
helpText: 'The three counts that tell you how today is going, the moment you open the app. On every plan.',
|
|
212
|
-
available: true,
|
|
213
|
-
plans: { free: true, starter: true, pro: true },
|
|
214
|
-
},
|
|
215
155
|
{
|
|
216
156
|
key: 'revenueInsight',
|
|
217
|
-
label: '
|
|
218
|
-
helpText: '
|
|
157
|
+
label: 'Full revenue tracking',
|
|
158
|
+
helpText: 'The full year of collections broken down by month, by membership plan and by payment method, with renewals and joining fees separated — so you can see which plan actually earns and which one just looks busy.',
|
|
219
159
|
available: true,
|
|
220
160
|
plans: {
|
|
221
161
|
free: false,
|
|
222
|
-
|
|
223
|
-
text: "Today and this month's revenue",
|
|
224
|
-
helpText: 'The two headline numbers on your dashboard. The year-long trend and the breakdown by what sold it are on Pro.',
|
|
225
|
-
},
|
|
226
|
-
pro: 'Full revenue trends, by day, week, month and category',
|
|
162
|
+
pro: 'Full revenue tracking',
|
|
227
163
|
},
|
|
228
164
|
},
|
|
229
165
|
{
|
|
230
|
-
key: '
|
|
231
|
-
label: '
|
|
232
|
-
|
|
166
|
+
key: 'advancedInsights',
|
|
167
|
+
label: 'Advanced dashboard stats',
|
|
168
|
+
// ⚠️ The tooltip is the row. It is the one place the whole insight suite is
|
|
169
|
+
// named, so trimming it for length removes the reason to buy the tier.
|
|
170
|
+
helpText: 'Crowd load by hour and by weekday so you can staff your real peaks; member demographics by age and gender; attendance trends and who is slipping; retention and churn; membership plan mix; expiring and overdue counts; and equipment usage worked out from the workouts you actually assign.',
|
|
233
171
|
available: true,
|
|
234
172
|
plans: {
|
|
235
173
|
free: false,
|
|
236
|
-
|
|
237
|
-
text: 'Crowd load by hour',
|
|
238
|
-
helpText: "The shape of your day, hour by hour. Pro splits it into a separate curve for each weekday — Monday's rush is not Saturday's.",
|
|
239
|
-
},
|
|
240
|
-
pro: 'Crowd load by hour, and peak hours for every weekday',
|
|
174
|
+
pro: 'Advanced dashboard stats',
|
|
241
175
|
},
|
|
242
176
|
},
|
|
177
|
+
// ═══ Talking to your members ════════════════════════════════════════════
|
|
243
178
|
{
|
|
244
|
-
key: '
|
|
245
|
-
label: '
|
|
246
|
-
helpText: '
|
|
179
|
+
key: 'monthlyAnnouncements',
|
|
180
|
+
label: 'Unlimited announcements every month',
|
|
181
|
+
helpText: 'A message to everyone at a center at once — a holiday, new timings, a festival offer. It lands in the app of every member you have.',
|
|
247
182
|
available: true,
|
|
248
183
|
plans: {
|
|
249
|
-
free:
|
|
250
|
-
|
|
251
|
-
text: 'Attendance trends, weekly and monthly',
|
|
252
|
-
helpText: 'The trend line over time. Which plans sell and who buys them is on Pro.',
|
|
253
|
-
},
|
|
254
|
-
pro: 'Attendance trends, plan mix and member demographics',
|
|
184
|
+
free: '1 announcement per month',
|
|
185
|
+
pro: 'Unlimited announcements every month',
|
|
255
186
|
},
|
|
256
187
|
},
|
|
257
188
|
{
|
|
258
|
-
key: '
|
|
259
|
-
label: '
|
|
260
|
-
helpText: '
|
|
261
|
-
available: true,
|
|
262
|
-
plans: { free: false, starter: true, pro: true },
|
|
263
|
-
},
|
|
264
|
-
{
|
|
265
|
-
key: 'peakLoadAlerts',
|
|
266
|
-
label: 'Told when to put extra staff on the floor',
|
|
267
|
-
helpText: 'An alert when one window is carrying most of the week’s check-ins, so you staff it before your members complain about it.',
|
|
268
|
-
available: true,
|
|
269
|
-
plans: { free: false, starter: false, pro: true },
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
key: 'machineUsage',
|
|
273
|
-
label: 'Machine usage: which equipment actually gets used',
|
|
274
|
-
helpText: 'Derived from the workouts you assign, so you buy the second squat rack instead of the second treadmill.',
|
|
275
|
-
// ⚠️ NOT BUILT — shown deliberately. Needs an exercise->equipment link that
|
|
276
|
-
// does not exist; the card renders its own empty state today. See the TODO
|
|
277
|
-
// in insights.service. It is the strongest Pro line on the board, so it is
|
|
278
|
-
// listed — but an empty chart on a paid tier is a refund request.
|
|
279
|
-
available: true,
|
|
280
|
-
plans: { free: false, starter: false, pro: true },
|
|
281
|
-
},
|
|
282
|
-
// ═══ Talking to members ═════════════════════════════════════════════════
|
|
283
|
-
{
|
|
284
|
-
key: 'monthlyAnnouncements',
|
|
285
|
-
label: 'Announcements',
|
|
286
|
-
helpText: 'Push a message to every member of a center at once. It lands in their app and on their phone.',
|
|
189
|
+
key: 'inAppNotifications',
|
|
190
|
+
label: 'Unlimited in-app notifications',
|
|
191
|
+
helpText: 'Fee reminders, plan expiry and check-in confirmations delivered inside your members’ app, with no monthly ceiling and nothing to pay per message.',
|
|
287
192
|
available: true,
|
|
288
193
|
plans: {
|
|
289
|
-
free:
|
|
290
|
-
|
|
291
|
-
pro: 'Unlimited announcements',
|
|
194
|
+
free: false,
|
|
195
|
+
pro: 'Unlimited in-app notifications',
|
|
292
196
|
},
|
|
293
197
|
},
|
|
294
|
-
// ═══ Trial and support ══════════════════════════════════════════════════
|
|
295
198
|
{
|
|
296
|
-
key: '
|
|
297
|
-
label: '
|
|
298
|
-
helpText: '
|
|
299
|
-
available: true,
|
|
300
|
-
plans: { free: false, starter: '14-day free trial', pro: '14-day free trial' },
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
key: 'support',
|
|
304
|
-
label: 'Support',
|
|
305
|
-
helpText: 'How quickly you hear back when something is wrong.',
|
|
199
|
+
key: 'whatsappLateFeeNotices',
|
|
200
|
+
label: 'Up to 150 WhatsApp late-fee notifications',
|
|
201
|
+
helpText: 'For the member who has stopped opening the app: a reminder about an overdue fee, sent to their WhatsApp from your gym. Up to 150 a month across your whole gym — WhatsApp charges for every conversation, which is why this one has a number on it while in-app reminders do not.',
|
|
306
202
|
available: true,
|
|
307
203
|
plans: {
|
|
308
|
-
free:
|
|
309
|
-
|
|
310
|
-
pro: 'Priority support, within 24 hours',
|
|
204
|
+
free: false,
|
|
205
|
+
pro: 'Up to 150 WhatsApp late-fee notifications',
|
|
311
206
|
},
|
|
312
207
|
},
|
|
313
208
|
];
|
|
@@ -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 * gymmonk-schema — SaaS plan feature display\n * ==========================================\n * What a pricing card SAYS, kept apart from what the server ENFORCES\n * (`plan-limits.ts`), exactly as `dating-schema` splits them.\n *\n * The split is not tidiness. The two lists are different sizes and always will\n * be: some rows cover several limits at once (one \"staff you can add\" line\n * stands for four per-role caps), and some limits will never earn a row.\n * Forcing one array to be both produces either a card full of plumbing or an\n * enforcement set with holes in it.\n *\n * ── WHAT EARNS A ROW ────────────────────────────────────────────────────────\n * A row belongs here only if an owner would say \"I would pay for that\" or \"I\n * cannot run without it\". Everything else is how the software works, not what\n * it is worth.\n *\n * So these are deliberately ABSENT, and should stay absent: opening hours,\n * address and map pin, social links, photos per center, editing a member,\n * regenerating an invite code, roster search, activate/suspend, appearance and\n * language settings, MPIN, assign/pause/renew/cancel, recording cash or UPI,\n * receipt history, today's attendance list, marking an exercise done, plan\n * colours, undo-a-deletion, the feedback inbox, buddies and member chat, and\n * the exercise library. Every gym app has them; nobody has ever chosen software\n * because it let them enter an address. Several are also free on every tier, so\n * listing them adds three identical ticks and no information.\n *\n * ── ORDER IS THE ARGUMENT ───────────────────────────────────────────────────\n * Rows render in array order, so this sequence is the story a card tells: what\n * you get for your members, how people find you, what you can build, who helps\n * you run it, what you can see, and how you talk to them. Money-adjacent rows\n * sit in \"Your numbers\" rather than up top, because the free tier can already\n * take payment — what it cannot do is see the aggregate.\n *\n * ⚠️ `available: false` HIDES a row from every card, and NOTHING currently uses\n * it. Three rows below — the public gym page, diet plans and machine usage — are\n * NOT BUILT and are shown anyway, because the tiers are designed around them and\n * they are committed work. Each carries a ⚠️ at its own definition.\n *\n * That is a deliberate, reversible risk: a pricing card that lists a feature the\n * customer cannot open is the fastest route to a refund request, and the refund\n * policy is already published. If any of the three slips, flip its `available`\n * to `false` and it disappears from every card at once — one edit, no marketing\n * copy to chase.\n *\n * @module gymmonk-schema/plan-features-data\n */\n\nimport type { FeatureDisplayItem } from './plan-limits.js';\n\nexport const PLAN_FEATURE_DISPLAY_DATA: FeatureDisplayItem[] = [\n // ═══ Your members ═══════════════════════════════════════════════════════\n\n {\n key: 'members',\n label: 'Unlimited members',\n helpText:\n 'Members are never counted for billing, on any plan. Growing your gym never increases what you pay us.',\n available: true,\n plans: {\n free: {\n text: 'Unlimited members*',\n helpText:\n 'Never metered. A fair-use policy applies above 500 active members, and nothing ever stops you adding one.',\n },\n starter: 'Unlimited members',\n pro: 'Unlimited members',\n },\n },\n {\n key: 'memberApp',\n label: 'Member app with digital ID card',\n helpText:\n 'Your members get the GymMonk app free on every plan: their ID card, their plan, their training, their check-in history and their buddies. It belongs to them, not to your subscription.',\n available: true,\n plans: { free: true, starter: true, pro: true },\n },\n {\n key: 'selfJoin',\n label: 'Members join themselves by QR or gym code',\n helpText:\n 'You create the record, they claim it with their own login. No data entry for you, and no password of theirs for you to hold.',\n available: true,\n plans: { free: true, starter: true, pro: true },\n },\n {\n key: 'qrCheckIn',\n label: 'QR check-in, no register book',\n helpText:\n 'Print one poster per center. Members scan it with their own phone camera on the way in and on the way out.',\n available: true,\n plans: { free: true, starter: true, pro: true },\n },\n {\n key: 'attendanceHistoryMonths',\n label: 'Attendance history',\n helpText:\n 'How far back YOU can look. Older records are hidden, never deleted — they come back in full the moment you upgrade, and a member always sees their own attendance whatever your plan.',\n available: true,\n plans: {\n free: '1 month of attendance history',\n starter: '3 months of attendance history',\n pro: '1 year of attendance history',\n },\n },\n\n // ═══ Getting found ══════════════════════════════════════════════════════\n\n {\n key: 'discovery',\n label: 'Recommended in GymMonk search',\n helpText:\n 'Every gym on GymMonk is listed. Paid gyms surface at the top of the results people actually look at.',\n available: true,\n plans: {\n free: false,\n starter: 'Recommended in GymMonk search',\n pro: 'Recommended in GymMonk search',\n },\n },\n {\n key: 'publicGymPage',\n label: 'Found in Google and AI search',\n helpText:\n 'A public page for your gym and every center — hours, address, what you offer — crawlable by Google and readable by AI assistants. The only thing here that brings you new members rather than organising the ones you have.',\n // ⚠️ NOT BUILT — shown deliberately. No public routes, no SEO metadata, no\n // LocalBusiness markup exist yet. Listed because the paid tiers are being\n // designed around it and the public gym pages are a committed build. It MUST\n // ship before this board is public.\n available: true,\n plans: {\n free: false,\n starter: 'Found in Google and AI search',\n pro: 'Found in Google and AI search',\n },\n },\n\n // ═══ What you can build ═════════════════════════════════════════════════\n\n {\n key: 'membershipPlans',\n label: 'Membership plans you sell',\n helpText: 'Your own durations, prices and inclusions, sold to members from inside their app.',\n available: true,\n plans: {\n free: '2 membership plans',\n starter: '5 membership plans',\n pro: 'Unlimited membership plans',\n },\n },\n {\n key: 'workoutPlans',\n label: 'Custom workout plans',\n helpText:\n 'Build a week of training day by day from the exercise library, then give it to a member. They open their app and see exactly what you set.',\n available: true,\n plans: {\n free: false,\n starter: '3 custom workout plans',\n pro: 'Unlimited custom workout plans',\n },\n },\n {\n key: 'dietPlans',\n label: 'Custom diet plans',\n helpText: 'The same as workout plans, for what your members eat.',\n // ⚠️ NOT BUILT — shown deliberately. No diet module exists in the backend.\n // Listed because diet plans are a committed part of the product and the\n // Starter allowance is designed around them. MUST ship before launch.\n available: true,\n plans: {\n free: false,\n starter: '3 custom diet plans',\n pro: 'Unlimited custom diet plans',\n },\n },\n {\n key: 'customExercises',\n label: 'Your own custom exercises',\n helpText:\n 'Add the movements your gym runs that the GymMonk library does not carry, and use them in your plans.',\n available: true,\n plans: {\n free: false,\n starter: '10 custom exercises',\n pro: 'Unlimited custom exercises',\n },\n },\n\n // ═══ Your team and branches ═════════════════════════════════════════════\n\n {\n key: 'centers',\n label: 'Centers',\n helpText:\n 'Branches under one gym account, each with its own roster, staff, QR poster and numbers.',\n available: true,\n plans: { free: '1 center', starter: '1 center', pro: '2 centers' },\n },\n {\n key: 'staff',\n label: 'Staff you can add',\n helpText:\n 'Each one gets their own login and their own view of the app, limited to their job — the front desk can take a check-in without ever seeing your revenue.',\n available: true,\n plans: {\n free: false,\n starter: {\n text: '1 trainer and 1 manager',\n helpText:\n 'Two logins beside yours. Reception and cleaning staff need Pro — worth knowing, because the front desk is often who most wants one.',\n },\n pro: 'Unlimited trainers, managers, reception and cleaning staff',\n },\n },\n {\n key: 'staffOperations',\n label: 'Staff duty clock, attendance and pay',\n helpText:\n 'Who is on the floor right now, who worked which days, and what each of them is owed.',\n available: true,\n plans: { free: false, starter: true, pro: true },\n },\n {\n key: 'equipmentRegister',\n label: 'Equipment register',\n helpText:\n 'What each center holds, by category, with quantity and condition, so you know what needs servicing and what needs replacing.',\n available: true,\n plans: { free: false, starter: true, pro: true },\n },\n\n // ═══ Your numbers ═══════════════════════════════════════════════════════\n\n {\n key: 'liveDashboard',\n label: 'Live dashboard: members, who is in right now, birthdays',\n helpText:\n 'The three counts that tell you how today is going, the moment you open the app. On every plan.',\n available: true,\n plans: { free: true, starter: true, pro: true },\n },\n {\n key: 'revenueInsight',\n label: 'Revenue',\n helpText:\n 'What your gym is actually earning. Free shows no rupee figure anywhere — you can still take payment and see who owes what, you just cannot see the totals.',\n available: true,\n plans: {\n free: false,\n starter: {\n text: \"Today and this month's revenue\",\n helpText:\n 'The two headline numbers on your dashboard. The year-long trend and the breakdown by what sold it are on Pro.',\n },\n pro: 'Full revenue trends, by day, week, month and category',\n },\n },\n {\n key: 'crowdInsight',\n label: 'Crowd load by hour',\n helpText:\n 'How many people come at each hour, so you know when the floor fills up and your members know when to avoid it.',\n available: true,\n plans: {\n free: false,\n starter: {\n text: 'Crowd load by hour',\n helpText:\n \"The shape of your day, hour by hour. Pro splits it into a separate curve for each weekday — Monday's rush is not Saturday's.\",\n },\n pro: 'Crowd load by hour, and peak hours for every weekday',\n },\n },\n {\n key: 'memberInsight',\n label: 'Attendance and member trends',\n helpText: 'Whether the gym is filling up or emptying out, and who is actually in it.',\n available: true,\n plans: {\n free: false,\n starter: {\n text: 'Attendance trends, weekly and monthly',\n helpText: 'The trend line over time. Which plans sell and who buys them is on Pro.',\n },\n pro: 'Attendance trends, plan mix and member demographics',\n },\n },\n {\n key: 'expiringAlerts',\n label: 'Told which memberships expire this week',\n helpText:\n 'The renewal you would otherwise notice a month after it lapsed, on your dashboard before it does.',\n available: true,\n plans: { free: false, starter: true, pro: true },\n },\n {\n key: 'peakLoadAlerts',\n label: 'Told when to put extra staff on the floor',\n helpText:\n 'An alert when one window is carrying most of the week’s check-ins, so you staff it before your members complain about it.',\n available: true,\n plans: { free: false, starter: false, pro: true },\n },\n {\n key: 'machineUsage',\n label: 'Machine usage: which equipment actually gets used',\n helpText:\n 'Derived from the workouts you assign, so you buy the second squat rack instead of the second treadmill.',\n // ⚠️ NOT BUILT — shown deliberately. Needs an exercise->equipment link that\n // does not exist; the card renders its own empty state today. See the TODO\n // in insights.service. It is the strongest Pro line on the board, so it is\n // listed — but an empty chart on a paid tier is a refund request.\n available: true,\n plans: { free: false, starter: false, pro: true },\n },\n\n // ═══ Talking to members ═════════════════════════════════════════════════\n\n {\n key: 'monthlyAnnouncements',\n label: 'Announcements',\n helpText:\n 'Push a message to every member of a center at once. It lands in their app and on their phone.',\n available: true,\n plans: {\n free: '1 announcement a month',\n starter: '4 announcements a month',\n pro: 'Unlimited announcements',\n },\n },\n\n // ═══ Trial and support ══════════════════════════════════════════════════\n\n {\n key: 'freeTrial',\n label: 'Free trial, no card up front',\n helpText:\n 'Try a paid plan for two weeks without entering a card. Asking for a card first is the biggest drop-off in Indian SMB software, and it filters out exactly the cautious owner a trial exists to convince.',\n available: true,\n plans: { free: false, starter: '14-day free trial', pro: '14-day free trial' },\n },\n {\n key: 'support',\n label: 'Support',\n helpText: 'How quickly you hear back when something is wrong.',\n available: true,\n plans: {\n free: 'Community support',\n starter: 'Email support, within 48 hours',\n pro: 'Priority support, within 24 hours',\n },\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 * gymmonk-schema — SaaS plan feature display\n * ==========================================\n * What a pricing card SAYS, kept apart from what the server ENFORCES\n * (`plan-limits.ts`), exactly as `dating-schema` splits them.\n *\n * The split is not tidiness. The two lists are different sizes and always will\n * be: some rows cover several limits at once (one \"staff you can add\" line\n * stands for four per-role caps), and MOST limits never earn a row at all.\n * Forcing one array to be both produces either a card full of plumbing or an\n * enforcement set with holes in it.\n *\n * ── THIS LIST IS A PRODUCT DECISION, NOT AN INVENTORY ───────────────────────\n * ⚠️ It is DELIBERATELY SHORT, and it was cut down on purpose. Do not add a row\n * because the product happens to have the feature.\n *\n * It previously carried 28 rows — the member app, QR check-in, self-join,\n * search discovery, the public gym page, custom exercises, branches, staff\n * duty/pay, the equipment register, the live dashboard, expiring-membership\n * alerts, peak-load alerts, equipment usage, the trial and support tiers. Every\n * one of them is real and shipped. None of them was on the list the product\n * owner asked to sell on, and together they buried the four lines that actually\n * decide the sale.\n *\n * The rule is now explicit: a row exists here ONLY if it is on that list. If\n * you think something else deserves selling, that is a conversation with the\n * product owner, not an edit to this array.\n *\n * ── ORDER IS THE ARGUMENT ───────────────────────────────────────────────────\n * Rows render in array order: who your members are, what you can do with them,\n * what you can build, who helps you run it, what you can see, how you talk to\n * them. The first three lines carry the whole board — nothing is metered, thirty\n * are workable for free, and the tools arrive with the subscription.\n *\n * ── EVERY ROW APPEARS ON EVERY CARD ─────────────────────────────────────────\n * `getPlanFeatureDisplay` splits them into included and locked. A card that\n * listed only what a tier includes would state the overlap and hide the gap, so\n * the upgrade case would have to be made on a comparison page nobody opens.\n *\n * ⚠️ Two rows below are NOT BUILT — diet plans and the advanced-stats bundle's\n * equipment usage. They are shown because the tiers are designed around them\n * and they are committed work. Flip `available` to `false` and a row vanishes\n * from every card at once, which is the lever to pull if either slips: a card\n * promising a feature the customer cannot open is the fastest route to a refund\n * request, and the refund policy is already published.\n *\n * @module gymmonk-schema/plan-features-data\n */\n\nimport type { FeatureDisplayItem } from './plan-limits.js';\n\nexport const PLAN_FEATURE_DISPLAY_DATA: FeatureDisplayItem[] = [\n // ═══ Your members ═══════════════════════════════════════════════════════\n\n {\n key: 'members',\n label: 'Add unlimited members',\n helpText:\n 'Members are never counted for billing, on any plan. Growing your gym never increases what you pay us.',\n available: true,\n plans: {\n free: {\n text: 'Add unlimited members*',\n helpText:\n 'Never metered, and nothing ever stops you adding one — not even on the free plan. A fair-use policy applies above 500 active members, which is a conversation and not a cut-off.',\n },\n pro: 'Add unlimited members',\n },\n },\n {\n key: 'manageableMembers',\n label: 'Manage unlimited members',\n helpText:\n 'How many of your members you can open, edit, collect from and track. Everyone you add always keeps their app, their ID card and their check-in — this is about what YOU can work with.',\n available: true,\n plans: {\n free: {\n text: 'Manage up to 30 members',\n helpText:\n 'Your first 30 members by join date are fully workable. Members past the thirtieth still join, still check in and still use the app in full — you just cannot open them from the console until you subscribe. Nothing is deleted, and they all appear the moment you do.',\n },\n pro: {\n text: 'Manage unlimited members',\n helpText: 'Your whole roster, however large, open and workable from the console.',\n },\n },\n },\n {\n key: 'memberDirectoryTools',\n label: 'Advanced member filters',\n helpText:\n 'Cut the roster the way you actually work instead of scrolling it: filter by due date, overdue, membership plan, status or joining date, sort by due date, join date or name, and search by name or phone. This is what turns a long roster into a morning’s work.',\n available: true,\n plans: {\n free: false,\n pro: 'Advanced member filters',\n },\n },\n\n // ═══ Attendance ═════════════════════════════════════════════════════════\n\n {\n key: 'attendanceTracking',\n label: 'Attendance tracking',\n helpText:\n 'Who trained and when, per member and per day, from QR check-ins at the door. Your members always see their own attendance in the app whatever your plan — this row is the OWNER’S record of it.',\n available: true,\n plans: {\n free: false,\n pro: 'Attendance tracking',\n },\n },\n {\n key: 'attendanceHistoryMonths',\n label: '1 year of attendance history',\n helpText:\n 'A full year back, which covers every renewal conversation you will ever have: who has stopped coming, who came all year, and who lapsed the month before they cancelled. Older records are hidden, never deleted — they come back in full the moment you upgrade.',\n available: true,\n plans: {\n free: false,\n pro: '1 year of attendance history',\n },\n },\n\n // ═══ What you can build ═════════════════════════════════════════════════\n\n {\n key: 'membershipPlans',\n label: 'Add unlimited membership plans',\n helpText:\n 'The plans your members buy — monthly, quarterly, annual, personal training, whatever you price. Each carries its own duration, fee and joining fee.',\n available: true,\n plans: {\n free: false,\n pro: 'Add unlimited membership plans',\n },\n },\n {\n key: 'workoutPlans',\n label: 'Create unlimited custom workout plans',\n helpText:\n 'Build your own routines from the exercise library, assign them to a member, and they appear in that member’s app with videos and set-by-set tracking.',\n available: true,\n plans: {\n free: false,\n pro: 'Create unlimited custom workout plans',\n },\n },\n {\n key: 'dietPlans',\n label: 'Create unlimited custom diet plans',\n // ⚠️ NOT BUILT. Committed work — see the module note.\n helpText:\n 'Build meal plans from the food library with calories and macros worked out for you, and assign them to a member alongside their training.',\n available: true,\n plans: {\n free: false,\n pro: 'Create unlimited custom diet plans',\n },\n },\n\n // ═══ Who runs it with you ═══════════════════════════════════════════════\n\n {\n key: 'staff',\n label: 'Add unlimited staff members',\n helpText:\n 'Trainers, managers, front desk and cleaning staff, each with their own login and only the access their role needs. Nobody shares the owner’s account.',\n available: true,\n plans: {\n free: false,\n pro: 'Add unlimited staff members',\n },\n },\n\n // ═══ Your numbers ═══════════════════════════════════════════════════════\n\n {\n key: 'revenueInsight',\n label: 'Full revenue tracking',\n helpText:\n 'The full year of collections broken down by month, by membership plan and by payment method, with renewals and joining fees separated — so you can see which plan actually earns and which one just looks busy.',\n available: true,\n plans: {\n free: false,\n pro: 'Full revenue tracking',\n },\n },\n {\n key: 'advancedInsights',\n label: 'Advanced dashboard stats',\n // ⚠️ The tooltip is the row. It is the one place the whole insight suite is\n // named, so trimming it for length removes the reason to buy the tier.\n helpText:\n 'Crowd load by hour and by weekday so you can staff your real peaks; member demographics by age and gender; attendance trends and who is slipping; retention and churn; membership plan mix; expiring and overdue counts; and equipment usage worked out from the workouts you actually assign.',\n available: true,\n plans: {\n free: false,\n pro: 'Advanced dashboard stats',\n },\n },\n\n // ═══ Talking to your members ════════════════════════════════════════════\n\n {\n key: 'monthlyAnnouncements',\n label: 'Unlimited announcements every month',\n helpText:\n 'A message to everyone at a center at once — a holiday, new timings, a festival offer. It lands in the app of every member you have.',\n available: true,\n plans: {\n free: '1 announcement per month',\n pro: 'Unlimited announcements every month',\n },\n },\n {\n key: 'inAppNotifications',\n label: 'Unlimited in-app notifications',\n helpText:\n 'Fee reminders, plan expiry and check-in confirmations delivered inside your members’ app, with no monthly ceiling and nothing to pay per message.',\n available: true,\n plans: {\n free: false,\n pro: 'Unlimited in-app notifications',\n },\n },\n {\n key: 'whatsappLateFeeNotices',\n label: 'Up to 150 WhatsApp late-fee notifications',\n helpText:\n 'For the member who has stopped opening the app: a reminder about an overdue fee, sent to their WhatsApp from your gym. Up to 150 a month across your whole gym — WhatsApp charges for every conversation, which is why this one has a number on it while in-app reminders do not.',\n available: true,\n plans: {\n free: false,\n pro: 'Up to 150 WhatsApp late-fee notifications',\n },\n },\n];\n"]}
|