@dgpholdings/greatoak-shared 1.2.87 → 1.2.88
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/__mocks__/catalog.fixture.d.ts +2 -0
- package/dist/__mocks__/catalog.fixture.js +208 -0
- package/dist/__mocks__/exercises.mock.d.ts +4 -11
- package/dist/__mocks__/exercises.mock.js +82 -42
- package/dist/__mocks__/sessions.mock.d.ts +28 -0
- package/dist/__mocks__/sessions.mock.js +394 -0
- package/dist/__mocks__/testIds.d.ts +9 -0
- package/dist/__mocks__/testIds.js +13 -0
- package/dist/__mocks__/user.mock.js +3 -1
- package/dist/constants/goalJourney.d.ts +108 -0
- package/dist/constants/goalJourney.js +443 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/types/TApiUser.d.ts +2 -0
- package/dist/utils/adoptionEngine/scaleProPlan.util.js +9 -4
- package/dist/utils/constellation/computeNormalisedLoad.test.d.ts +1 -0
- package/dist/utils/constellation/computeNormalisedLoad.test.js +218 -0
- package/dist/utils/constellation/evaluateConstellation.js +1 -1
- package/dist/utils/constellation/evaluateConstellation.test.d.ts +1 -0
- package/dist/utils/constellation/evaluateConstellation.test.js +93 -0
- package/dist/utils/constellation/index.d.ts +1 -0
- package/dist/utils/constellation/index.js +4 -1
- package/dist/utils/constellation/starFoundation.test.d.ts +1 -0
- package/dist/utils/constellation/starFoundation.test.js +75 -0
- package/dist/utils/constellation/stars/consistency.test.d.ts +1 -0
- package/dist/utils/constellation/stars/consistency.test.js +94 -0
- package/dist/utils/constellation/stars/quality.test.d.ts +1 -0
- package/dist/utils/constellation/stars/quality.test.js +113 -0
- package/dist/utils/constellation/stars/recovery.test.d.ts +1 -0
- package/dist/utils/constellation/stars/recovery.test.js +131 -0
- package/dist/utils/constellation/strengthStar.test.d.ts +1 -0
- package/dist/utils/constellation/strengthStar.test.js +190 -0
- package/dist/utils/exerciseRecord/recordValidator.integration.test.js +1 -1
- package/dist/utils/exerciseRecord/recordValidator.js +1 -1
- package/dist/utils/exerciseRecord/recordValidator.test.js +8 -8
- package/dist/utils/scoringWorkout/scoringWorkout.integration.test.js +19 -19
- package/package.json +1 -1
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// shared/src/__mocks__/sessions.mock.ts
|
|
3
|
+
/**
|
|
4
|
+
* Real workout-session records (verbatim shape as stored in CLIENT_WORKOUTS_TABLE),
|
|
5
|
+
* used to test the session loader's mapping and the constellation end-to-end
|
|
6
|
+
* against the real exercise catalog. clientId is rewired to MOCK_USER_ID.
|
|
7
|
+
*
|
|
8
|
+
* These reference real exercise IDs that exist in the production exercise
|
|
9
|
+
* snapshot, with real movement patterns (push_horizontal, squat, lunge, etc.).
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.mockStoredSessions = exports.mockSessionMixed = exports.mockSessionLegs = exports.mockSessionPush = void 0;
|
|
13
|
+
const testIds_1 = require("./testIds");
|
|
14
|
+
/** Upper/push + accessory session (bench-pattern, triceps, shoulders). */
|
|
15
|
+
exports.mockSessionPush = {
|
|
16
|
+
pk: testIds_1.MOCK_CLIENT_PK,
|
|
17
|
+
sk: "SESSION#2026-05-19T09:05:38.286Z#PERSONAL",
|
|
18
|
+
clientId: testIds_1.MOCK_USER_ID,
|
|
19
|
+
createdAt: "2026-05-19T09:47:09.418Z",
|
|
20
|
+
expirationTime: 1794736029,
|
|
21
|
+
sessionId: "QKB0lDAN_2sB3RbumAZ1O",
|
|
22
|
+
userDuration: 2491,
|
|
23
|
+
sessionRecord: [
|
|
24
|
+
{
|
|
25
|
+
exerciseId: "2tprDDd4_BsnK6gbMVWTQ",
|
|
26
|
+
records: [
|
|
27
|
+
{
|
|
28
|
+
auxWeightKg: "0",
|
|
29
|
+
durationMmSs: "00:30",
|
|
30
|
+
isDone: true,
|
|
31
|
+
isStrictMode: false,
|
|
32
|
+
type: "duration",
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
exerciseId: "-SR_ogujWtdkH6EtCe2OQ",
|
|
38
|
+
records: [
|
|
39
|
+
{
|
|
40
|
+
auxWeightKg: "0",
|
|
41
|
+
isDone: true,
|
|
42
|
+
isStrictMode: false,
|
|
43
|
+
reps: "8",
|
|
44
|
+
type: "reps-only",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
auxWeightKg: "0",
|
|
48
|
+
isDone: true,
|
|
49
|
+
isStrictMode: false,
|
|
50
|
+
reps: "8",
|
|
51
|
+
restDurationSecs: 90,
|
|
52
|
+
type: "reps-only",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
auxWeightKg: "0",
|
|
56
|
+
isDone: true,
|
|
57
|
+
isStrictMode: false,
|
|
58
|
+
reps: "6",
|
|
59
|
+
type: "reps-only",
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
exerciseId: "EA9B8p_H60pQPRBevjRj6",
|
|
65
|
+
records: [
|
|
66
|
+
{
|
|
67
|
+
auxWeightKg: "0",
|
|
68
|
+
isDone: true,
|
|
69
|
+
isStrictMode: false,
|
|
70
|
+
reps: "10",
|
|
71
|
+
type: "reps-only",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
auxWeightKg: "0",
|
|
75
|
+
isDone: true,
|
|
76
|
+
isStrictMode: false,
|
|
77
|
+
reps: "9",
|
|
78
|
+
restDurationSecs: 90,
|
|
79
|
+
type: "reps-only",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
auxWeightKg: "0",
|
|
83
|
+
isDone: true,
|
|
84
|
+
isStrictMode: false,
|
|
85
|
+
reps: "8",
|
|
86
|
+
restDurationSecs: 90,
|
|
87
|
+
type: "reps-only",
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
exerciseId: "5LyI0el3TUJta6xLYdoua",
|
|
93
|
+
records: [
|
|
94
|
+
{
|
|
95
|
+
isDone: true,
|
|
96
|
+
isStrictMode: false,
|
|
97
|
+
kg: "20",
|
|
98
|
+
reps: "10",
|
|
99
|
+
type: "weight-reps",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
isDone: true,
|
|
103
|
+
isStrictMode: false,
|
|
104
|
+
kg: "20",
|
|
105
|
+
reps: "9",
|
|
106
|
+
restDurationSecs: 90,
|
|
107
|
+
type: "weight-reps",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
isDone: true,
|
|
111
|
+
isStrictMode: false,
|
|
112
|
+
kg: "20",
|
|
113
|
+
reps: "7",
|
|
114
|
+
restDurationSecs: 90,
|
|
115
|
+
type: "weight-reps",
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
exerciseId: "RQCNQi0sw8icSqyhzytyS",
|
|
121
|
+
records: [
|
|
122
|
+
{
|
|
123
|
+
isDone: true,
|
|
124
|
+
isStrictMode: false,
|
|
125
|
+
kg: "26",
|
|
126
|
+
reps: "10",
|
|
127
|
+
type: "weight-reps",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
isDone: true,
|
|
131
|
+
isStrictMode: false,
|
|
132
|
+
kg: "26",
|
|
133
|
+
reps: "10",
|
|
134
|
+
restDurationSecs: 60,
|
|
135
|
+
type: "weight-reps",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
isDone: true,
|
|
139
|
+
isStrictMode: false,
|
|
140
|
+
kg: "26",
|
|
141
|
+
reps: "8",
|
|
142
|
+
restDurationSecs: 60,
|
|
143
|
+
type: "weight-reps",
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
exerciseId: "cICiD8ldTl3TVKl_SZV4y",
|
|
149
|
+
records: [
|
|
150
|
+
{
|
|
151
|
+
isDone: true,
|
|
152
|
+
isStrictMode: false,
|
|
153
|
+
kg: "50",
|
|
154
|
+
reps: "8",
|
|
155
|
+
type: "weight-reps",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
isDone: true,
|
|
159
|
+
isStrictMode: false,
|
|
160
|
+
kg: "50",
|
|
161
|
+
reps: "7",
|
|
162
|
+
restDurationSecs: 60,
|
|
163
|
+
type: "weight-reps",
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
isDone: true,
|
|
167
|
+
isStrictMode: false,
|
|
168
|
+
kg: "45",
|
|
169
|
+
reps: "7",
|
|
170
|
+
restDurationSecs: 60,
|
|
171
|
+
type: "weight-reps",
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
exerciseId: "9W7Yon0FWh1Eqd52yjHV9",
|
|
177
|
+
records: [
|
|
178
|
+
{
|
|
179
|
+
auxWeightKg: "0",
|
|
180
|
+
durationMmSs: "01:13",
|
|
181
|
+
isDone: true,
|
|
182
|
+
isStrictMode: false,
|
|
183
|
+
type: "duration",
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
/** Lower-body session (squat, lunge, plyo) — note several sets isDone:false. */
|
|
190
|
+
exports.mockSessionLegs = {
|
|
191
|
+
pk: testIds_1.MOCK_CLIENT_PK,
|
|
192
|
+
sk: "SESSION#2026-04-29T07:47:53.111Z#PERSONAL",
|
|
193
|
+
clientId: testIds_1.MOCK_USER_ID,
|
|
194
|
+
createdAt: "2026-04-29T07:52:24.207Z",
|
|
195
|
+
expirationTime: 1793001144,
|
|
196
|
+
sessionId: "EASmO9MwSnNHKtCWseQzz",
|
|
197
|
+
userDuration: 271,
|
|
198
|
+
sessionRecord: [
|
|
199
|
+
{
|
|
200
|
+
exerciseId: "xNvol6-lFnHQUMCfxFMBD",
|
|
201
|
+
records: [
|
|
202
|
+
{
|
|
203
|
+
auxWeightKg: "0",
|
|
204
|
+
isDone: false,
|
|
205
|
+
isStrictMode: false,
|
|
206
|
+
reps: "15",
|
|
207
|
+
type: "reps-only",
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
auxWeightKg: "0",
|
|
211
|
+
isDone: false,
|
|
212
|
+
isStrictMode: false,
|
|
213
|
+
reps: "15",
|
|
214
|
+
type: "reps-only",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
auxWeightKg: "0",
|
|
218
|
+
isDone: false,
|
|
219
|
+
isStrictMode: false,
|
|
220
|
+
reps: "15",
|
|
221
|
+
type: "reps-only",
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
exerciseId: "D3XVV-ypHfraYO52eH9ur",
|
|
227
|
+
records: [
|
|
228
|
+
{
|
|
229
|
+
auxWeightKg: "0",
|
|
230
|
+
isDone: true,
|
|
231
|
+
isStrictMode: false,
|
|
232
|
+
reps: "10",
|
|
233
|
+
restDurationSecs: 60,
|
|
234
|
+
type: "reps-only",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
auxWeightKg: "0",
|
|
238
|
+
isDone: false,
|
|
239
|
+
isStrictMode: false,
|
|
240
|
+
reps: "10",
|
|
241
|
+
restDurationSecs: 45,
|
|
242
|
+
type: "reps-only",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
auxWeightKg: "0",
|
|
246
|
+
isDone: false,
|
|
247
|
+
isStrictMode: false,
|
|
248
|
+
reps: "10",
|
|
249
|
+
type: "reps-only",
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
exerciseId: "cXExEzqEAF8YrFN2kAnIq",
|
|
255
|
+
records: [
|
|
256
|
+
{
|
|
257
|
+
auxWeightKg: "0",
|
|
258
|
+
isDone: true,
|
|
259
|
+
isStrictMode: false,
|
|
260
|
+
reps: "10",
|
|
261
|
+
rir: "0",
|
|
262
|
+
type: "reps-only",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
auxWeightKg: "0",
|
|
266
|
+
isDone: true,
|
|
267
|
+
isStrictMode: false,
|
|
268
|
+
reps: "12",
|
|
269
|
+
restDurationSecs: 30,
|
|
270
|
+
rir: "0",
|
|
271
|
+
type: "reps-only",
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
auxWeightKg: "0",
|
|
275
|
+
isDone: true,
|
|
276
|
+
isStrictMode: false,
|
|
277
|
+
reps: "12",
|
|
278
|
+
rir: "0",
|
|
279
|
+
type: "reps-only",
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
exerciseId: "3CkW5o5VQbCodRFmByeMc",
|
|
285
|
+
records: [
|
|
286
|
+
{
|
|
287
|
+
auxWeightKg: "0",
|
|
288
|
+
isDone: true,
|
|
289
|
+
isStrictMode: false,
|
|
290
|
+
reps: "10",
|
|
291
|
+
type: "reps-only",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
auxWeightKg: "0",
|
|
295
|
+
isDone: false,
|
|
296
|
+
isStrictMode: false,
|
|
297
|
+
reps: "12",
|
|
298
|
+
type: "reps-only",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
auxWeightKg: "0",
|
|
302
|
+
isDone: false,
|
|
303
|
+
isStrictMode: false,
|
|
304
|
+
reps: "12",
|
|
305
|
+
type: "reps-only",
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
/** Short mixed session (abs, cardio-machine, duration) — recent. */
|
|
312
|
+
exports.mockSessionMixed = {
|
|
313
|
+
pk: testIds_1.MOCK_CLIENT_PK,
|
|
314
|
+
sk: "SESSION#2026-06-05T19:39:08.048Z#PERSONAL",
|
|
315
|
+
clientId: testIds_1.MOCK_USER_ID,
|
|
316
|
+
createdAt: "2026-06-05T19:40:04.918Z",
|
|
317
|
+
expirationTime: 1796240404,
|
|
318
|
+
sessionId: "HauSJHH0Eo3clVrSmR9z7",
|
|
319
|
+
userDuration: 56,
|
|
320
|
+
sessionRecord: [
|
|
321
|
+
{
|
|
322
|
+
exerciseId: "S7Edj-DnCvOgYNv_0SlzP",
|
|
323
|
+
records: [
|
|
324
|
+
{
|
|
325
|
+
auxWeightKg: "0",
|
|
326
|
+
isDone: true,
|
|
327
|
+
isStrictMode: false,
|
|
328
|
+
reps: "10",
|
|
329
|
+
type: "reps-only",
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
auxWeightKg: "0",
|
|
333
|
+
isDone: true,
|
|
334
|
+
isStrictMode: false,
|
|
335
|
+
reps: "10",
|
|
336
|
+
type: "reps-only",
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
auxWeightKg: "0",
|
|
340
|
+
isDone: true,
|
|
341
|
+
isStrictMode: false,
|
|
342
|
+
reps: "10",
|
|
343
|
+
type: "reps-only",
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
exerciseId: "_pz6syBDTeH36DFmg2VRy",
|
|
349
|
+
records: [
|
|
350
|
+
{
|
|
351
|
+
distance: "2",
|
|
352
|
+
durationMmSs: "15:00",
|
|
353
|
+
isDone: true,
|
|
354
|
+
isStrictMode: false,
|
|
355
|
+
speed: "8",
|
|
356
|
+
type: "cardio-machine",
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
distance: "2",
|
|
360
|
+
durationMmSs: "13:00",
|
|
361
|
+
isDone: true,
|
|
362
|
+
isStrictMode: false,
|
|
363
|
+
speed: "8",
|
|
364
|
+
type: "cardio-machine",
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
exerciseId: "9W7Yon0FWh1Eqd52yjHV9",
|
|
370
|
+
records: [
|
|
371
|
+
{
|
|
372
|
+
auxWeightKg: "0",
|
|
373
|
+
durationMmSs: "00:00",
|
|
374
|
+
isDone: true,
|
|
375
|
+
isStrictMode: false,
|
|
376
|
+
type: "duration",
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
auxWeightKg: "0",
|
|
380
|
+
durationMmSs: "00:00",
|
|
381
|
+
isDone: true,
|
|
382
|
+
isStrictMode: false,
|
|
383
|
+
restDurationSecs: 10,
|
|
384
|
+
type: "duration",
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
};
|
|
390
|
+
exports.mockStoredSessions = [
|
|
391
|
+
exports.mockSessionPush,
|
|
392
|
+
exports.mockSessionLegs,
|
|
393
|
+
exports.mockSessionMixed,
|
|
394
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Common identifiers for tests and fixtures. Keeping them here means a mock
|
|
3
|
+
* user, their session records, and any controller test all agree on the same
|
|
4
|
+
* id without magic strings scattered around.
|
|
5
|
+
*/
|
|
6
|
+
/** The canonical test user. Used as both userId and the CLIENT#<id> partition. */
|
|
7
|
+
export declare const MOCK_USER_ID = "mock-user-123";
|
|
8
|
+
/** The DynamoDB partition key for that user's workout sessions. */
|
|
9
|
+
export declare const MOCK_CLIENT_PK = "CLIENT#mock-user-123";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// shared/src/__mocks__/testIds.ts
|
|
3
|
+
/**
|
|
4
|
+
* Common identifiers for tests and fixtures. Keeping them here means a mock
|
|
5
|
+
* user, their session records, and any controller test all agree on the same
|
|
6
|
+
* id without magic strings scattered around.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.MOCK_CLIENT_PK = exports.MOCK_USER_ID = void 0;
|
|
10
|
+
/** The canonical test user. Used as both userId and the CLIENT#<id> partition. */
|
|
11
|
+
exports.MOCK_USER_ID = "mock-user-123";
|
|
12
|
+
/** The DynamoDB partition key for that user's workout sessions. */
|
|
13
|
+
exports.MOCK_CLIENT_PK = `CLIENT#${exports.MOCK_USER_ID}`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mockUser = void 0;
|
|
4
|
+
const testIds_1 = require("./testIds");
|
|
4
5
|
exports.mockUser = {
|
|
5
6
|
// TUserPreferences fields (flat in TUserMetric)
|
|
6
7
|
preferredDurationMinutes: 45,
|
|
@@ -18,8 +19,9 @@ exports.mockUser = {
|
|
|
18
19
|
appLanguage: "en",
|
|
19
20
|
preferencesUpdatedAt: new Date("2023-01-01").toISOString(),
|
|
20
21
|
femaleHealth: null, // Male user
|
|
22
|
+
constellationLevel: 1,
|
|
21
23
|
// TUserMetric-specific fields
|
|
22
|
-
userId:
|
|
24
|
+
userId: testIds_1.MOCK_USER_ID,
|
|
23
25
|
userCode: "MOCK123",
|
|
24
26
|
userType: "regular",
|
|
25
27
|
fullName: "Mock User",
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { TAiFitnessGoal } from "./AiExerciseVocabulary";
|
|
2
|
+
import { QUICK_START_CLEAR_INTENTS } from "./quickStartIntents";
|
|
3
|
+
export declare const USER_FITNESS_GOALS: readonly ["lose_weight", "build_muscle", "lean_and_toned", "glutes_and_legs", "get_stronger", "boost_endurance", "athletic_performance", "general_fitness", "posture_and_back", "stress_relief", "rehabilitation", "core_strength", "mobility_flexibility"];
|
|
4
|
+
export type TUserFitnessGoal = (typeof USER_FITNESS_GOALS)[number];
|
|
5
|
+
export type TSessionIntent = (typeof QUICK_START_CLEAR_INTENTS)[keyof typeof QUICK_START_CLEAR_INTENTS] | "rest";
|
|
6
|
+
export declare const GOAL_SESSION_INTENTS: Record<TUserFitnessGoal, TWeeklyIntentTemplate>;
|
|
7
|
+
export declare const GOAL_TO_AI_FITNESS_GOAL: Record<TUserFitnessGoal, TAiFitnessGoal>;
|
|
8
|
+
export declare const TRAINING_PHASES: readonly [1, 2, 3, 4];
|
|
9
|
+
export type TTrainingPhase = (typeof TRAINING_PHASES)[number];
|
|
10
|
+
export type TPhaseDisplay = {
|
|
11
|
+
/** i18n key for the phase name — e.g. "goalPhase.foundation.name" */
|
|
12
|
+
nameKey: string;
|
|
13
|
+
/** English fallback for nameKey */
|
|
14
|
+
nameEn: string;
|
|
15
|
+
/** i18n key for the short subtitle — e.g. "goalPhase.foundation.subtitle" */
|
|
16
|
+
subtitleKey: string;
|
|
17
|
+
/** English fallback for subtitleKey */
|
|
18
|
+
subtitleEn: string;
|
|
19
|
+
/** i18n key for the longer purpose description shown in phase detail */
|
|
20
|
+
purposeKey: string;
|
|
21
|
+
/** English fallback for purposeKey */
|
|
22
|
+
purposeEn: string;
|
|
23
|
+
/** i18n key for the week range label — e.g. "goalPhase.foundation.duration" */
|
|
24
|
+
durationKey: string;
|
|
25
|
+
/** English fallback for durationKey */
|
|
26
|
+
durationEn: string;
|
|
27
|
+
/** Inclusive week range [startWeek, endWeek]. Phase 4 end is open (99). */
|
|
28
|
+
weekRange: [number, number];
|
|
29
|
+
/**
|
|
30
|
+
* Reference intensity as a percentage (0–100).
|
|
31
|
+
* For UI progress bars / intensity indicators only — not used in algorithm.
|
|
32
|
+
*/
|
|
33
|
+
intensityPercent: number;
|
|
34
|
+
};
|
|
35
|
+
export declare const PHASE_DISPLAY: Record<TTrainingPhase, TPhaseDisplay>;
|
|
36
|
+
export type TIntentDisplay = {
|
|
37
|
+
/** i18n key for the full label — e.g. "sessionIntent.push.label" */
|
|
38
|
+
labelKey: string;
|
|
39
|
+
/** English fallback for labelKey */
|
|
40
|
+
labelEn: string;
|
|
41
|
+
/**
|
|
42
|
+
* i18n key for the short label used in compact journey nodes.
|
|
43
|
+
* e.g. "sessionIntent.push.shortLabel"
|
|
44
|
+
*/
|
|
45
|
+
shortLabelKey: string;
|
|
46
|
+
/** English fallback for shortLabelKey */
|
|
47
|
+
shortLabelEn: string;
|
|
48
|
+
/**
|
|
49
|
+
* Emoji for the session node icon.
|
|
50
|
+
* Not translated — emoji is universal.
|
|
51
|
+
*/
|
|
52
|
+
emoji: string;
|
|
53
|
+
};
|
|
54
|
+
export declare const INTENT_DISPLAY: Record<TSessionIntent, TIntentDisplay>;
|
|
55
|
+
export type TGoalDisplay = {
|
|
56
|
+
/** i18n key for the goal name — e.g. "userGoal.loseWeight.name" */
|
|
57
|
+
nameKey: string;
|
|
58
|
+
/** English fallback for nameKey */
|
|
59
|
+
nameEn: string;
|
|
60
|
+
/** i18n key for the short description shown on goal selection screen */
|
|
61
|
+
descriptionKey: string;
|
|
62
|
+
/** English fallback for descriptionKey */
|
|
63
|
+
descriptionEn: string;
|
|
64
|
+
/**
|
|
65
|
+
* i18n key for the motivational tagline shown on the goal journey screen.
|
|
66
|
+
* e.g. "userGoal.loseWeight.tagline"
|
|
67
|
+
*/
|
|
68
|
+
taglineKey: string;
|
|
69
|
+
/** English fallback for taglineKey */
|
|
70
|
+
taglineEn: string;
|
|
71
|
+
/** Emoji representing the goal — universal, not translated */
|
|
72
|
+
emoji: string;
|
|
73
|
+
/**
|
|
74
|
+
* Goal category — used to group goals on the selection screen.
|
|
75
|
+
* Category label itself is also translated via categoryKey.
|
|
76
|
+
*/
|
|
77
|
+
category: "appearance" | "performance" | "health" | "focused";
|
|
78
|
+
};
|
|
79
|
+
export declare const GOAL_DISPLAY: Record<TUserFitnessGoal, TGoalDisplay>;
|
|
80
|
+
export type TGoalCategory = TGoalDisplay["category"];
|
|
81
|
+
export type TGoalCategoryDisplay = {
|
|
82
|
+
labelKey: string;
|
|
83
|
+
labelEn: string;
|
|
84
|
+
};
|
|
85
|
+
export declare const GOAL_CATEGORY_DISPLAY: Record<TGoalCategory, TGoalCategoryDisplay>;
|
|
86
|
+
/**
|
|
87
|
+
* Derive the current training phase from the week number since goal start.
|
|
88
|
+
* Week is 1-indexed (week 1 = first week on the program).
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* derivePhase(1) // → 1 (Foundation)
|
|
92
|
+
* derivePhase(3) // → 2 (Momentum)
|
|
93
|
+
* derivePhase(7) // → 3 (Push)
|
|
94
|
+
* derivePhase(10) // → 4 (Peak)
|
|
95
|
+
*/
|
|
96
|
+
export declare function derivePhase(weekNumber: number): TTrainingPhase;
|
|
97
|
+
export declare const DAYS_PER_WEEK_OPTIONS: readonly [2, 3, 4, 5];
|
|
98
|
+
export type TDaysPerWeek = (typeof DAYS_PER_WEEK_OPTIONS)[number];
|
|
99
|
+
export type TDurationHint = "short" | "medium" | "long";
|
|
100
|
+
export type TWeeklyIntentTemplate = [
|
|
101
|
+
TSessionIntent,
|
|
102
|
+
TSessionIntent,
|
|
103
|
+
TSessionIntent,
|
|
104
|
+
TSessionIntent,
|
|
105
|
+
TSessionIntent,
|
|
106
|
+
TSessionIntent,
|
|
107
|
+
TSessionIntent
|
|
108
|
+
];
|