gymmonk-schema 0.20.0 → 0.22.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/exercise.d.ts +2 -1
- package/dist/exercise.d.ts.map +1 -1
- package/dist/exercise.js +21 -2
- package/dist/exercise.js.map +1 -1
- package/dist/messages.d.ts +19 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +13 -0
- package/dist/messages.js.map +1 -1
- package/dist/notification.d.ts +57 -4
- package/dist/notification.d.ts.map +1 -1
- package/dist/notification.js +52 -6
- package/dist/notification.js.map +1 -1
- package/dist/workout-plan.d.ts +3 -3
- package/dist/workout-plan.d.ts.map +1 -1
- package/dist/workout-plan.js +17 -2
- package/dist/workout-plan.js.map +1 -1
- package/package.json +1 -1
package/dist/exercise.d.ts
CHANGED
|
@@ -68,6 +68,7 @@ export declare const exerciseSummarySchema: z.ZodObject<{
|
|
|
68
68
|
}>;
|
|
69
69
|
targetArea: z.ZodString;
|
|
70
70
|
thumbnailUrl: z.ZodNullable<z.ZodString>;
|
|
71
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
71
72
|
}, z.core.$strip>;
|
|
72
73
|
export type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;
|
|
73
74
|
export declare const exerciseSchema: z.ZodObject<{
|
|
@@ -122,7 +123,7 @@ export declare const exerciseSchema: z.ZodObject<{
|
|
|
122
123
|
}, z.core.$strip>;
|
|
123
124
|
export type Exercise = z.infer<typeof exerciseSchema>;
|
|
124
125
|
export declare const createExerciseBodySchema: z.ZodObject<{
|
|
125
|
-
centerId: z.ZodString
|
|
126
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
126
127
|
name: z.ZodString;
|
|
127
128
|
description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
128
129
|
category: z.ZodEnum<{
|
package/dist/exercise.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"exercise.d.ts","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,gBAAgB;;;;EAAmD,CAAC;AACjF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,sLAiBhB,CAAC;AACX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;EAAwB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,iBAAiB;;;;;iBAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;iBAmBhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAItD,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA8D,CAAC;AACpG,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAI1E,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;iBAKrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
|
package/dist/exercise.js
CHANGED
|
@@ -54,10 +54,20 @@ export const exerciseSummarySchema = z.object({
|
|
|
54
54
|
category: exerciseCategorySchema,
|
|
55
55
|
targetArea: z.string(),
|
|
56
56
|
thumbnailUrl: z.string().nullable(),
|
|
57
|
+
/**
|
|
58
|
+
* Who authored this entry: `null` = the PLATFORM library, every gym sees it;
|
|
59
|
+
* a center id = that gym's own, and only its people see it.
|
|
60
|
+
*
|
|
61
|
+
* On the SUMMARY, not just the detail, because the grid is where the
|
|
62
|
+
* distinction has to be visible. An owner scrolling their library needs to
|
|
63
|
+
* know which cards are theirs to edit before tapping one, and a member is
|
|
64
|
+
* entitled to know that a routine came from their gym rather than from us.
|
|
65
|
+
* The detail shape inherits it from here, so there is one definition.
|
|
66
|
+
*/
|
|
67
|
+
centerId: objectIdSchema.nullable(),
|
|
57
68
|
});
|
|
58
69
|
// ─── Detail (full entity) ────────────────────────────────────────────────────
|
|
59
70
|
export const exerciseSchema = exerciseSummarySchema.extend({
|
|
60
|
-
centerId: objectIdSchema.nullable(),
|
|
61
71
|
description: z.string(),
|
|
62
72
|
youtubeId: z.string().nullable(),
|
|
63
73
|
posterUrl: z.string().nullable(),
|
|
@@ -69,7 +79,16 @@ export const exerciseSchema = exerciseSummarySchema.extend({
|
|
|
69
79
|
});
|
|
70
80
|
// ─── Create / update body ────────────────────────────────────────────────────
|
|
71
81
|
export const createExerciseBodySchema = z.object({
|
|
72
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Which library this entry joins. `null` is the PLATFORM library — content
|
|
84
|
+
* the product publishes to every gym — and only platform staff may send it.
|
|
85
|
+
*
|
|
86
|
+
* Nullable rather than optional on purpose: an omitted field would default to
|
|
87
|
+
* the global library, so a client that simply forgot to send a center would
|
|
88
|
+
* silently publish a gym's private exercise to the whole platform. Choosing
|
|
89
|
+
* global has to be something the caller SAYS.
|
|
90
|
+
*/
|
|
91
|
+
centerId: objectIdSchema.nullable(),
|
|
73
92
|
name: z.string().trim().min(1, 'Name is required').max(120),
|
|
74
93
|
description: optionalTrimmedString(4000),
|
|
75
94
|
category: exerciseCategorySchema,
|
package/dist/exercise.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEvF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC,CAAC;AAGjF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,IAAI,CAAC;IAC3C,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,MAAM;IACN,WAAW;CACZ,CAAC,CAAC;AAGH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO;IACP,MAAM;IACN,WAAW;IACX,QAAQ;IACR,SAAS;IACT,UAAU;IACV,OAAO;IACP,YAAY;IACZ,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,MAAM;IACN,UAAU;IACV,YAAY;IACZ,WAAW;IACX,QAAQ;CACA,CAAC;AACX,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAGvD,gFAAgF;AAEhF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CACzB,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,UAAU,EAAE,gBAAgB;IAC5B,QAAQ,EAAE,sBAAsB;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,cAAc,GAAG,qBAAqB,CAAC,MAAM,CAAC;IACzD,
|
|
1
|
+
{"version":3,"file":"exercise.js","sourceRoot":"","sources":["../src/exercise.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Exercise library\n * ==================================\n * The catalog of exercises. Global entries (centerId null) plus gym-custom ones\n * an owner authors. Difficulty/category/muscle vocabularies are normalised to\n * lowercase; the frontend title-cases for display.\n *\n * @module gymmonk-schema/exercise\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\n\n// ─── Enums ───────────────────────────────────────────────────────────────────\n\nexport const difficultySchema = z.enum(['beginner', 'intermediate', 'advanced']);\nexport type Difficulty = z.infer<typeof difficultySchema>;\n\nexport const exerciseCategorySchema = z.enum([\n 'cardio',\n 'upper-body',\n 'lower-body',\n 'core',\n 'full-body',\n]);\nexport type ExerciseCategory = z.infer<typeof exerciseCategorySchema>;\n\n/** Normalised superset of the target-muscle vocabulary used across the app. */\nexport const MUSCLE_GROUPS = [\n 'chest',\n 'back',\n 'shoulders',\n 'biceps',\n 'triceps',\n 'forearms',\n 'quads',\n 'hamstrings',\n 'glutes',\n 'calves',\n 'legs',\n 'core',\n 'obliques',\n 'lower-back',\n 'full-body',\n 'cardio',\n] as const;\nexport const muscleGroupSchema = z.enum(MUSCLE_GROUPS);\nexport type MuscleGroup = z.infer<typeof muscleGroupSchema>;\n\n// ─── Prescribed sets (on the detail view) ────────────────────────────────────\n\nexport const exerciseSetSchema = z.object({\n order: z.number().int().min(1),\n reps: z.string().trim().min(1),\n weight: z.string().trim(),\n tempo: z.string().trim(),\n});\nexport type ExerciseSet = z.infer<typeof exerciseSetSchema>;\n\n// ─── Summary (library card) ──────────────────────────────────────────────────\n\nexport const exerciseSummarySchema = z.object({\n id: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n thumbnailUrl: z.string().nullable(),\n /**\n * Who authored this entry: `null` = the PLATFORM library, every gym sees it;\n * a center id = that gym's own, and only its people see it.\n *\n * On the SUMMARY, not just the detail, because the grid is where the\n * distinction has to be visible. An owner scrolling their library needs to\n * know which cards are theirs to edit before tapping one, and a member is\n * entitled to know that a routine came from their gym rather than from us.\n * The detail shape inherits it from here, so there is one definition.\n */\n centerId: objectIdSchema.nullable(),\n});\nexport type ExerciseSummary = z.infer<typeof exerciseSummarySchema>;\n\n// ─── Detail (full entity) ────────────────────────────────────────────────────\n\nexport const exerciseSchema = exerciseSummarySchema.extend({\n description: z.string(),\n youtubeId: z.string().nullable(),\n posterUrl: z.string().nullable(),\n targetMuscles: z.array(muscleGroupSchema),\n sets: z.array(exerciseSetSchema),\n formTips: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type Exercise = z.infer<typeof exerciseSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createExerciseBodySchema = z.object({\n /**\n * Which library this entry joins. `null` is the PLATFORM library — content\n * the product publishes to every gym — and only platform staff may send it.\n *\n * Nullable rather than optional on purpose: an omitted field would default to\n * the global library, so a client that simply forgot to send a center would\n * silently publish a gym's private exercise to the whole platform. Choosing\n * global has to be something the caller SAYS.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Name is required').max(120),\n description: optionalTrimmedString(4000),\n category: exerciseCategorySchema,\n difficulty: difficultySchema,\n targetArea: optionalTrimmedString(120),\n youtubeId: optionalTrimmedString(40),\n thumbnailUrl: optionalTrimmedString(2000),\n posterUrl: optionalTrimmedString(2000),\n targetMuscles: z.array(muscleGroupSchema).max(16).default([]),\n sets: z.array(exerciseSetSchema).max(20).default([]),\n formTips: z.array(z.string().trim().max(400)).max(20).default([]),\n});\nexport type CreateExerciseBody = z.infer<typeof createExerciseBodySchema>;\n\nexport const updateExerciseBodySchema = createExerciseBodySchema.omit({ centerId: true }).partial();\nexport type UpdateExerciseBody = z.infer<typeof updateExerciseBodySchema>;\n\n// ─── Library query ───────────────────────────────────────────────────────────\n\nexport const exerciseLibraryQuerySchema = z.object({\n centerId: objectIdSchema.optional(),\n category: exerciseCategorySchema.optional(),\n difficulty: difficultySchema.optional(),\n q: optionalTrimmedString(120),\n});\nexport type ExerciseLibraryQuery = z.infer<typeof exerciseLibraryQuerySchema>;\n"]}
|
package/dist/messages.d.ts
CHANGED
|
@@ -197,6 +197,22 @@ export declare const SUCCESS_MESSAGE: {
|
|
|
197
197
|
readonly announcementDraftSaved: {
|
|
198
198
|
readonly title: "Draft saved";
|
|
199
199
|
};
|
|
200
|
+
readonly announcementDeleted: {
|
|
201
|
+
readonly title: "Announcement deleted";
|
|
202
|
+
};
|
|
203
|
+
readonly announcementCancelled: {
|
|
204
|
+
readonly title: "Announcement cancelled";
|
|
205
|
+
readonly description: "It will not be sent.";
|
|
206
|
+
};
|
|
207
|
+
readonly notificationHidden: {
|
|
208
|
+
readonly title: "Notification hidden";
|
|
209
|
+
};
|
|
210
|
+
readonly notificationRestored: {
|
|
211
|
+
readonly title: "Notification restored";
|
|
212
|
+
};
|
|
213
|
+
readonly allNotificationsRead: {
|
|
214
|
+
readonly title: "All caught up";
|
|
215
|
+
};
|
|
200
216
|
readonly mpinSet: {
|
|
201
217
|
readonly title: "PIN set";
|
|
202
218
|
};
|
|
@@ -294,6 +310,9 @@ export declare const ERROR_MESSAGE: {
|
|
|
294
310
|
readonly noCenterForPlans: "No gym center found. Add a center before creating plans.";
|
|
295
311
|
readonly noCenterForWorkouts: "No gym center found. Add a center before creating workouts.";
|
|
296
312
|
readonly noCenterForAnnouncements: "No gym center found. Add a center before sending announcements.";
|
|
313
|
+
readonly announcementAlreadySent: "That announcement has already gone out, so it cannot be cancelled.";
|
|
314
|
+
readonly notificationHideFailed: "Could not hide that notification.";
|
|
315
|
+
readonly notificationRestoreFailed: "Could not restore that notification.";
|
|
297
316
|
readonly planUnavailable: "That plan is not available right now.";
|
|
298
317
|
readonly membershipPlanRequired: "Choose a membership plan to continue";
|
|
299
318
|
/** The member was created, but the plan the owner picked did not stick. */
|
package/dist/messages.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;CAwBb,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAIrE,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;IAU1B,sEAAsE
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH;;;;GAIG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;CAwBb,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AAIrE,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;IAU1B,sEAAsE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ItB,CAAC;AAEnD,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,eAAe,CAAC;AAE7D,0DAA0D;AAC1D,eAAO,MAAM,mBAAmB;iCACV,MAAM,KAAG,aAAa;gCAIvB,MAAM,KAAG,aAAa;sCAIhB,MAAM,KAAG,aAAa;uCAIrB,MAAM,KAAG,aAAa;uCAGtB,MAAM,KAAG,aAAa;uCAItB,MAAM,KAAG,aAAa;CAIxC,CAAC;AAIX;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;IAiBxB,4EAA4E;;IAE5E,+EAA+E;;IAE/E,gFAAgF;;IAGhF,iDAAiD;;;IAKjD,kDAAkD;;IAElD;;;;OAIG;;IAEH;;;;OAIG;;IAEH,qEAAqE;;IAErE,2EAA2E;;IAE3E,wEAAwE;;;;;;;;;;;;;;IAoBxE,2EAA2E;;;;;;;;;;;;;;IAkB3E;;;OAGG;;;;IAMH,wEAAwE;;IAExE,uEAAuE;;IAEvE,yEAAyE;;IAEzE,8EAA8E;;IAE9E,0DAA0D;;;IAG1D;;;;OAIG;;IAIH,4EAA4E;;IAG5E,6DAA6D;;IAE7D,kDAAkD;;IAElD,+DAA+D;;IAE/D,sEAAsE;;;IAItE,kEAAkE;;;;IAIlE,uEAAuE;;IAEvE,8EAA8E;;;;;;;;;;;;;;;;;CAyBrC,CAAC;AAE5C,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,aAAa,CAAC;AAEzD,iDAAiD;AACjD,eAAO,MAAM,iBAAiB;8BACX,MAAM,KAAG,MAAM;IAChC,2DAA2D;sCAClC,MAAM,KAAG,MAAM;CAEhC,CAAC"}
|
package/dist/messages.js
CHANGED
|
@@ -147,6 +147,15 @@ export const SUCCESS_MESSAGE = {
|
|
|
147
147
|
announcementSent: { title: 'Announcement sent' },
|
|
148
148
|
announcementScheduled: { title: 'Announcement scheduled' },
|
|
149
149
|
announcementDraftSaved: { title: 'Draft saved' },
|
|
150
|
+
announcementDeleted: { title: 'Announcement deleted' },
|
|
151
|
+
announcementCancelled: {
|
|
152
|
+
title: 'Announcement cancelled',
|
|
153
|
+
description: 'It will not be sent.',
|
|
154
|
+
},
|
|
155
|
+
// Notification feed
|
|
156
|
+
notificationHidden: { title: 'Notification hidden' },
|
|
157
|
+
notificationRestored: { title: 'Notification restored' },
|
|
158
|
+
allNotificationsRead: { title: 'All caught up' },
|
|
150
159
|
// Security (role-switch PIN)
|
|
151
160
|
mpinSet: { title: 'PIN set' },
|
|
152
161
|
mpinReset: { title: 'Your PIN has been reset.' },
|
|
@@ -259,6 +268,10 @@ export const ERROR_MESSAGE = {
|
|
|
259
268
|
noCenterForPlans: 'No gym center found. Add a center before creating plans.',
|
|
260
269
|
noCenterForWorkouts: 'No gym center found. Add a center before creating workouts.',
|
|
261
270
|
noCenterForAnnouncements: 'No gym center found. Add a center before sending announcements.',
|
|
271
|
+
announcementAlreadySent: 'That announcement has already gone out, so it cannot be cancelled.',
|
|
272
|
+
// Notification feed
|
|
273
|
+
notificationHideFailed: 'Could not hide that notification.',
|
|
274
|
+
notificationRestoreFailed: 'Could not restore that notification.',
|
|
262
275
|
// Membership
|
|
263
276
|
planUnavailable: 'That plan is not available right now.',
|
|
264
277
|
membershipPlanRequired: 'Choose a membership plan to continue',
|
package/dist/messages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — API result messages\n * ====================================\n * Single source of truth for every user-facing SUCCESS and ERROR message the\n * product shows, plus the API error codes both sides key off.\n *\n * Why it lives here: the schema package is already the SSOT for data shapes,\n * types and validation. Result copy is part of that contract — the backend\n * raises a message, the client shows it, and neither should invent its own\n * wording. Both repos import from here, so copy changes land in one place and\n * can never drift between server and client.\n *\n * Usage:\n * backend → `throw new BadRequestError(ERROR_MESSAGE.centerAddressRequired)`\n * frontend → `showSuccess(...toast(SUCCESS_MESSAGE.profileUpdated))`\n *\n * @module gymmonk-schema/messages\n */\n\n// ─── API error codes ─────────────────────────────────────────────────────────\n\n/**\n * Machine-readable error codes returned in the API envelope\n * (`{ success: false, error: { code, message } }`). The client can branch on a\n * code; the message is what a human reads.\n */\nexport const ERROR_CODE = {\n // General\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n NOT_FOUND: 'NOT_FOUND',\n\n // Auth\n INVALID_TOKEN: 'INVALID_TOKEN',\n TOKEN_EXPIRED: 'TOKEN_EXPIRED',\n UNAUTHORIZED: 'UNAUTHORIZED',\n FORBIDDEN: 'FORBIDDEN',\n SESSION_INVALIDATED: 'SESSION_INVALIDATED',\n\n // User\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS',\n INVALID_ROLE: 'INVALID_ROLE',\n\n // Rate limiting\n RATE_LIMITED: 'RATE_LIMITED',\n RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',\n\n // Upstream / dependency unavailable\n SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',\n} as const;\n\nexport type ErrorCode = (typeof ERROR_CODE)[keyof typeof ERROR_CODE];\n\n// ─── Message shape ───────────────────────────────────────────────────────────\n\n/** A result message: a headline and an optional quieter second line. */\nexport interface ResultMessage {\n title: string;\n description?: string;\n}\n\n// ─── Success messages ────────────────────────────────────────────────────────\n\n/**\n * Confirmation shown after a write succeeds, keyed by action. Interpolating\n * entries are functions so the caller supplies the value without re-wording.\n */\nexport const SUCCESS_MESSAGE = {\n // Onboarding\n memberOnboardingComplete: {\n title: \"You're all set\",\n description: 'Welcome to GymMonk.',\n },\n ownerOnboardingComplete: {\n title: 'Your gym is ready',\n description: 'Welcome to GymMonk.',\n },\n /** Each wizard step is persisted on its own, so each one confirms. */\n onboardingStepSaved: { title: 'Saved' },\n\n // Identity & profile\n profileUpdated: { title: 'Profile updated' },\n organisationUpdated: { title: 'Organisation updated' },\n\n // Gym structure\n centerAdded: { title: 'Center added' },\n centerUpdated: { title: 'Center updated' },\n membershipPlanCreated: { title: 'Membership plan created' },\n membershipPlanUpdated: { title: 'Membership plan updated' },\n equipmentSaved: { title: 'Equipment updated' },\n\n // Membership (member-side)\n membershipUpdated: { title: 'Membership updated' },\n membershipRenewed: { title: 'Membership renewed' },\n membershipCancelled: { title: 'Membership cancelled' },\n membershipPauseRequested: {\n title: 'Pause request sent',\n description: 'Your gym will confirm the pause.',\n },\n\n // Owner SaaS subscription\n subscriptionUpdated: { title: 'Subscription updated' },\n\n // Training\n workoutPlanCreated: { title: 'Workout plan created' },\n workoutPlanUpdated: { title: 'Workout plan saved' },\n workoutPlanDeleted: {\n title: 'Workout plan deleted',\n description: 'Members on this plan no longer have one.',\n },\n workoutCreated: { title: 'Workout created' },\n workoutUpdated: { title: 'Workout saved' },\n workoutDeleted: { title: 'Workout removed' },\n workoutPlanAssigned: { title: 'Workout plan assigned' },\n\n // Roster (owner console)\n attendanceMarked: { title: 'Attendance saved' },\n memberMarkedInactive: {\n title: 'Member marked inactive',\n description: 'They can no longer check in.',\n },\n memberMarkedActive: { title: 'Member reactivated' },\n memberDeleted: { title: 'Member removed' },\n memberPlanAssigned: { title: 'Plan updated' },\n memberMembershipPaused: { title: 'Membership paused' },\n memberMembershipCancelled: { title: 'Membership cancelled' },\n paymentCollected: { title: 'Payment recorded' },\n\n // Sessions\n checkedIn: { title: 'Checked in', description: 'Your session has started.' },\n checkedOut: { title: 'Checked out', description: 'Session saved.' },\n checkInQrRotated: {\n title: 'New QR generated',\n description: 'Print it and replace the old poster.',\n },\n\n // Membership join requests\n membershipRequestSent: {\n title: 'Request sent',\n description: 'The gym will review it shortly.',\n },\n membershipRequestApproved: {\n title: 'Member approved',\n description: 'They can now check in at your gym.',\n },\n membershipRequestRejected: {\n title: 'Request declined',\n description: 'The member has been told.',\n },\n\n // Gym registration + platform review\n gymRegistered: {\n title: 'Gym submitted',\n description: 'Our team will review it and let you know.',\n },\n gymApproved: {\n title: 'Gym approved',\n description: 'It is now listed for members to find.',\n },\n gymRejected: {\n title: 'Gym rejected',\n description: 'The owner has been told.',\n },\n\n // Engagement\n feedbackSubmitted: {\n title: 'Feedback sent',\n description: 'Thank you for helping us improve.',\n },\n complaintSubmitted: {\n title: 'Complaint submitted',\n description: 'Your gym will look into it.',\n },\n announcementSent: { title: 'Announcement sent' },\n announcementScheduled: { title: 'Announcement scheduled' },\n announcementDraftSaved: { title: 'Draft saved' },\n\n // Security (role-switch PIN)\n mpinSet: { title: 'PIN set' },\n mpinReset: { title: 'Your PIN has been reset.' },\n mpinResetLinkSent: {\n title: \"We've emailed you a reset link\",\n description: 'Check your inbox.',\n },\n\n // ── Platform console (superadmin / platform manager) ────────────────────────\n platformRolesUpdated: { title: 'Platform roles updated' },\n platformUserSuspended: {\n title: 'Account suspended',\n description: 'They can no longer sign in.',\n },\n platformUserReinstated: { title: 'Account reinstated' },\n platformUserDeleted: {\n title: 'Account deleted',\n description: 'It is hidden everywhere but can still be restored.',\n },\n platformUserRestored: { title: 'Account restored' },\n platformGymDeleted: {\n title: 'Gym deleted',\n description: 'It is hidden everywhere but can still be restored.',\n },\n platformGymRestored: {\n title: 'Gym restored',\n description: 'It is back in the directory and its owner has the console again.',\n },\n} as const satisfies Record<string, ResultMessage>;\n\nexport type SuccessMessageKey = keyof typeof SUCCESS_MESSAGE;\n\n/** Success messages that name the thing they acted on. */\nexport const SUCCESS_MESSAGE_FOR = {\n memberAdded: (name: string): ResultMessage => ({\n title: 'Member added',\n description: `Share the invite with ${name}.`,\n }),\n staffAdded: (name: string): ResultMessage => ({\n title: 'Staff added',\n description: `Share the invite with ${name}.`,\n }),\n inviteClaimed: (gymName: string): ResultMessage => ({\n title: \"You're all set\",\n description: `Your account is linked to ${gymName}.`,\n }),\n roleSwitched: (roleLabel: string): ResultMessage => ({\n title: `Switched to ${roleLabel}`,\n }),\n gymApprovedFor: (gymName: string): ResultMessage => ({\n title: 'Gym approved',\n description: `${gymName} is now live on GymMonk.`,\n }),\n gymRejectedFor: (gymName: string): ResultMessage => ({\n title: 'Gym rejected',\n description: `The owner of ${gymName} has been told why.`,\n }),\n} as const;\n\n// ─── Error messages ──────────────────────────────────────────────────────────\n\n/**\n * Failure copy. Transport entries describe a request that never reached the\n * API; the rest are domain rules the backend enforces and the client can also\n * check up-front — same wording either way.\n */\nexport const ERROR_MESSAGE = {\n // Transport / generic\n generic: 'Something went wrong. Please try again.',\n network: 'Network error. Check your connection and try again.',\n timeout: 'That took too long. Please try again.',\n sessionExpired: 'Your session expired. Please sign in again.',\n\n // Client-side validation\n formInvalid: 'Please check the highlighted fields.',\n\n // Onboarding\n roleRequired: 'Choose a role to continue',\n ownerOnboardingFailed: 'We could not create your gym. Please try again.',\n memberOnboardingFailed: 'We could not save your details. Please try again.',\n\n // ── Gym registration (\"list your gym\") ─────────────────────────────────────\n gymRegistrationFailed: 'We could not register your gym. Please try again.',\n /** One organisation per account — registering a second is not supported. */\n gymAlreadyRegistered: 'You have already registered a gym on this account.',\n /** Registering a gym is something a MEMBER does, so the profile must exist. */\n gymRegistrationNeedsProfile: 'Finish setting up your profile before registering a gym.',\n /** Every owner action other than editing their own details, before approval. */\n gymAwaitingApproval:\n 'Your gym is waiting for approval. You can manage it once our team has reviewed it.',\n /** The reviewer turned the registration down. */\n gymRegistrationRejected: 'Your gym registration was not approved.',\n organisationNotFound: 'That gym could not be found.',\n\n // ── Platform console ────────────────────────────────────────────────────────\n /** The account is gone, or was already erased. */\n platformUserNotFound: 'That account could not be found.',\n /**\n * An admin acting on their OWN row. Suspending or deleting yourself takes away\n * the access needed to undo it, so the console refuses rather than letting one\n * mis-tap lock the platform's last superadmin out of it.\n */\n platformCannotActOnSelf: 'You cannot do that to your own account.',\n /**\n * Removing the last superadmin. `manage GymApproval` is held by nobody else,\n * so the gym review queue would become unreachable with no way back in short\n * of a database edit.\n */\n platformLastSuperadmin: 'The platform must keep at least one superadmin.',\n /** The typed confirmation did not match the record being deleted. */\n platformConfirmationMismatch: 'That did not match. Nothing was changed.',\n /** Two reviewers acting on the same registration; the second one loses. */\n organisationAlreadyDecided: 'Someone has already reviewed this gym.',\n /** A step failed to persist — the user stays put so nothing is lost. */\n onboardingStepSaveFailed: 'We could not save this step. Please try again.',\n\n // Gym structure prerequisites\n centerRequiredForPlan: 'Pick the center this plan belongs to.',\n planTierTaken: 'This center already has a plan on that tier. Pick another tier.',\n planVariantRequired: 'Add at least one pricing variant before saving the plan.',\n centerAddressRequired: 'Add the center address before creating it.',\n noCenterForPlans: 'No gym center found. Add a center before creating plans.',\n noCenterForWorkouts: 'No gym center found. Add a center before creating workouts.',\n noCenterForAnnouncements: 'No gym center found. Add a center before sending announcements.',\n\n // Membership\n planUnavailable: 'That plan is not available right now.',\n membershipPlanRequired: 'Choose a membership plan to continue',\n /** The member was created, but the plan the owner picked did not stick. */\n initialPlanNotAssigned:\n 'Member added, but the plan could not be assigned. Assign it from their profile.',\n noPlansToAssign: 'No membership plans yet. Create one to assign it while adding a member.',\n\n // Training\n workoutPlanRequired: 'Choose a plan to assign',\n // Roster (owner console)\n attendanceMarkFailed: 'Could not save that attendance. Please try again.',\n memberStatusFailed: \"Could not change that member's status. Please try again.\",\n memberDeleteFailed: 'Could not remove that member. Please try again.',\n memberPlanAssignFailed: 'Could not update that plan. Please try again.',\n memberPauseFailed: 'Could not pause that membership. Please try again.',\n memberCancelFailed: 'Could not cancel that membership. Please try again.',\n paymentCollectFailed: 'Could not record that payment. Please try again.',\n paymentAmountRequired: 'Enter the amount collected',\n pauseDatesRequired: 'Pick both pause dates',\n pauseDatesOrder: 'The end date has to be after the start date',\n /**\n * Attendance, workout plans and payments are all keyed on the central-auth\n * user, which an invited record does not have until the person claims it.\n */\n memberNotClaimed: 'This member has not claimed their invite yet.',\n\n // Sessions\n checkInFailed: 'Could not check you in. Please try again.',\n checkOutFailed: 'Could not check you out. Please try again.',\n /** The camera decoded a QR, but it is not a gymmonk check-in poster. */\n qrNotRecognised: 'That is not a gym check-in QR. Point at the poster at the gym.',\n /** A valid gymmonk QR, but for a gym the member does not belong to. */\n qrWrongGym: 'That QR belongs to a different gym.',\n /** The scanned code matches no center — a retired or mistyped poster. */\n qrUnknown: 'This QR is no longer valid. Ask the gym for the current poster.',\n /** Checking out with a poster from somewhere other than where you started. */\n qrWrongGymForCheckOut: 'Scan the QR at the gym where you checked in.',\n /** Manual entry only accepts a full, well-formed code. */\n checkInCodeInvalid: 'Enter the 16-character code printed under the QR.',\n checkInQrRotateFailed: 'Could not generate a new QR. Please try again.',\n /**\n * Ticking an exercise off records it against a live session, so there has to\n * be one. Shown when a member opens an exercise outside a workout and taps\n * Mark As Done.\n */\n noSessionToTrack: 'Check in at your gym to track this workout.',\n\n // ── Membership join requests ───────────────────────────────────────────────\n /** Scanned a valid poster, but the gym has not accepted this member yet. */\n membershipNotApproved:\n 'Your gym has not accepted your join request yet. You can check in once they do.',\n /** Accepted, but with no live plan — check-in needs both. */\n membershipNotActive: 'Your membership plan is not active. Renew it to start checking in again.',\n /** A second request while one is already open. */\n membershipRequestPending: 'You already have a request waiting with this gym.',\n /** Requesting a gym they are already an accepted member of. */\n membershipRequestAlreadyMember: 'You are already a member of this gym.',\n /** v1 memberships are single-center — leave the current gym first. */\n membershipRequestAlreadyAtAnotherGym:\n 'You already belong to a gym. Cancel that membership before joining another.',\n membershipRequestNotFound: 'That join request no longer exists.',\n /** Two staff acting on the same request; the second one loses. */\n membershipRequestAlreadyDecided: 'Someone has already answered this request.',\n membershipRequestFailed: 'Could not send your request. Please try again.',\n gymCodeUnknown: 'No gym found with that id. Check it with your gym.',\n /** Actions that only make sense once a gym has taken the member on. */\n noGymJoined: 'Join a gym first. You can find one from your Me tab.',\n /** Searching by name needs somewhere to look — see `gymSearchQuerySchema`. */\n gymSearchStateRequired: 'Pick a state to search gyms by name.',\n gymSearchNoResults: 'No gyms matched. Try a different area, or enter the gym id.',\n\n // Camera (QR scanning)\n cameraDenied: 'Camera access is blocked. Allow it in your browser settings to scan.',\n cameraUnavailable: 'No camera found on this device. Enter the code printed under the QR.',\n cameraInsecure: 'Scanning needs a secure (https) connection.',\n cameraFailed: 'Could not start the camera. Enter the code printed under the QR.',\n\n // Engagement\n feedbackRatingRequired: 'Choose a rating to submit your feedback',\n complaintIssueRequired: 'Choose the issue you are reporting',\n\n // Security (role-switch PIN)\n mpinIncorrect: 'Incorrect PIN.',\n mpinVerifyFailed: \"Couldn't verify. Try again.\",\n mpinSetFailed: \"Couldn't set your PIN. Try again.\",\n mpinMismatch: \"Those didn't match. Try again.\",\n mpinResetLinkFailed: \"Couldn't send the reset link. Try again.\",\n mpinResetFailed: \"Couldn't reset your PIN. Try again.\",\n\n // Uploads\n imageUploadFailed: 'Could not upload that image. Please try again.',\n imageProcessFailed: 'Could not process that image. Please try again.',\n} as const satisfies Record<string, string>;\n\nexport type ErrorMessageKey = keyof typeof ERROR_MESSAGE;\n\n/** Error messages that name a limit or value. */\nexport const ERROR_MESSAGE_FOR = {\n maxPhotos: (max: number): string => `You can add up to ${max} photos`,\n /** Role-switch PIN lockout, in whole minutes remaining. */\n mpinLockedOut: (minutes: number): string =>\n `Too many attempts. Try again in ${minutes} minute${minutes > 1 ? 's' : ''}.`,\n} as const;\n"]}
|
|
1
|
+
{"version":3,"file":"messages.js","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — API result messages\n * ====================================\n * Single source of truth for every user-facing SUCCESS and ERROR message the\n * product shows, plus the API error codes both sides key off.\n *\n * Why it lives here: the schema package is already the SSOT for data shapes,\n * types and validation. Result copy is part of that contract — the backend\n * raises a message, the client shows it, and neither should invent its own\n * wording. Both repos import from here, so copy changes land in one place and\n * can never drift between server and client.\n *\n * Usage:\n * backend → `throw new BadRequestError(ERROR_MESSAGE.centerAddressRequired)`\n * frontend → `showSuccess(...toast(SUCCESS_MESSAGE.profileUpdated))`\n *\n * @module gymmonk-schema/messages\n */\n\n// ─── API error codes ─────────────────────────────────────────────────────────\n\n/**\n * Machine-readable error codes returned in the API envelope\n * (`{ success: false, error: { code, message } }`). The client can branch on a\n * code; the message is what a human reads.\n */\nexport const ERROR_CODE = {\n // General\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n NOT_FOUND: 'NOT_FOUND',\n\n // Auth\n INVALID_TOKEN: 'INVALID_TOKEN',\n TOKEN_EXPIRED: 'TOKEN_EXPIRED',\n UNAUTHORIZED: 'UNAUTHORIZED',\n FORBIDDEN: 'FORBIDDEN',\n SESSION_INVALIDATED: 'SESSION_INVALIDATED',\n\n // User\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n USER_ALREADY_EXISTS: 'USER_ALREADY_EXISTS',\n INVALID_ROLE: 'INVALID_ROLE',\n\n // Rate limiting\n RATE_LIMITED: 'RATE_LIMITED',\n RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',\n\n // Upstream / dependency unavailable\n SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',\n} as const;\n\nexport type ErrorCode = (typeof ERROR_CODE)[keyof typeof ERROR_CODE];\n\n// ─── Message shape ───────────────────────────────────────────────────────────\n\n/** A result message: a headline and an optional quieter second line. */\nexport interface ResultMessage {\n title: string;\n description?: string;\n}\n\n// ─── Success messages ────────────────────────────────────────────────────────\n\n/**\n * Confirmation shown after a write succeeds, keyed by action. Interpolating\n * entries are functions so the caller supplies the value without re-wording.\n */\nexport const SUCCESS_MESSAGE = {\n // Onboarding\n memberOnboardingComplete: {\n title: \"You're all set\",\n description: 'Welcome to GymMonk.',\n },\n ownerOnboardingComplete: {\n title: 'Your gym is ready',\n description: 'Welcome to GymMonk.',\n },\n /** Each wizard step is persisted on its own, so each one confirms. */\n onboardingStepSaved: { title: 'Saved' },\n\n // Identity & profile\n profileUpdated: { title: 'Profile updated' },\n organisationUpdated: { title: 'Organisation updated' },\n\n // Gym structure\n centerAdded: { title: 'Center added' },\n centerUpdated: { title: 'Center updated' },\n membershipPlanCreated: { title: 'Membership plan created' },\n membershipPlanUpdated: { title: 'Membership plan updated' },\n equipmentSaved: { title: 'Equipment updated' },\n\n // Membership (member-side)\n membershipUpdated: { title: 'Membership updated' },\n membershipRenewed: { title: 'Membership renewed' },\n membershipCancelled: { title: 'Membership cancelled' },\n membershipPauseRequested: {\n title: 'Pause request sent',\n description: 'Your gym will confirm the pause.',\n },\n\n // Owner SaaS subscription\n subscriptionUpdated: { title: 'Subscription updated' },\n\n // Training\n workoutPlanCreated: { title: 'Workout plan created' },\n workoutPlanUpdated: { title: 'Workout plan saved' },\n workoutPlanDeleted: {\n title: 'Workout plan deleted',\n description: 'Members on this plan no longer have one.',\n },\n workoutCreated: { title: 'Workout created' },\n workoutUpdated: { title: 'Workout saved' },\n workoutDeleted: { title: 'Workout removed' },\n workoutPlanAssigned: { title: 'Workout plan assigned' },\n\n // Roster (owner console)\n attendanceMarked: { title: 'Attendance saved' },\n memberMarkedInactive: {\n title: 'Member marked inactive',\n description: 'They can no longer check in.',\n },\n memberMarkedActive: { title: 'Member reactivated' },\n memberDeleted: { title: 'Member removed' },\n memberPlanAssigned: { title: 'Plan updated' },\n memberMembershipPaused: { title: 'Membership paused' },\n memberMembershipCancelled: { title: 'Membership cancelled' },\n paymentCollected: { title: 'Payment recorded' },\n\n // Sessions\n checkedIn: { title: 'Checked in', description: 'Your session has started.' },\n checkedOut: { title: 'Checked out', description: 'Session saved.' },\n checkInQrRotated: {\n title: 'New QR generated',\n description: 'Print it and replace the old poster.',\n },\n\n // Membership join requests\n membershipRequestSent: {\n title: 'Request sent',\n description: 'The gym will review it shortly.',\n },\n membershipRequestApproved: {\n title: 'Member approved',\n description: 'They can now check in at your gym.',\n },\n membershipRequestRejected: {\n title: 'Request declined',\n description: 'The member has been told.',\n },\n\n // Gym registration + platform review\n gymRegistered: {\n title: 'Gym submitted',\n description: 'Our team will review it and let you know.',\n },\n gymApproved: {\n title: 'Gym approved',\n description: 'It is now listed for members to find.',\n },\n gymRejected: {\n title: 'Gym rejected',\n description: 'The owner has been told.',\n },\n\n // Engagement\n feedbackSubmitted: {\n title: 'Feedback sent',\n description: 'Thank you for helping us improve.',\n },\n complaintSubmitted: {\n title: 'Complaint submitted',\n description: 'Your gym will look into it.',\n },\n announcementSent: { title: 'Announcement sent' },\n announcementScheduled: { title: 'Announcement scheduled' },\n announcementDraftSaved: { title: 'Draft saved' },\n announcementDeleted: { title: 'Announcement deleted' },\n announcementCancelled: {\n title: 'Announcement cancelled',\n description: 'It will not be sent.',\n },\n\n // Notification feed\n notificationHidden: { title: 'Notification hidden' },\n notificationRestored: { title: 'Notification restored' },\n allNotificationsRead: { title: 'All caught up' },\n\n // Security (role-switch PIN)\n mpinSet: { title: 'PIN set' },\n mpinReset: { title: 'Your PIN has been reset.' },\n mpinResetLinkSent: {\n title: \"We've emailed you a reset link\",\n description: 'Check your inbox.',\n },\n\n // ── Platform console (superadmin / platform manager) ────────────────────────\n platformRolesUpdated: { title: 'Platform roles updated' },\n platformUserSuspended: {\n title: 'Account suspended',\n description: 'They can no longer sign in.',\n },\n platformUserReinstated: { title: 'Account reinstated' },\n platformUserDeleted: {\n title: 'Account deleted',\n description: 'It is hidden everywhere but can still be restored.',\n },\n platformUserRestored: { title: 'Account restored' },\n platformGymDeleted: {\n title: 'Gym deleted',\n description: 'It is hidden everywhere but can still be restored.',\n },\n platformGymRestored: {\n title: 'Gym restored',\n description: 'It is back in the directory and its owner has the console again.',\n },\n} as const satisfies Record<string, ResultMessage>;\n\nexport type SuccessMessageKey = keyof typeof SUCCESS_MESSAGE;\n\n/** Success messages that name the thing they acted on. */\nexport const SUCCESS_MESSAGE_FOR = {\n memberAdded: (name: string): ResultMessage => ({\n title: 'Member added',\n description: `Share the invite with ${name}.`,\n }),\n staffAdded: (name: string): ResultMessage => ({\n title: 'Staff added',\n description: `Share the invite with ${name}.`,\n }),\n inviteClaimed: (gymName: string): ResultMessage => ({\n title: \"You're all set\",\n description: `Your account is linked to ${gymName}.`,\n }),\n roleSwitched: (roleLabel: string): ResultMessage => ({\n title: `Switched to ${roleLabel}`,\n }),\n gymApprovedFor: (gymName: string): ResultMessage => ({\n title: 'Gym approved',\n description: `${gymName} is now live on GymMonk.`,\n }),\n gymRejectedFor: (gymName: string): ResultMessage => ({\n title: 'Gym rejected',\n description: `The owner of ${gymName} has been told why.`,\n }),\n} as const;\n\n// ─── Error messages ──────────────────────────────────────────────────────────\n\n/**\n * Failure copy. Transport entries describe a request that never reached the\n * API; the rest are domain rules the backend enforces and the client can also\n * check up-front — same wording either way.\n */\nexport const ERROR_MESSAGE = {\n // Transport / generic\n generic: 'Something went wrong. Please try again.',\n network: 'Network error. Check your connection and try again.',\n timeout: 'That took too long. Please try again.',\n sessionExpired: 'Your session expired. Please sign in again.',\n\n // Client-side validation\n formInvalid: 'Please check the highlighted fields.',\n\n // Onboarding\n roleRequired: 'Choose a role to continue',\n ownerOnboardingFailed: 'We could not create your gym. Please try again.',\n memberOnboardingFailed: 'We could not save your details. Please try again.',\n\n // ── Gym registration (\"list your gym\") ─────────────────────────────────────\n gymRegistrationFailed: 'We could not register your gym. Please try again.',\n /** One organisation per account — registering a second is not supported. */\n gymAlreadyRegistered: 'You have already registered a gym on this account.',\n /** Registering a gym is something a MEMBER does, so the profile must exist. */\n gymRegistrationNeedsProfile: 'Finish setting up your profile before registering a gym.',\n /** Every owner action other than editing their own details, before approval. */\n gymAwaitingApproval:\n 'Your gym is waiting for approval. You can manage it once our team has reviewed it.',\n /** The reviewer turned the registration down. */\n gymRegistrationRejected: 'Your gym registration was not approved.',\n organisationNotFound: 'That gym could not be found.',\n\n // ── Platform console ────────────────────────────────────────────────────────\n /** The account is gone, or was already erased. */\n platformUserNotFound: 'That account could not be found.',\n /**\n * An admin acting on their OWN row. Suspending or deleting yourself takes away\n * the access needed to undo it, so the console refuses rather than letting one\n * mis-tap lock the platform's last superadmin out of it.\n */\n platformCannotActOnSelf: 'You cannot do that to your own account.',\n /**\n * Removing the last superadmin. `manage GymApproval` is held by nobody else,\n * so the gym review queue would become unreachable with no way back in short\n * of a database edit.\n */\n platformLastSuperadmin: 'The platform must keep at least one superadmin.',\n /** The typed confirmation did not match the record being deleted. */\n platformConfirmationMismatch: 'That did not match. Nothing was changed.',\n /** Two reviewers acting on the same registration; the second one loses. */\n organisationAlreadyDecided: 'Someone has already reviewed this gym.',\n /** A step failed to persist — the user stays put so nothing is lost. */\n onboardingStepSaveFailed: 'We could not save this step. Please try again.',\n\n // Gym structure prerequisites\n centerRequiredForPlan: 'Pick the center this plan belongs to.',\n planTierTaken: 'This center already has a plan on that tier. Pick another tier.',\n planVariantRequired: 'Add at least one pricing variant before saving the plan.',\n centerAddressRequired: 'Add the center address before creating it.',\n noCenterForPlans: 'No gym center found. Add a center before creating plans.',\n noCenterForWorkouts: 'No gym center found. Add a center before creating workouts.',\n noCenterForAnnouncements: 'No gym center found. Add a center before sending announcements.',\n announcementAlreadySent: 'That announcement has already gone out, so it cannot be cancelled.',\n\n // Notification feed\n notificationHideFailed: 'Could not hide that notification.',\n notificationRestoreFailed: 'Could not restore that notification.',\n\n // Membership\n planUnavailable: 'That plan is not available right now.',\n membershipPlanRequired: 'Choose a membership plan to continue',\n /** The member was created, but the plan the owner picked did not stick. */\n initialPlanNotAssigned:\n 'Member added, but the plan could not be assigned. Assign it from their profile.',\n noPlansToAssign: 'No membership plans yet. Create one to assign it while adding a member.',\n\n // Training\n workoutPlanRequired: 'Choose a plan to assign',\n // Roster (owner console)\n attendanceMarkFailed: 'Could not save that attendance. Please try again.',\n memberStatusFailed: \"Could not change that member's status. Please try again.\",\n memberDeleteFailed: 'Could not remove that member. Please try again.',\n memberPlanAssignFailed: 'Could not update that plan. Please try again.',\n memberPauseFailed: 'Could not pause that membership. Please try again.',\n memberCancelFailed: 'Could not cancel that membership. Please try again.',\n paymentCollectFailed: 'Could not record that payment. Please try again.',\n paymentAmountRequired: 'Enter the amount collected',\n pauseDatesRequired: 'Pick both pause dates',\n pauseDatesOrder: 'The end date has to be after the start date',\n /**\n * Attendance, workout plans and payments are all keyed on the central-auth\n * user, which an invited record does not have until the person claims it.\n */\n memberNotClaimed: 'This member has not claimed their invite yet.',\n\n // Sessions\n checkInFailed: 'Could not check you in. Please try again.',\n checkOutFailed: 'Could not check you out. Please try again.',\n /** The camera decoded a QR, but it is not a gymmonk check-in poster. */\n qrNotRecognised: 'That is not a gym check-in QR. Point at the poster at the gym.',\n /** A valid gymmonk QR, but for a gym the member does not belong to. */\n qrWrongGym: 'That QR belongs to a different gym.',\n /** The scanned code matches no center — a retired or mistyped poster. */\n qrUnknown: 'This QR is no longer valid. Ask the gym for the current poster.',\n /** Checking out with a poster from somewhere other than where you started. */\n qrWrongGymForCheckOut: 'Scan the QR at the gym where you checked in.',\n /** Manual entry only accepts a full, well-formed code. */\n checkInCodeInvalid: 'Enter the 16-character code printed under the QR.',\n checkInQrRotateFailed: 'Could not generate a new QR. Please try again.',\n /**\n * Ticking an exercise off records it against a live session, so there has to\n * be one. Shown when a member opens an exercise outside a workout and taps\n * Mark As Done.\n */\n noSessionToTrack: 'Check in at your gym to track this workout.',\n\n // ── Membership join requests ───────────────────────────────────────────────\n /** Scanned a valid poster, but the gym has not accepted this member yet. */\n membershipNotApproved:\n 'Your gym has not accepted your join request yet. You can check in once they do.',\n /** Accepted, but with no live plan — check-in needs both. */\n membershipNotActive: 'Your membership plan is not active. Renew it to start checking in again.',\n /** A second request while one is already open. */\n membershipRequestPending: 'You already have a request waiting with this gym.',\n /** Requesting a gym they are already an accepted member of. */\n membershipRequestAlreadyMember: 'You are already a member of this gym.',\n /** v1 memberships are single-center — leave the current gym first. */\n membershipRequestAlreadyAtAnotherGym:\n 'You already belong to a gym. Cancel that membership before joining another.',\n membershipRequestNotFound: 'That join request no longer exists.',\n /** Two staff acting on the same request; the second one loses. */\n membershipRequestAlreadyDecided: 'Someone has already answered this request.',\n membershipRequestFailed: 'Could not send your request. Please try again.',\n gymCodeUnknown: 'No gym found with that id. Check it with your gym.',\n /** Actions that only make sense once a gym has taken the member on. */\n noGymJoined: 'Join a gym first. You can find one from your Me tab.',\n /** Searching by name needs somewhere to look — see `gymSearchQuerySchema`. */\n gymSearchStateRequired: 'Pick a state to search gyms by name.',\n gymSearchNoResults: 'No gyms matched. Try a different area, or enter the gym id.',\n\n // Camera (QR scanning)\n cameraDenied: 'Camera access is blocked. Allow it in your browser settings to scan.',\n cameraUnavailable: 'No camera found on this device. Enter the code printed under the QR.',\n cameraInsecure: 'Scanning needs a secure (https) connection.',\n cameraFailed: 'Could not start the camera. Enter the code printed under the QR.',\n\n // Engagement\n feedbackRatingRequired: 'Choose a rating to submit your feedback',\n complaintIssueRequired: 'Choose the issue you are reporting',\n\n // Security (role-switch PIN)\n mpinIncorrect: 'Incorrect PIN.',\n mpinVerifyFailed: \"Couldn't verify. Try again.\",\n mpinSetFailed: \"Couldn't set your PIN. Try again.\",\n mpinMismatch: \"Those didn't match. Try again.\",\n mpinResetLinkFailed: \"Couldn't send the reset link. Try again.\",\n mpinResetFailed: \"Couldn't reset your PIN. Try again.\",\n\n // Uploads\n imageUploadFailed: 'Could not upload that image. Please try again.',\n imageProcessFailed: 'Could not process that image. Please try again.',\n} as const satisfies Record<string, string>;\n\nexport type ErrorMessageKey = keyof typeof ERROR_MESSAGE;\n\n/** Error messages that name a limit or value. */\nexport const ERROR_MESSAGE_FOR = {\n maxPhotos: (max: number): string => `You can add up to ${max} photos`,\n /** Role-switch PIN lockout, in whole minutes remaining. */\n mpinLockedOut: (minutes: number): string =>\n `Too many attempts. Try again in ${minutes} minute${minutes > 1 ? 's' : ''}.`,\n} as const;\n"]}
|
package/dist/notification.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
export declare const notificationCategorySchema: z.ZodEnum<{
|
|
11
|
+
message: "message";
|
|
11
12
|
payment: "payment";
|
|
12
13
|
membership: "membership";
|
|
13
14
|
rest: "rest";
|
|
@@ -17,13 +18,30 @@ export declare const notificationCategorySchema: z.ZodEnum<{
|
|
|
17
18
|
challenge: "challenge";
|
|
18
19
|
fuel: "fuel";
|
|
19
20
|
announcement: "announcement";
|
|
21
|
+
social: "social";
|
|
20
22
|
system: "system";
|
|
21
23
|
}>;
|
|
22
24
|
export type NotificationCategory = z.infer<typeof notificationCategorySchema>;
|
|
25
|
+
/**
|
|
26
|
+
* The person a notification is ABOUT, when there is one.
|
|
27
|
+
*
|
|
28
|
+
* Denormalised on purpose: the feed renders their face beside the row, and
|
|
29
|
+
* joining every notification back to a user to draw one avatar is a query per
|
|
30
|
+
* row. It is a snapshot — a follower who later changes their photo keeps the old
|
|
31
|
+
* one on historic rows, which is correct for a feed that records what happened.
|
|
32
|
+
*
|
|
33
|
+
* `null` for anything the SYSTEM raised (payment due, gym approved).
|
|
34
|
+
*/
|
|
35
|
+
export declare const notificationActorSchema: z.ZodObject<{
|
|
36
|
+
name: z.ZodString;
|
|
37
|
+
avatarUrl: z.ZodNullable<z.ZodString>;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
export type NotificationActor = z.infer<typeof notificationActorSchema>;
|
|
23
40
|
export declare const notificationSchema: z.ZodObject<{
|
|
24
41
|
id: z.ZodString;
|
|
25
42
|
userId: z.ZodString;
|
|
26
43
|
category: z.ZodEnum<{
|
|
44
|
+
message: "message";
|
|
27
45
|
payment: "payment";
|
|
28
46
|
membership: "membership";
|
|
29
47
|
rest: "rest";
|
|
@@ -33,22 +51,45 @@ export declare const notificationSchema: z.ZodObject<{
|
|
|
33
51
|
challenge: "challenge";
|
|
34
52
|
fuel: "fuel";
|
|
35
53
|
announcement: "announcement";
|
|
54
|
+
social: "social";
|
|
36
55
|
system: "system";
|
|
37
56
|
}>;
|
|
38
57
|
title: z.ZodString;
|
|
39
58
|
body: z.ZodString;
|
|
40
59
|
actionUrl: z.ZodNullable<z.ZodString>;
|
|
60
|
+
actor: z.ZodNullable<z.ZodObject<{
|
|
61
|
+
name: z.ZodString;
|
|
62
|
+
avatarUrl: z.ZodNullable<z.ZodString>;
|
|
63
|
+
}, z.core.$strip>>;
|
|
41
64
|
readAt: z.ZodNullable<z.ZodISODateTime>;
|
|
65
|
+
hiddenAt: z.ZodNullable<z.ZodISODateTime>;
|
|
42
66
|
createdAt: z.ZodISODateTime;
|
|
43
67
|
}, z.core.$strip>;
|
|
44
68
|
export type AppNotification = z.infer<typeof notificationSchema>;
|
|
69
|
+
/**
|
|
70
|
+
* The feed's filter chips.
|
|
71
|
+
*
|
|
72
|
+
* `all` deliberately means "everything NOT hidden" rather than literally
|
|
73
|
+
* everything: hiding is the user saying they are done with a row, so putting it
|
|
74
|
+
* back in the default list would make the gesture pointless. `hidden` is the
|
|
75
|
+
* only view that shows them, which is also what makes it the way back.
|
|
76
|
+
*/
|
|
77
|
+
export declare const notificationFilterSchema: z.ZodEnum<{
|
|
78
|
+
all: "all";
|
|
79
|
+
unread: "unread";
|
|
80
|
+
read: "read";
|
|
81
|
+
hidden: "hidden";
|
|
82
|
+
}>;
|
|
83
|
+
export type NotificationFilter = z.infer<typeof notificationFilterSchema>;
|
|
45
84
|
export declare const notificationListQuerySchema: z.ZodObject<{
|
|
46
85
|
page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
47
86
|
limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
filter: z.ZodDefault<z.ZodEnum<{
|
|
88
|
+
all: "all";
|
|
89
|
+
unread: "unread";
|
|
90
|
+
read: "read";
|
|
91
|
+
hidden: "hidden";
|
|
92
|
+
}>>;
|
|
52
93
|
}, z.core.$strip>;
|
|
53
94
|
export type NotificationListQuery = z.infer<typeof notificationListQuerySchema>;
|
|
54
95
|
/** Mark specific notifications read; empty `ids` = mark all read. */
|
|
@@ -56,4 +97,16 @@ export declare const markNotificationsReadBodySchema: z.ZodObject<{
|
|
|
56
97
|
ids: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
57
98
|
}, z.core.$strip>;
|
|
58
99
|
export type MarkNotificationsReadBody = z.infer<typeof markNotificationsReadBodySchema>;
|
|
100
|
+
/**
|
|
101
|
+
* Hide or restore specific notifications.
|
|
102
|
+
*
|
|
103
|
+
* `ids` is REQUIRED and non-empty, unlike mark-read's "empty means all". Hiding
|
|
104
|
+
* is destructive to the view; an empty array arriving by accident (a mapped
|
|
105
|
+
* list that turned out to be empty) must not silently clear somebody's whole
|
|
106
|
+
* feed.
|
|
107
|
+
*/
|
|
108
|
+
export declare const hideNotificationsBodySchema: z.ZodObject<{
|
|
109
|
+
ids: z.ZodArray<z.ZodString>;
|
|
110
|
+
}, z.core.$strip>;
|
|
111
|
+
export type HideNotificationsBody = z.infer<typeof hideNotificationsBodySchema>;
|
|
59
112
|
//# sourceMappingURL=notification.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,0BAA0B
|
|
1
|
+
{"version":3,"file":"notification.d.ts","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;EAmBrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E;;;;;;;;;GASG;AACH,eAAO,MAAM,uBAAuB;;;iBAGlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkB7B,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAIjE;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;;EAA8C,CAAC;AACpF,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,2BAA2B;;;;;;;;;iBAEtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,qEAAqE;AACrE,eAAO,MAAM,+BAA+B;;iBAE1C,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,+BAA+B,CAAC,CAAC;AAExF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
package/dist/notification.js
CHANGED
|
@@ -19,8 +19,31 @@ export const notificationCategorySchema = z.enum([
|
|
|
19
19
|
'announcement',
|
|
20
20
|
'membership',
|
|
21
21
|
'payment',
|
|
22
|
+
/**
|
|
23
|
+
* A chat message. Split out of `system` — messages, new followers and
|
|
24
|
+
* platform decisions were all landing under one category, so the feed could
|
|
25
|
+
* not tell them apart and rendered the same icon for all three.
|
|
26
|
+
*/
|
|
27
|
+
'message',
|
|
28
|
+
/** Somebody followed you: the social graph, not the gym's admin. */
|
|
29
|
+
'social',
|
|
22
30
|
'system',
|
|
23
31
|
]);
|
|
32
|
+
// ─── Actor ───────────────────────────────────────────────────────────────────
|
|
33
|
+
/**
|
|
34
|
+
* The person a notification is ABOUT, when there is one.
|
|
35
|
+
*
|
|
36
|
+
* Denormalised on purpose: the feed renders their face beside the row, and
|
|
37
|
+
* joining every notification back to a user to draw one avatar is a query per
|
|
38
|
+
* row. It is a snapshot — a follower who later changes their photo keeps the old
|
|
39
|
+
* one on historic rows, which is correct for a feed that records what happened.
|
|
40
|
+
*
|
|
41
|
+
* `null` for anything the SYSTEM raised (payment due, gym approved).
|
|
42
|
+
*/
|
|
43
|
+
export const notificationActorSchema = z.object({
|
|
44
|
+
name: z.string(),
|
|
45
|
+
avatarUrl: z.string().nullable(),
|
|
46
|
+
});
|
|
24
47
|
// ─── Entity ──────────────────────────────────────────────────────────────────
|
|
25
48
|
export const notificationSchema = z.object({
|
|
26
49
|
id: objectIdSchema,
|
|
@@ -30,20 +53,43 @@ export const notificationSchema = z.object({
|
|
|
30
53
|
body: z.string(),
|
|
31
54
|
/** Optional deep-link the card opens. */
|
|
32
55
|
actionUrl: z.string().nullable(),
|
|
56
|
+
/** Who it is about, for the avatar. Null for system-raised rows. */
|
|
57
|
+
actor: notificationActorSchema.nullable(),
|
|
33
58
|
readAt: isoDateTimeSchema.nullable(),
|
|
59
|
+
/**
|
|
60
|
+
* When the user dismissed it. Hidden rows leave the default feed and stop
|
|
61
|
+
* counting toward the badge, but are NOT deleted — the Hidden filter can show
|
|
62
|
+
* them and restore them, because "swipe by accident" must be undoable.
|
|
63
|
+
*/
|
|
64
|
+
hiddenAt: isoDateTimeSchema.nullable(),
|
|
34
65
|
createdAt: isoDateTimeSchema,
|
|
35
66
|
});
|
|
36
67
|
// ─── Query ───────────────────────────────────────────────────────────────────
|
|
68
|
+
/**
|
|
69
|
+
* The feed's filter chips.
|
|
70
|
+
*
|
|
71
|
+
* `all` deliberately means "everything NOT hidden" rather than literally
|
|
72
|
+
* everything: hiding is the user saying they are done with a row, so putting it
|
|
73
|
+
* back in the default list would make the gesture pointless. `hidden` is the
|
|
74
|
+
* only view that shows them, which is also what makes it the way back.
|
|
75
|
+
*/
|
|
76
|
+
export const notificationFilterSchema = z.enum(['all', 'unread', 'read', 'hidden']);
|
|
37
77
|
export const notificationListQuerySchema = paginationSchema.extend({
|
|
38
|
-
|
|
39
|
-
// (any non-empty string is truthy), so parse the literal instead.
|
|
40
|
-
unreadOnly: z
|
|
41
|
-
.enum(['true', 'false'])
|
|
42
|
-
.optional()
|
|
43
|
-
.transform((v) => v === 'true'),
|
|
78
|
+
filter: notificationFilterSchema.default('all'),
|
|
44
79
|
});
|
|
45
80
|
/** Mark specific notifications read; empty `ids` = mark all read. */
|
|
46
81
|
export const markNotificationsReadBodySchema = z.object({
|
|
47
82
|
ids: z.array(objectIdSchema).default([]),
|
|
48
83
|
});
|
|
84
|
+
/**
|
|
85
|
+
* Hide or restore specific notifications.
|
|
86
|
+
*
|
|
87
|
+
* `ids` is REQUIRED and non-empty, unlike mark-read's "empty means all". Hiding
|
|
88
|
+
* is destructive to the view; an empty array arriving by accident (a mapped
|
|
89
|
+
* list that turned out to be empty) must not silently clear somebody's whole
|
|
90
|
+
* feed.
|
|
91
|
+
*/
|
|
92
|
+
export const hideNotificationsBodySchema = z.object({
|
|
93
|
+
ids: z.array(objectIdSchema).min(1, 'Nothing selected'),
|
|
94
|
+
});
|
|
49
95
|
//# sourceMappingURL=notification.js.map
|
package/dist/notification.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAElF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,IAAI,CAAC;IAC/C,MAAM;IACN,WAAW;IACX,OAAO;IACP,WAAW;IACX,MAAM;IACN,MAAM;IACN,cAAc;IACd,YAAY;IACZ,SAAS;IACT,QAAQ;CACT,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,cAAc;IAClB,MAAM,EAAE,cAAc;IACtB,QAAQ,EAAE,0BAA0B;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,yCAAyC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,MAAM,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACpC,SAAS,EAAE,iBAAiB;CAC7B,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"notification.js","sourceRoot":"","sources":["../src/notification.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAElF,gFAAgF;AAEhF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,IAAI,CAAC;IAC/C,MAAM;IACN,WAAW;IACX,OAAO;IACP,WAAW;IACX,MAAM;IACN,MAAM;IACN,cAAc;IACd,YAAY;IACZ,SAAS;IACT;;;;OAIG;IACH,SAAS;IACT,oEAAoE;IACpE,QAAQ;IACR,QAAQ;CACT,CAAC,CAAC;AAGH,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,EAAE,EAAE,cAAc;IAClB,MAAM,EAAE,cAAc;IACtB,QAAQ,EAAE,0BAA0B;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,yCAAyC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,oEAAoE;IACpE,KAAK,EAAE,uBAAuB,CAAC,QAAQ,EAAE;IACzC,MAAM,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACpC;;;;OAIG;IACH,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE;IACtC,SAAS,EAAE,iBAAiB;CAC7B,CAAC,CAAC;AAGH,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAGpF,MAAM,CAAC,MAAM,2BAA2B,GAAG,gBAAgB,CAAC,MAAM,CAAC;IACjE,MAAM,EAAE,wBAAwB,CAAC,OAAO,CAAC,KAAK,CAAC;CAChD,CAAC,CAAC;AAGH,qEAAqE;AACrE,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAC,MAAM,CAAC;IACtD,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAGH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC;CACxD,CAAC,CAAC","sourcesContent":["/**\n * gymmonk-schema — In-app notifications\n * =====================================\n * The member/owner notification feed. `unread` and relative time are DERIVED at\n * the edge from `readAt` / `createdAt`.\n *\n * @module gymmonk-schema/notification\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, paginationSchema } from './common.js';\n\n// ─── Category (also drives the feed icon) ────────────────────────────────────\n\nexport const notificationCategorySchema = z.enum([\n 'move',\n 'milestone',\n 'recap',\n 'challenge',\n 'rest',\n 'fuel',\n 'announcement',\n 'membership',\n 'payment',\n /**\n * A chat message. Split out of `system` — messages, new followers and\n * platform decisions were all landing under one category, so the feed could\n * not tell them apart and rendered the same icon for all three.\n */\n 'message',\n /** Somebody followed you: the social graph, not the gym's admin. */\n 'social',\n 'system',\n]);\nexport type NotificationCategory = z.infer<typeof notificationCategorySchema>;\n\n// ─── Actor ───────────────────────────────────────────────────────────────────\n\n/**\n * The person a notification is ABOUT, when there is one.\n *\n * Denormalised on purpose: the feed renders their face beside the row, and\n * joining every notification back to a user to draw one avatar is a query per\n * row. It is a snapshot — a follower who later changes their photo keeps the old\n * one on historic rows, which is correct for a feed that records what happened.\n *\n * `null` for anything the SYSTEM raised (payment due, gym approved).\n */\nexport const notificationActorSchema = z.object({\n name: z.string(),\n avatarUrl: z.string().nullable(),\n});\nexport type NotificationActor = z.infer<typeof notificationActorSchema>;\n\n// ─── Entity ──────────────────────────────────────────────────────────────────\n\nexport const notificationSchema = z.object({\n id: objectIdSchema,\n userId: objectIdSchema,\n category: notificationCategorySchema,\n title: z.string(),\n body: z.string(),\n /** Optional deep-link the card opens. */\n actionUrl: z.string().nullable(),\n /** Who it is about, for the avatar. Null for system-raised rows. */\n actor: notificationActorSchema.nullable(),\n readAt: isoDateTimeSchema.nullable(),\n /**\n * When the user dismissed it. Hidden rows leave the default feed and stop\n * counting toward the badge, but are NOT deleted — the Hidden filter can show\n * them and restore them, because \"swipe by accident\" must be undoable.\n */\n hiddenAt: isoDateTimeSchema.nullable(),\n createdAt: isoDateTimeSchema,\n});\nexport type AppNotification = z.infer<typeof notificationSchema>;\n\n// ─── Query ───────────────────────────────────────────────────────────────────\n\n/**\n * The feed's filter chips.\n *\n * `all` deliberately means \"everything NOT hidden\" rather than literally\n * everything: hiding is the user saying they are done with a row, so putting it\n * back in the default list would make the gesture pointless. `hidden` is the\n * only view that shows them, which is also what makes it the way back.\n */\nexport const notificationFilterSchema = z.enum(['all', 'unread', 'read', 'hidden']);\nexport type NotificationFilter = z.infer<typeof notificationFilterSchema>;\n\nexport const notificationListQuerySchema = paginationSchema.extend({\n filter: notificationFilterSchema.default('all'),\n});\nexport type NotificationListQuery = z.infer<typeof notificationListQuerySchema>;\n\n/** Mark specific notifications read; empty `ids` = mark all read. */\nexport const markNotificationsReadBodySchema = z.object({\n ids: z.array(objectIdSchema).default([]),\n});\nexport type MarkNotificationsReadBody = z.infer<typeof markNotificationsReadBodySchema>;\n\n/**\n * Hide or restore specific notifications.\n *\n * `ids` is REQUIRED and non-empty, unlike mark-read's \"empty means all\". Hiding\n * is destructive to the view; an empty array arriving by accident (a mapped\n * list that turned out to be empty) must not silently clear somebody's whole\n * feed.\n */\nexport const hideNotificationsBodySchema = z.object({\n ids: z.array(objectIdSchema).min(1, 'Nothing selected'),\n});\nexport type HideNotificationsBody = z.infer<typeof hideNotificationsBodySchema>;\n"]}
|
package/dist/workout-plan.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export declare const planDaySchema: z.ZodObject<{
|
|
|
97
97
|
export type PlanDay = z.infer<typeof planDaySchema>;
|
|
98
98
|
export declare const workoutPlanSummarySchema: z.ZodObject<{
|
|
99
99
|
id: z.ZodString;
|
|
100
|
-
centerId: z.ZodString
|
|
100
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
101
101
|
name: z.ZodString;
|
|
102
102
|
description: z.ZodNullable<z.ZodString>;
|
|
103
103
|
goals: z.ZodNullable<z.ZodString>;
|
|
@@ -108,7 +108,7 @@ export declare const workoutPlanSummarySchema: z.ZodObject<{
|
|
|
108
108
|
export type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;
|
|
109
109
|
export declare const workoutPlanSchema: z.ZodObject<{
|
|
110
110
|
id: z.ZodString;
|
|
111
|
-
centerId: z.ZodString
|
|
111
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
112
112
|
name: z.ZodString;
|
|
113
113
|
description: z.ZodNullable<z.ZodString>;
|
|
114
114
|
goals: z.ZodNullable<z.ZodString>;
|
|
@@ -152,7 +152,7 @@ export declare const workoutPlanSchema: z.ZodObject<{
|
|
|
152
152
|
}, z.core.$strip>;
|
|
153
153
|
export type WorkoutPlan = z.infer<typeof workoutPlanSchema>;
|
|
154
154
|
export declare const createWorkoutPlanBodySchema: z.ZodObject<{
|
|
155
|
-
centerId: z.ZodString
|
|
155
|
+
centerId: z.ZodNullable<z.ZodString>;
|
|
156
156
|
name: z.ZodString;
|
|
157
157
|
description: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
158
158
|
goals: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"workout-plan.d.ts","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,uEAAuE;AACvE,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;iBAY7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAGxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,wBAAwB;;;;;;;;;iBAyBnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAI5D,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;iBAetC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;iBAE5B,CAAC;AACb,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC"}
|
package/dist/workout-plan.js
CHANGED
|
@@ -46,7 +46,14 @@ export const planDaySchema = z.object({
|
|
|
46
46
|
// ─── Entity ──────────────────────────────────────────────────────────────────
|
|
47
47
|
export const workoutPlanSummarySchema = z.object({
|
|
48
48
|
id: objectIdSchema,
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* `null` = a PLATFORM template, offered to every gym; a center id = that
|
|
51
|
+
* gym's own routine, visible only to its people.
|
|
52
|
+
*
|
|
53
|
+
* See `createWorkoutPlanBodySchema.centerId` for why the global case is a
|
|
54
|
+
* null the caller must state rather than a field they may omit.
|
|
55
|
+
*/
|
|
56
|
+
centerId: objectIdSchema.nullable(),
|
|
50
57
|
name: z.string(),
|
|
51
58
|
description: z.string().nullable(),
|
|
52
59
|
/**
|
|
@@ -68,7 +75,15 @@ export const workoutPlanSchema = workoutPlanSummarySchema.extend({
|
|
|
68
75
|
});
|
|
69
76
|
// ─── Create / update body ────────────────────────────────────────────────────
|
|
70
77
|
export const createWorkoutPlanBodySchema = z.object({
|
|
71
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Which library this plan joins. `null` is the PLATFORM template shelf, which
|
|
80
|
+
* only platform staff may write to.
|
|
81
|
+
*
|
|
82
|
+
* Nullable rather than optional: omitting the field would quietly mean
|
|
83
|
+
* "global", so one forgetful client could publish a gym's programming to
|
|
84
|
+
* every competitor on the product. Going global has to be stated.
|
|
85
|
+
*/
|
|
86
|
+
centerId: objectIdSchema.nullable(),
|
|
72
87
|
name: z.string().trim().min(1, 'Plan name is required').max(120),
|
|
73
88
|
description: optionalTrimmedString(2000),
|
|
74
89
|
goals: optionalTrimmedString(400),
|
package/dist/workout-plan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,gFAAgF;AAEhF,uEAAuE;AACvE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,UAAU,EAAE,cAAc;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;CAC3C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,OAAO,EAAE,aAAa;IACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAChE,CAAC,CAAC;AAGH,gFAAgF;AAEhF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,cAAc;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,gBAAgB;IAC5B,QAAQ,EAAE,sBAAsB;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;CAC1B,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,aAAa;IACtB,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;CACvC,CAAC,CAAC;AAGH,gFAAgF;AAEhF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"workout-plan.js","sourceRoot":"","sources":["../src/workout-plan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — Workout plans (routines)\n * ==========================================\n * A weekly training routine an owner builds from library exercises and assigns\n * to members. Each day carries prescribed exercises (sets / reps / rest). The\n * prescription is stored by exercise ref; the API populates a summary for\n * rendering.\n *\n * @module gymmonk-schema/workout-plan\n */\n\nimport { z } from 'zod';\nimport { isoDateTimeSchema, objectIdSchema, optionalTrimmedString } from './common.js';\nimport { difficultySchema, exerciseCategorySchema } from './exercise.js';\nimport { weekdaySchema } from './shared.js';\n\n// ─── Prescription (stored input) ─────────────────────────────────────────────\n\n/** One exercise slot in a plan day, referencing a library exercise. */\nexport const planExerciseInputSchema = z.object({\n exerciseId: objectIdSchema,\n sets: z.number().int().min(1).max(20),\n reps: z.string().trim().min(1).max(40),\n restSec: z.number().int().min(0).max(3600),\n});\nexport type PlanExerciseInput = z.infer<typeof planExerciseInputSchema>;\n\nexport const workoutPlanDayInputSchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseInputSchema).max(30).default([]),\n});\nexport type WorkoutPlanDayInput = z.infer<typeof workoutPlanDayInputSchema>;\n\n// ─── Populated response shapes ───────────────────────────────────────────────\n\n/** A plan-day exercise with its populated library summary + prescription. */\nexport const planExerciseSchema = z.object({\n exerciseId: objectIdSchema,\n slug: z.string(),\n name: z.string(),\n description: z.string(),\n thumbnailUrl: z.string().nullable(),\n difficulty: difficultySchema,\n category: exerciseCategorySchema,\n targetArea: z.string(),\n sets: z.number().int(),\n reps: z.string(),\n restSec: z.number().int(),\n});\nexport type PlanExercise = z.infer<typeof planExerciseSchema>;\n\nexport const planDaySchema = z.object({\n weekday: weekdaySchema,\n exercises: z.array(planExerciseSchema),\n});\nexport type PlanDay = z.infer<typeof planDaySchema>;\n\n// ─── Entity ──────────────────────────────────────────────────────────────────\n\nexport const workoutPlanSummarySchema = z.object({\n id: objectIdSchema,\n /**\n * `null` = a PLATFORM template, offered to every gym; a center id = that\n * gym's own routine, visible only to its people.\n *\n * See `createWorkoutPlanBodySchema.centerId` for why the global case is a\n * null the caller must state rather than a field they may omit.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string(),\n description: z.string().nullable(),\n /**\n * What the plan is FOR (\"Strength, Endurance\"), as distinct from\n * `description`, the prose blurb on the plan card.\n *\n * `createWorkoutPlanBodySchema` has accepted `goals` from the start but no\n * read shape carried it, so the owner's Goals / Focus field was write-only —\n * and, until the Mongoose model gained the path, not even written. Reading it\n * back is what lets the plan be edited without silently clearing the field.\n */\n goals: z.string().nullable(),\n focusTags: z.array(z.string()),\n createdAt: isoDateTimeSchema,\n updatedAt: isoDateTimeSchema,\n});\nexport type WorkoutPlanSummary = z.infer<typeof workoutPlanSummarySchema>;\n\nexport const workoutPlanSchema = workoutPlanSummarySchema.extend({\n days: z.array(planDaySchema),\n});\nexport type WorkoutPlan = z.infer<typeof workoutPlanSchema>;\n\n// ─── Create / update body ────────────────────────────────────────────────────\n\nexport const createWorkoutPlanBodySchema = z.object({\n /**\n * Which library this plan joins. `null` is the PLATFORM template shelf, which\n * only platform staff may write to.\n *\n * Nullable rather than optional: omitting the field would quietly mean\n * \"global\", so one forgetful client could publish a gym's programming to\n * every competitor on the product. Going global has to be stated.\n */\n centerId: objectIdSchema.nullable(),\n name: z.string().trim().min(1, 'Plan name is required').max(120),\n description: optionalTrimmedString(2000),\n goals: optionalTrimmedString(400),\n focusTags: z.array(z.string().trim().max(40)).max(20).default([]),\n days: z.array(workoutPlanDayInputSchema).max(7).default([]),\n});\nexport type CreateWorkoutPlanBody = z.infer<typeof createWorkoutPlanBodySchema>;\n\nexport const updateWorkoutPlanBodySchema = createWorkoutPlanBodySchema\n .omit({ centerId: true })\n .partial();\nexport type UpdateWorkoutPlanBody = z.infer<typeof updateWorkoutPlanBodySchema>;\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gymmonk-schema",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Shared Zod schemas, enums and domain types for GymMonk (fitness SaaS) — single source of truth (SSOT) consumed by gymmonk-backend and gymmonk-web-client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|