gymmonk-schema 0.37.0 → 0.39.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/file.d.ts CHANGED
@@ -25,7 +25,7 @@ import { z } from 'zod';
25
25
  * `<folder>/<userId>/<timestamp>-<random><ext>`. That per-user prefix is what
26
26
  * makes ownership checkable on cleanup.
27
27
  */
28
- export declare const UPLOAD_FOLDERS: readonly ["profile-photos", "center-photos", "logos", "member-documents", "equipment-photos", "announcement-media", "exercise-media", "progress-photos", "feedback-media"];
28
+ export declare const UPLOAD_FOLDERS: readonly ["profile-photos", "center-photos", "logos", "member-documents", "equipment-photos", "announcement-media", "exercise-media", "progress-photos", "payment-proofs", "feedback-media"];
29
29
  export declare const uploadFolderSchema: z.ZodEnum<{
30
30
  "profile-photos": "profile-photos";
31
31
  "center-photos": "center-photos";
@@ -35,6 +35,7 @@ export declare const uploadFolderSchema: z.ZodEnum<{
35
35
  "announcement-media": "announcement-media";
36
36
  "exercise-media": "exercise-media";
37
37
  "progress-photos": "progress-photos";
38
+ "payment-proofs": "payment-proofs";
38
39
  "feedback-media": "feedback-media";
39
40
  }>;
40
41
  export type UploadFolder = z.infer<typeof uploadFolderSchema>;
@@ -82,6 +83,7 @@ export declare const signedUploadUrlBodySchema: z.ZodObject<{
82
83
  "announcement-media": "announcement-media";
83
84
  "exercise-media": "exercise-media";
84
85
  "progress-photos": "progress-photos";
86
+ "payment-proofs": "payment-proofs";
85
87
  "feedback-media": "feedback-media";
86
88
  }>;
87
89
  fileSize: z.ZodNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,4KAmBjB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;;;;;;;;EAAyB,CAAC;AACzD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wDAAwD;AACxD,eAAO,MAAM,yBAAyB,oFAM5B,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;EAAoC,CAAC;AACtE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAEpE,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;iBA0BlC,CAAC;AAEL,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,mDAAmD;AACnD,eAAO,MAAM,6BAA6B;;;;;iBAUxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAIpF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB;;iBAEnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,8LAqBjB,CAAC;AAEX,eAAO,MAAM,kBAAkB;;;;;;;;;;;EAAyB,CAAC;AACzD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,wDAAwD;AACxD,eAAO,MAAM,yBAAyB,oFAM5B,CAAC;AAEX,eAAO,MAAM,oBAAoB;;;;;;EAAoC,CAAC;AACtE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAEpE,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;iBA0BlC,CAAC;AAEL,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,mDAAmD;AACnD,eAAO,MAAM,6BAA6B;;;;;iBAUxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAIpF;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB;;iBAEnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
package/dist/file.js CHANGED
@@ -43,6 +43,8 @@ export const UPLOAD_FOLDERS = [
43
43
  'exercise-media',
44
44
  /** Progress photos a member uploads against a measurement entry. */
45
45
  'progress-photos',
46
+ /** Screenshot of a transfer, attached to a membership awaiting confirmation. */
47
+ 'payment-proofs',
46
48
  /** Screenshots and photos attached to feedback or a complaint. */
47
49
  'feedback-media',
48
50
  ];
package/dist/file.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — File uploads\n * =============================\n * Contracts for the signed-URL upload flow. GymMonk never streams file bytes\n * through the API: the browser asks the backend for a short-lived v4 signed\n * PUT URL, uploads straight to Google Cloud Storage, and stores the returned\n * PERMANENT public URL.\n *\n * The download URL is deliberately NOT signed. A signed read URL expires,\n * which would rot every image reference already written to Mongo; the bucket\n * instead grants `allUsers` object-viewer and we store the plain public URL.\n *\n * Mirrors reform-backend's `shared/schemas/file.schema.ts`.\n *\n * @module gymmonk-schema/file\n */\n\nimport { z } from 'zod';\n\n// ─── Folders ─────────────────────────────────────────────────────────────────\n\n/**\n * Every folder an upload may target. This is an allow-list, not a hint: the\n * backend rejects anything outside it, so a compromised client cannot scatter\n * objects across the bucket. Adding a new upload surface means adding it here\n * FIRST, then publishing the package.\n *\n * `userId` is appended by the backend, so the effective path is\n * `<folder>/<userId>/<timestamp>-<random><ext>`. That per-user prefix is what\n * makes ownership checkable on cleanup.\n */\nexport const UPLOAD_FOLDERS = [\n /** Member + owner + staff avatars. Square, cropped round in the UI. */\n 'profile-photos',\n /** Gym/center gallery photos. Multi-select, uncropped. */\n 'center-photos',\n /** Organisation and center logos. */\n 'logos',\n /** Member ID proof / address proof captured at the front desk. */\n 'member-documents',\n /** Equipment photos in the gym inventory. */\n 'equipment-photos',\n /** Images attached to an announcement. */\n 'announcement-media',\n /** Custom exercise thumbnails added by a gym. */\n 'exercise-media',\n /** Progress photos a member uploads against a measurement entry. */\n 'progress-photos',\n /** Screenshots and photos attached to feedback or a complaint. */\n 'feedback-media',\n] as const;\n\nexport const uploadFolderSchema = z.enum(UPLOAD_FOLDERS);\nexport type UploadFolder = z.infer<typeof uploadFolderSchema>;\n\n// ─── Content types ───────────────────────────────────────────────────────────\n\n/** MIME types the signed-URL endpoint will sign for. */\nexport const ALLOWED_UPLOAD_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/gif',\n 'application/pdf',\n] as const;\n\nexport const uploadMimeTypeSchema = z.enum(ALLOWED_UPLOAD_MIME_TYPES);\nexport type UploadMimeType = z.infer<typeof uploadMimeTypeSchema>;\n\n// ─── Size limits ─────────────────────────────────────────────────────────────\n\n/**\n * Default per-file ceiling, in MB. Validation runs on the RAW pick, before the\n * client-side optimizer shrinks it — a modern phone camera produces 8-12 MB\n * JPEGs that compress to well under 1 MB, so a tighter cap would reject\n * perfectly ordinary photos.\n */\nexport const MAX_UPLOAD_SIZE_MB = 10;\n\n/** Per-folder overrides. Documents may be larger scans than a photo. */\nexport const FOLDER_MAX_SIZE_MB: Partial<Record<UploadFolder, number>> = {\n 'member-documents': 20,\n};\n\nconst HARD_CAP_MB = Math.max(MAX_UPLOAD_SIZE_MB, ...Object.values(FOLDER_MAX_SIZE_MB));\n\n// ─── Signed upload URL ───────────────────────────────────────────────────────\n\n/**\n * Request body for `POST /api/v1/files/signed-url`.\n *\n * `fileName` is restricted to a safe charset because it becomes part of the GCS\n * object path — the client sanitises before sending, and this rejects anything\n * that slipped through (path separators, control characters, unicode tricks).\n */\nexport const signedUploadUrlBodySchema = z\n .object({\n fileName: z\n .string()\n .min(1)\n .max(255)\n .regex(/^[a-zA-Z0-9_.-]+$/, 'Invalid file name'),\n contentType: uploadMimeTypeSchema,\n folder: uploadFolderSchema,\n fileSize: z\n .number()\n .int()\n .min(1)\n .max(HARD_CAP_MB * 1024 * 1024, `File must be smaller than ${HARD_CAP_MB}MB`),\n })\n .superRefine((data, ctx) => {\n // Tighten to the per-folder cap. The outer `.max` is only the widest\n // ceiling any folder allows; this is the one that actually applies.\n const capMb = FOLDER_MAX_SIZE_MB[data.folder] ?? MAX_UPLOAD_SIZE_MB;\n if (data.fileSize > capMb * 1024 * 1024) {\n ctx.addIssue({\n code: 'custom',\n path: ['fileSize'],\n message: `File must be smaller than ${capMb}MB for ${data.folder}`,\n });\n }\n });\n\nexport type SignedUploadUrlBody = z.infer<typeof signedUploadUrlBodySchema>;\n\n/** Response of `POST /api/v1/files/signed-url`. */\nexport const signedUploadUrlResponseSchema = z.object({\n /** Short-lived v4 signed URL — PUT the bytes here. */\n uploadUrl: z.string(),\n /** Permanent public URL. This is what gets stored in Mongo. */\n downloadUrl: z.string(),\n /** Object path inside the bucket, without the bucket prefix. Used to\n * delete an object the user abandoned before saving. */\n filePath: z.string(),\n /** When `uploadUrl` stops working. */\n expiresAt: z.iso.datetime(),\n});\n\nexport type SignedUploadUrlResponse = z.infer<typeof signedUploadUrlResponseSchema>;\n\n// ─── Cleanup ─────────────────────────────────────────────────────────────────\n\n/**\n * Body for `POST /api/v1/files/cleanup-uploads`. Called when a user removes a\n * photo they uploaded but never saved, so the orphaned object does not sit in\n * the bucket forever.\n *\n * Ownership is enforced per-path from the `userId` segment the backend embedded\n * at signing time. Paths belonging to someone else are skipped silently rather\n * than 403-ing, so one foreign entry cannot void a legitimate batch.\n */\nexport const cleanupUploadsBodySchema = z.object({\n filePaths: z.array(z.string().min(1)).min(1).max(20),\n});\n\nexport type CleanupUploadsBody = z.infer<typeof cleanupUploadsBodySchema>;\n\nexport const cleanupUploadsResponseSchema = z.object({\n deleted: z.number().int().min(0),\n skipped: z.number().int().min(0),\n});\n\nexport type CleanupUploadsResponse = z.infer<typeof cleanupUploadsResponseSchema>;\n"]}
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gymmonk-schema — File uploads\n * =============================\n * Contracts for the signed-URL upload flow. GymMonk never streams file bytes\n * through the API: the browser asks the backend for a short-lived v4 signed\n * PUT URL, uploads straight to Google Cloud Storage, and stores the returned\n * PERMANENT public URL.\n *\n * The download URL is deliberately NOT signed. A signed read URL expires,\n * which would rot every image reference already written to Mongo; the bucket\n * instead grants `allUsers` object-viewer and we store the plain public URL.\n *\n * Mirrors reform-backend's `shared/schemas/file.schema.ts`.\n *\n * @module gymmonk-schema/file\n */\n\nimport { z } from 'zod';\n\n// ─── Folders ─────────────────────────────────────────────────────────────────\n\n/**\n * Every folder an upload may target. This is an allow-list, not a hint: the\n * backend rejects anything outside it, so a compromised client cannot scatter\n * objects across the bucket. Adding a new upload surface means adding it here\n * FIRST, then publishing the package.\n *\n * `userId` is appended by the backend, so the effective path is\n * `<folder>/<userId>/<timestamp>-<random><ext>`. That per-user prefix is what\n * makes ownership checkable on cleanup.\n */\nexport const UPLOAD_FOLDERS = [\n /** Member + owner + staff avatars. Square, cropped round in the UI. */\n 'profile-photos',\n /** Gym/center gallery photos. Multi-select, uncropped. */\n 'center-photos',\n /** Organisation and center logos. */\n 'logos',\n /** Member ID proof / address proof captured at the front desk. */\n 'member-documents',\n /** Equipment photos in the gym inventory. */\n 'equipment-photos',\n /** Images attached to an announcement. */\n 'announcement-media',\n /** Custom exercise thumbnails added by a gym. */\n 'exercise-media',\n /** Progress photos a member uploads against a measurement entry. */\n 'progress-photos',\n /** Screenshot of a transfer, attached to a membership awaiting confirmation. */\n 'payment-proofs',\n /** Screenshots and photos attached to feedback or a complaint. */\n 'feedback-media',\n] as const;\n\nexport const uploadFolderSchema = z.enum(UPLOAD_FOLDERS);\nexport type UploadFolder = z.infer<typeof uploadFolderSchema>;\n\n// ─── Content types ───────────────────────────────────────────────────────────\n\n/** MIME types the signed-URL endpoint will sign for. */\nexport const ALLOWED_UPLOAD_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/webp',\n 'image/gif',\n 'application/pdf',\n] as const;\n\nexport const uploadMimeTypeSchema = z.enum(ALLOWED_UPLOAD_MIME_TYPES);\nexport type UploadMimeType = z.infer<typeof uploadMimeTypeSchema>;\n\n// ─── Size limits ─────────────────────────────────────────────────────────────\n\n/**\n * Default per-file ceiling, in MB. Validation runs on the RAW pick, before the\n * client-side optimizer shrinks it — a modern phone camera produces 8-12 MB\n * JPEGs that compress to well under 1 MB, so a tighter cap would reject\n * perfectly ordinary photos.\n */\nexport const MAX_UPLOAD_SIZE_MB = 10;\n\n/** Per-folder overrides. Documents may be larger scans than a photo. */\nexport const FOLDER_MAX_SIZE_MB: Partial<Record<UploadFolder, number>> = {\n 'member-documents': 20,\n};\n\nconst HARD_CAP_MB = Math.max(MAX_UPLOAD_SIZE_MB, ...Object.values(FOLDER_MAX_SIZE_MB));\n\n// ─── Signed upload URL ───────────────────────────────────────────────────────\n\n/**\n * Request body for `POST /api/v1/files/signed-url`.\n *\n * `fileName` is restricted to a safe charset because it becomes part of the GCS\n * object path — the client sanitises before sending, and this rejects anything\n * that slipped through (path separators, control characters, unicode tricks).\n */\nexport const signedUploadUrlBodySchema = z\n .object({\n fileName: z\n .string()\n .min(1)\n .max(255)\n .regex(/^[a-zA-Z0-9_.-]+$/, 'Invalid file name'),\n contentType: uploadMimeTypeSchema,\n folder: uploadFolderSchema,\n fileSize: z\n .number()\n .int()\n .min(1)\n .max(HARD_CAP_MB * 1024 * 1024, `File must be smaller than ${HARD_CAP_MB}MB`),\n })\n .superRefine((data, ctx) => {\n // Tighten to the per-folder cap. The outer `.max` is only the widest\n // ceiling any folder allows; this is the one that actually applies.\n const capMb = FOLDER_MAX_SIZE_MB[data.folder] ?? MAX_UPLOAD_SIZE_MB;\n if (data.fileSize > capMb * 1024 * 1024) {\n ctx.addIssue({\n code: 'custom',\n path: ['fileSize'],\n message: `File must be smaller than ${capMb}MB for ${data.folder}`,\n });\n }\n });\n\nexport type SignedUploadUrlBody = z.infer<typeof signedUploadUrlBodySchema>;\n\n/** Response of `POST /api/v1/files/signed-url`. */\nexport const signedUploadUrlResponseSchema = z.object({\n /** Short-lived v4 signed URL — PUT the bytes here. */\n uploadUrl: z.string(),\n /** Permanent public URL. This is what gets stored in Mongo. */\n downloadUrl: z.string(),\n /** Object path inside the bucket, without the bucket prefix. Used to\n * delete an object the user abandoned before saving. */\n filePath: z.string(),\n /** When `uploadUrl` stops working. */\n expiresAt: z.iso.datetime(),\n});\n\nexport type SignedUploadUrlResponse = z.infer<typeof signedUploadUrlResponseSchema>;\n\n// ─── Cleanup ─────────────────────────────────────────────────────────────────\n\n/**\n * Body for `POST /api/v1/files/cleanup-uploads`. Called when a user removes a\n * photo they uploaded but never saved, so the orphaned object does not sit in\n * the bucket forever.\n *\n * Ownership is enforced per-path from the `userId` segment the backend embedded\n * at signing time. Paths belonging to someone else are skipped silently rather\n * than 403-ing, so one foreign entry cannot void a legitimate batch.\n */\nexport const cleanupUploadsBodySchema = z.object({\n filePaths: z.array(z.string().min(1)).min(1).max(20),\n});\n\nexport type CleanupUploadsBody = z.infer<typeof cleanupUploadsBodySchema>;\n\nexport const cleanupUploadsResponseSchema = z.object({\n deleted: z.number().int().min(0),\n skipped: z.number().int().min(0),\n});\n\nexport type CleanupUploadsResponse = z.infer<typeof cleanupUploadsResponseSchema>;\n"]}
@@ -201,4 +201,37 @@ export declare const gymRegistrationBodySchema: z.ZodObject<{
201
201
  }, z.core.$strip>;
202
202
  }, z.core.$strip>;
203
203
  export type GymRegistrationBody = z.infer<typeof gymRegistrationBodySchema>;
204
+ /**
205
+ * The wizard's UI-shaped, partially-filled form, persisted a STEP AT A TIME.
206
+ *
207
+ * Opaque to the backend by design — the client owns the form shape, and what is
208
+ * stored here is re-validated strictly by `gymRegistrationBodySchema` at submit.
209
+ * Keys are form field names; the backend caps the stored size.
210
+ *
211
+ * ── Why the wizard needs its own cursor ─────────────────────────────────────
212
+ * Not the onboarding cursor. That one belongs to onboarding, a flow this user
213
+ * finished long ago and can no longer enter, and writing a `step` into it would
214
+ * move the resume target of a different wizard. This is a separate record with
215
+ * its own lifecycle: it starts when somebody begins describing their gym, and
216
+ * it is retired the moment the gym is actually submitted.
217
+ */
218
+ export declare const gymRegistrationDraftSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
219
+ export type GymRegistrationDraft = z.infer<typeof gymRegistrationDraftSchema>;
220
+ /**
221
+ * `GET /gym-registration/draft` — how far the caller got and what they typed.
222
+ *
223
+ * `step: 0` with no draft is the ordinary "never started" answer, so the client
224
+ * has one shape to read rather than a null to branch on.
225
+ */
226
+ export declare const gymRegistrationProgressSchema: z.ZodObject<{
227
+ step: z.ZodNumber;
228
+ draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
229
+ }, z.core.$strip>;
230
+ export type GymRegistrationProgress = z.infer<typeof gymRegistrationProgressSchema>;
231
+ /** `PUT /gym-registration/draft` body — any subset, merged server-side. */
232
+ export declare const gymRegistrationProgressUpdateSchema: z.ZodObject<{
233
+ step: z.ZodOptional<z.ZodNumber>;
234
+ draft: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
235
+ }, z.core.$strip>;
236
+ export type GymRegistrationProgressUpdate = z.infer<typeof gymRegistrationProgressUpdateSchema>;
204
237
  //# sourceMappingURL=gym-registration.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"gym-registration.d.ts","sourceRoot":"","sources":["../src/gym-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,sEAAsE;AACtE,eAAO,MAAM,sBAAsB;;;iBAGjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
1
+ {"version":3,"file":"gym-registration.d.ts","sourceRoot":"","sources":["../src/gym-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,sEAAsE;AACtE,eAAO,MAAM,sBAAsB;;;iBAGjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,0BAA0B,wCAAoC,CAAC;AAC5E,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B;;;iBAGxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF,2EAA2E;AAC3E,eAAO,MAAM,mCAAmC;;;iBAKpC,CAAC;AACb,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAC"}
@@ -23,6 +23,10 @@
23
23
  */
24
24
  import { z } from 'zod';
25
25
  import { createCenterBodySchema } from './center.js';
26
+ // The wizard's own step count, so the resume cursor below cannot be capped at a
27
+ // number the wizard has outgrown. `onboarding-form` imports nothing from here,
28
+ // so this is a one-way edge, not a cycle.
29
+ import { GYM_REGISTRATION_TOTAL_STEPS } from './onboarding-form.js';
26
30
  import { createOrganisationBodySchema } from './organisation.js';
27
31
  /** The SaaS plan the owner selects at the final registration step. */
28
32
  export const gymPlanSelectionSchema = z.object({
@@ -34,4 +38,37 @@ export const gymRegistrationBodySchema = z.object({
34
38
  center: createCenterBodySchema,
35
39
  subscription: gymPlanSelectionSchema,
36
40
  });
41
+ // ─── Resume: the per-step draft ──────────────────────────────────────────────
42
+ /**
43
+ * The wizard's UI-shaped, partially-filled form, persisted a STEP AT A TIME.
44
+ *
45
+ * Opaque to the backend by design — the client owns the form shape, and what is
46
+ * stored here is re-validated strictly by `gymRegistrationBodySchema` at submit.
47
+ * Keys are form field names; the backend caps the stored size.
48
+ *
49
+ * ── Why the wizard needs its own cursor ─────────────────────────────────────
50
+ * Not the onboarding cursor. That one belongs to onboarding, a flow this user
51
+ * finished long ago and can no longer enter, and writing a `step` into it would
52
+ * move the resume target of a different wizard. This is a separate record with
53
+ * its own lifecycle: it starts when somebody begins describing their gym, and
54
+ * it is retired the moment the gym is actually submitted.
55
+ */
56
+ export const gymRegistrationDraftSchema = z.record(z.string(), z.unknown());
57
+ /**
58
+ * `GET /gym-registration/draft` — how far the caller got and what they typed.
59
+ *
60
+ * `step: 0` with no draft is the ordinary "never started" answer, so the client
61
+ * has one shape to read rather than a null to branch on.
62
+ */
63
+ export const gymRegistrationProgressSchema = z.object({
64
+ step: z.number().int().min(0).max(GYM_REGISTRATION_TOTAL_STEPS),
65
+ draft: gymRegistrationDraftSchema.optional(),
66
+ });
67
+ /** `PUT /gym-registration/draft` body — any subset, merged server-side. */
68
+ export const gymRegistrationProgressUpdateSchema = z
69
+ .object({
70
+ step: z.number().int().min(0).max(GYM_REGISTRATION_TOTAL_STEPS),
71
+ draft: gymRegistrationDraftSchema,
72
+ })
73
+ .partial();
37
74
  //# sourceMappingURL=gym-registration.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gym-registration.js","sourceRoot":"","sources":["../src/gym-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAEjE,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,YAAY,EAAE,4BAA4B;IAC1C,MAAM,EAAE,sBAAsB;IAC9B,YAAY,EAAE,sBAAsB;CACrC,CAAC,CAAC","sourcesContent":["/**\n * gymmonk-schema — Gym registration\n * =================================\n * \"List your gym on GymMonk\" — the payload a signed-in MEMBER submits to create\n * the business they run.\n *\n * This used to be owner onboarding, a fork taken before the user had seen\n * anything. It is now an ordinary action taken from the Me tab by somebody who\n * already has an account, and that changes what it has to ask for:\n *\n * - NO personal details. Name, gender, date of birth, phone and photo were\n * all captured at onboarding. Asking again would be asking the same person\n * the same questions twice and then having two answers to keep in step.\n * - NO automatic membership of their own gym. Owning a gym and training at\n * one are separate things — an owner keeps the single member identity they\n * registered with, and is free to be a paying member of somebody else's gym.\n *\n * The submitted organisation starts `pending` and is invisible in the member\n * gym directory until a superadmin or platform manager approves it\n * (`organisationApprovalStatusSchema`).\n *\n * @module gymmonk-schema/gym-registration\n */\n\nimport { z } from 'zod';\nimport { createCenterBodySchema } from './center.js';\nimport { createOrganisationBodySchema } from './organisation.js';\n\n/** The SaaS plan the owner selects at the final registration step. */\nexport const gymPlanSelectionSchema = z.object({\n planId: z.string().trim().min(1),\n tenureId: z.string().trim().min(1).nullable(),\n});\nexport type GymPlanSelection = z.infer<typeof gymPlanSelectionSchema>;\n\nexport const gymRegistrationBodySchema = z.object({\n organisation: createOrganisationBodySchema,\n center: createCenterBodySchema,\n subscription: gymPlanSelectionSchema,\n});\nexport type GymRegistrationBody = z.infer<typeof gymRegistrationBodySchema>;\n"]}
1
+ {"version":3,"file":"gym-registration.js","sourceRoot":"","sources":["../src/gym-registration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,gFAAgF;AAChF,+EAA+E;AAC/E,0CAA0C;AAC1C,OAAO,EAAE,4BAA4B,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAEjE,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CAC9C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,YAAY,EAAE,4BAA4B;IAC1C,MAAM,EAAE,sBAAsB;IAC9B,YAAY,EAAE,sBAAsB;CACrC,CAAC,CAAC;AAGH,gFAAgF;AAEhF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAG5E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC;IACpD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAA4B,CAAC;IAC/D,KAAK,EAAE,0BAA0B,CAAC,QAAQ,EAAE;CAC7C,CAAC,CAAC;AAGH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC;KACjD,MAAM,CAAC;IACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAA4B,CAAC;IAC/D,KAAK,EAAE,0BAA0B;CAClC,CAAC;KACD,OAAO,EAAE,CAAC","sourcesContent":["/**\n * gymmonk-schema — Gym registration\n * =================================\n * \"List your gym on GymMonk\" — the payload a signed-in MEMBER submits to create\n * the business they run.\n *\n * This used to be owner onboarding, a fork taken before the user had seen\n * anything. It is now an ordinary action taken from the Me tab by somebody who\n * already has an account, and that changes what it has to ask for:\n *\n * - NO personal details. Name, gender, date of birth, phone and photo were\n * all captured at onboarding. Asking again would be asking the same person\n * the same questions twice and then having two answers to keep in step.\n * - NO automatic membership of their own gym. Owning a gym and training at\n * one are separate things — an owner keeps the single member identity they\n * registered with, and is free to be a paying member of somebody else's gym.\n *\n * The submitted organisation starts `pending` and is invisible in the member\n * gym directory until a superadmin or platform manager approves it\n * (`organisationApprovalStatusSchema`).\n *\n * @module gymmonk-schema/gym-registration\n */\n\nimport { z } from 'zod';\nimport { createCenterBodySchema } from './center.js';\n// The wizard's own step count, so the resume cursor below cannot be capped at a\n// number the wizard has outgrown. `onboarding-form` imports nothing from here,\n// so this is a one-way edge, not a cycle.\nimport { GYM_REGISTRATION_TOTAL_STEPS } from './onboarding-form.js';\nimport { createOrganisationBodySchema } from './organisation.js';\n\n/** The SaaS plan the owner selects at the final registration step. */\nexport const gymPlanSelectionSchema = z.object({\n planId: z.string().trim().min(1),\n tenureId: z.string().trim().min(1).nullable(),\n});\nexport type GymPlanSelection = z.infer<typeof gymPlanSelectionSchema>;\n\nexport const gymRegistrationBodySchema = z.object({\n organisation: createOrganisationBodySchema,\n center: createCenterBodySchema,\n subscription: gymPlanSelectionSchema,\n});\nexport type GymRegistrationBody = z.infer<typeof gymRegistrationBodySchema>;\n\n// ─── Resume: the per-step draft ──────────────────────────────────────────────\n\n/**\n * The wizard's UI-shaped, partially-filled form, persisted a STEP AT A TIME.\n *\n * Opaque to the backend by design — the client owns the form shape, and what is\n * stored here is re-validated strictly by `gymRegistrationBodySchema` at submit.\n * Keys are form field names; the backend caps the stored size.\n *\n * ── Why the wizard needs its own cursor ─────────────────────────────────────\n * Not the onboarding cursor. That one belongs to onboarding, a flow this user\n * finished long ago and can no longer enter, and writing a `step` into it would\n * move the resume target of a different wizard. This is a separate record with\n * its own lifecycle: it starts when somebody begins describing their gym, and\n * it is retired the moment the gym is actually submitted.\n */\nexport const gymRegistrationDraftSchema = z.record(z.string(), z.unknown());\nexport type GymRegistrationDraft = z.infer<typeof gymRegistrationDraftSchema>;\n\n/**\n * `GET /gym-registration/draft` — how far the caller got and what they typed.\n *\n * `step: 0` with no draft is the ordinary \"never started\" answer, so the client\n * has one shape to read rather than a null to branch on.\n */\nexport const gymRegistrationProgressSchema = z.object({\n step: z.number().int().min(0).max(GYM_REGISTRATION_TOTAL_STEPS),\n draft: gymRegistrationDraftSchema.optional(),\n});\nexport type GymRegistrationProgress = z.infer<typeof gymRegistrationProgressSchema>;\n\n/** `PUT /gym-registration/draft` body — any subset, merged server-side. */\nexport const gymRegistrationProgressUpdateSchema = z\n .object({\n step: z.number().int().min(0).max(GYM_REGISTRATION_TOTAL_STEPS),\n draft: gymRegistrationDraftSchema,\n })\n .partial();\nexport type GymRegistrationProgressUpdate = z.infer<typeof gymRegistrationProgressUpdateSchema>;\n"]}
package/dist/member.d.ts CHANGED
@@ -35,6 +35,8 @@ export declare const memberRosterItemSchema: z.ZodObject<{
35
35
  status: z.ZodNullable<z.ZodEnum<{
36
36
  invited: "invited";
37
37
  active: "active";
38
+ pending: "pending";
39
+ rejected: "rejected";
38
40
  paused: "paused";
39
41
  expired: "expired";
40
42
  cancelled: "cancelled";
@@ -201,6 +203,8 @@ export declare const memberDetailSchema: z.ZodObject<{
201
203
  status: z.ZodEnum<{
202
204
  invited: "invited";
203
205
  active: "active";
206
+ pending: "pending";
207
+ rejected: "rejected";
204
208
  paused: "paused";
205
209
  expired: "expired";
206
210
  cancelled: "cancelled";
@@ -209,6 +213,11 @@ export declare const memberDetailSchema: z.ZodObject<{
209
213
  endDate: z.ZodString;
210
214
  pausedFrom: z.ZodNullable<z.ZodString>;
211
215
  pausedTo: z.ZodNullable<z.ZodString>;
216
+ paymentProofUrl: z.ZodNullable<z.ZodString>;
217
+ requestedAt: z.ZodISODateTime;
218
+ decidedAt: z.ZodNullable<z.ZodISODateTime>;
219
+ decidedBy: z.ZodNullable<z.ZodString>;
220
+ decisionNote: z.ZodNullable<z.ZodString>;
212
221
  createdAt: z.ZodISODateTime;
213
222
  updatedAt: z.ZodISODateTime;
214
223
  }, z.core.$strip>>;
@@ -285,6 +294,7 @@ export declare const createMemberBodySchema: z.ZodObject<{
285
294
  planId: z.ZodString;
286
295
  variantId: z.ZodString;
287
296
  startDate: z.ZodOptional<z.ZodString>;
297
+ paymentProofUrl: z.ZodOptional<z.ZodString>;
288
298
  payment: z.ZodOptional<z.ZodObject<{
289
299
  amountInr: z.ZodNumber;
290
300
  method: z.ZodEnum<{
@@ -294,8 +304,8 @@ export declare const createMemberBodySchema: z.ZodObject<{
294
304
  }>;
295
305
  status: z.ZodDefault<z.ZodEnum<{
296
306
  success: "success";
297
- failed: "failed";
298
307
  pending: "pending";
308
+ failed: "failed";
299
309
  }>>;
300
310
  }, z.core.$strip>>;
301
311
  }, z.core.$strip>>;
@@ -429,6 +439,8 @@ export declare const provisionResultSchema: z.ZodObject<{
429
439
  status: z.ZodEnum<{
430
440
  invited: "invited";
431
441
  active: "active";
442
+ pending: "pending";
443
+ rejected: "rejected";
432
444
  paused: "paused";
433
445
  expired: "expired";
434
446
  cancelled: "cancelled";
@@ -437,6 +449,11 @@ export declare const provisionResultSchema: z.ZodObject<{
437
449
  endDate: z.ZodString;
438
450
  pausedFrom: z.ZodNullable<z.ZodString>;
439
451
  pausedTo: z.ZodNullable<z.ZodString>;
452
+ paymentProofUrl: z.ZodNullable<z.ZodString>;
453
+ requestedAt: z.ZodISODateTime;
454
+ decidedAt: z.ZodNullable<z.ZodISODateTime>;
455
+ decidedBy: z.ZodNullable<z.ZodString>;
456
+ decisionNote: z.ZodNullable<z.ZodString>;
440
457
  createdAt: z.ZodISODateTime;
441
458
  updatedAt: z.ZodISODateTime;
442
459
  }, z.core.$strip>>;
@@ -1 +1 @@
1
- {"version":3,"file":"member.d.ts","sourceRoot":"","sources":["../src/member.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB,kDAAkD;AAClD,eAAO,MAAM,mBAAmB;;;;EAAyC,CAAC;AAC1E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAIhE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDjC,CAAC;AAEH,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,oCAAoC;AACpC,eAAO,MAAM,uBAAuB;;;;;iBAKlC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAIxE,eAAO,MAAM,kBAAkB;;;;;EAAoD,CAAC;AACpF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,gBAAgB;;;;;EAA6C,CAAC;AAC3E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;iBAKhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,kEAAkE;AAClE,eAAO,MAAM,mBAAmB;;;;;;;iBAQ9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiD7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAejC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoB/B,CAAC;AACL,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB;;;;;;iBAU7B,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,2EAA2E;AAC3E,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAehC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;iBAS9B,CAAC;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;iBAEhC,CAAC;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAIpE,eAAO,MAAM,yBAAyB;;iBAAoC,CAAC;AAC3E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,eAAO,MAAM,uBAAuB;;iBAElC,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,eAAO,MAAM,2BAA2B;;iBAEtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,wEAAwE;AACxE,eAAO,MAAM,sBAAsB;;iBAEjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
1
+ {"version":3,"file":"member.d.ts","sourceRoot":"","sources":["../src/member.ts"],"names":[],"mappings":"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"}
@@ -28,8 +28,8 @@
28
28
  import { z } from 'zod';
29
29
  export declare const membershipRequestStatusSchema: z.ZodEnum<{
30
30
  pending: "pending";
31
- approved: "approved";
32
31
  rejected: "rejected";
32
+ approved: "approved";
33
33
  }>;
34
34
  export type MembershipRequestStatus = z.infer<typeof membershipRequestStatusSchema>;
35
35
  export declare const membershipRequestSchema: z.ZodObject<{
@@ -38,8 +38,8 @@ export declare const membershipRequestSchema: z.ZodObject<{
38
38
  centerId: z.ZodString;
39
39
  status: z.ZodEnum<{
40
40
  pending: "pending";
41
- approved: "approved";
42
41
  rejected: "rejected";
42
+ approved: "approved";
43
43
  }>;
44
44
  requestedAt: z.ZodISODateTime;
45
45
  decidedAt: z.ZodNullable<z.ZodISODateTime>;
@@ -57,8 +57,8 @@ export declare const membershipRequestItemSchema: z.ZodObject<{
57
57
  centerId: z.ZodString;
58
58
  status: z.ZodEnum<{
59
59
  pending: "pending";
60
- approved: "approved";
61
60
  rejected: "rejected";
61
+ approved: "approved";
62
62
  }>;
63
63
  requestedAt: z.ZodISODateTime;
64
64
  decidedAt: z.ZodNullable<z.ZodISODateTime>;
@@ -94,8 +94,8 @@ export declare const membershipRequestQuerySchema: z.ZodObject<{
94
94
  limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
95
95
  status: z.ZodOptional<z.ZodEnum<{
96
96
  pending: "pending";
97
- approved: "approved";
98
97
  rejected: "rejected";
98
+ approved: "approved";
99
99
  }>>;
100
100
  }, z.core.$strip>;
101
101
  export type MembershipRequestQuery = z.infer<typeof membershipRequestQuerySchema>;
@@ -109,8 +109,8 @@ export declare const myMembershipRequestSchema: z.ZodNullable<z.ZodObject<{
109
109
  centerId: z.ZodString;
110
110
  status: z.ZodEnum<{
111
111
  pending: "pending";
112
- approved: "approved";
113
112
  rejected: "rejected";
113
+ approved: "approved";
114
114
  }>;
115
115
  requestedAt: z.ZodISODateTime;
116
116
  decidedAt: z.ZodNullable<z.ZodISODateTime>;
@@ -12,12 +12,34 @@
12
12
  */
13
13
  import { z } from 'zod';
14
14
  /**
15
- * Membership lifecycle. `invited` = owner created it, member hasn't activated;
16
- * `expiring` is NOT stored (derived from `endDate`).
15
+ * Membership lifecycle.
16
+ *
17
+ * `pending` is where every membership STARTS, whoever created it. Choosing a
18
+ * plan is not the same event as paying for one, and until this release the two
19
+ * were welded together: the moment a member tapped a plan it went live, and the
20
+ * moment an owner assigned one at the desk it went live, whether or not any
21
+ * money had changed hands. A gym then had no way to tell a paid member from an
22
+ * optimistic one, and no lever to withhold access from the second.
23
+ *
24
+ * The only transition out of `pending` is the gym marking the payment done.
25
+ * That is deliberately a HUMAN act by the owner or a manager rather than a
26
+ * gateway callback: these gyms take cash at the desk and UPI transfers on a
27
+ * phone, so the person who knows the money arrived is the person at the gym.
28
+ *
29
+ * `rejected` is the other way out, for a screenshot that shows nothing, the
30
+ * wrong amount, or a transfer that never landed. It is a dead end — the
31
+ * member requests again rather than the gym reopening a closed decision.
32
+ *
33
+ * `invited` predates all of this and nothing writes it. Left in place because
34
+ * removing a value from a stored enum is not worth a migration.
35
+ *
36
+ * `expiring` is NOT stored — it is derived from `endDate` at the edge.
17
37
  */
18
38
  export declare const membershipStatusSchema: z.ZodEnum<{
19
39
  invited: "invited";
20
40
  active: "active";
41
+ pending: "pending";
42
+ rejected: "rejected";
21
43
  paused: "paused";
22
44
  expired: "expired";
23
45
  cancelled: "cancelled";
@@ -31,8 +53,8 @@ export declare const paymentMethodSchema: z.ZodEnum<{
31
53
  export type PaymentMethod = z.infer<typeof paymentMethodSchema>;
32
54
  export declare const paymentStatusSchema: z.ZodEnum<{
33
55
  success: "success";
34
- failed: "failed";
35
56
  pending: "pending";
57
+ failed: "failed";
36
58
  }>;
37
59
  export type PaymentStatus = z.infer<typeof paymentStatusSchema>;
38
60
  export declare const paymentSchema: z.ZodObject<{
@@ -46,8 +68,8 @@ export declare const paymentSchema: z.ZodObject<{
46
68
  }>;
47
69
  status: z.ZodEnum<{
48
70
  success: "success";
49
- failed: "failed";
50
71
  pending: "pending";
72
+ failed: "failed";
51
73
  }>;
52
74
  paidAt: z.ZodISODateTime;
53
75
  note: z.ZodNullable<z.ZodString>;
@@ -66,6 +88,8 @@ export declare const membershipSchema: z.ZodObject<{
66
88
  status: z.ZodEnum<{
67
89
  invited: "invited";
68
90
  active: "active";
91
+ pending: "pending";
92
+ rejected: "rejected";
69
93
  paused: "paused";
70
94
  expired: "expired";
71
95
  cancelled: "cancelled";
@@ -74,6 +98,11 @@ export declare const membershipSchema: z.ZodObject<{
74
98
  endDate: z.ZodString;
75
99
  pausedFrom: z.ZodNullable<z.ZodString>;
76
100
  pausedTo: z.ZodNullable<z.ZodString>;
101
+ paymentProofUrl: z.ZodNullable<z.ZodString>;
102
+ requestedAt: z.ZodISODateTime;
103
+ decidedAt: z.ZodNullable<z.ZodISODateTime>;
104
+ decidedBy: z.ZodNullable<z.ZodString>;
105
+ decisionNote: z.ZodNullable<z.ZodString>;
77
106
  createdAt: z.ZodISODateTime;
78
107
  updatedAt: z.ZodISODateTime;
79
108
  }, z.core.$strip>;
@@ -86,6 +115,7 @@ export declare const assignMembershipBodySchema: z.ZodObject<{
86
115
  planId: z.ZodString;
87
116
  variantId: z.ZodString;
88
117
  startDate: z.ZodOptional<z.ZodString>;
118
+ paymentProofUrl: z.ZodOptional<z.ZodString>;
89
119
  payment: z.ZodOptional<z.ZodObject<{
90
120
  amountInr: z.ZodNumber;
91
121
  method: z.ZodEnum<{
@@ -95,12 +125,89 @@ export declare const assignMembershipBodySchema: z.ZodObject<{
95
125
  }>;
96
126
  status: z.ZodDefault<z.ZodEnum<{
97
127
  success: "success";
98
- failed: "failed";
99
128
  pending: "pending";
129
+ failed: "failed";
100
130
  }>>;
101
131
  }, z.core.$strip>>;
102
132
  }, z.core.$strip>;
103
133
  export type AssignMembershipBody = z.infer<typeof assignMembershipBodySchema>;
134
+ /**
135
+ * The gym marking a pending membership's payment as done, which is the single
136
+ * act that activates it.
137
+ *
138
+ * It carries the LEDGER entry rather than being a bare approval, because those
139
+ * are the same event: the owner is asserting that this much money arrived by
140
+ * this route. Splitting them would let a membership go live with nothing
141
+ * written down, which is exactly the hole this feature exists to close.
142
+ *
143
+ * The amount is not forced to equal the plan price. A gym that takes half now
144
+ * and half on Friday still wants the member training, and the balance is
145
+ * already tracked against the term.
146
+ */
147
+ export declare const confirmMembershipPaymentBodySchema: z.ZodObject<{
148
+ amountInr: z.ZodNumber;
149
+ method: z.ZodEnum<{
150
+ upi: "upi";
151
+ cash: "cash";
152
+ card: "card";
153
+ }>;
154
+ note: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
155
+ }, z.core.$strip>;
156
+ export type ConfirmMembershipPaymentBody = z.infer<typeof confirmMembershipPaymentBodySchema>;
157
+ /**
158
+ * One row of the gym's confirmation queue.
159
+ *
160
+ * The membership plus just enough of the person to act on it. The owner is
161
+ * deciding about a HUMAN — "did Ravi's transfer land" — and a list of plan
162
+ * names and amounts with no names attached is not something anybody can
163
+ * answer. Kept to four fields rather than embedding the whole roster row,
164
+ * because this list is read on every visit to the members screen.
165
+ */
166
+ export declare const pendingMembershipRowSchema: z.ZodObject<{
167
+ membership: z.ZodObject<{
168
+ id: z.ZodString;
169
+ enrolmentId: z.ZodString;
170
+ userId: z.ZodNullable<z.ZodString>;
171
+ centerId: z.ZodString;
172
+ planId: z.ZodString;
173
+ planName: z.ZodString;
174
+ variantId: z.ZodString;
175
+ variantLabel: z.ZodString;
176
+ priceInr: z.ZodNumber;
177
+ status: z.ZodEnum<{
178
+ invited: "invited";
179
+ active: "active";
180
+ pending: "pending";
181
+ rejected: "rejected";
182
+ paused: "paused";
183
+ expired: "expired";
184
+ cancelled: "cancelled";
185
+ }>;
186
+ startDate: z.ZodString;
187
+ endDate: z.ZodString;
188
+ pausedFrom: z.ZodNullable<z.ZodString>;
189
+ pausedTo: z.ZodNullable<z.ZodString>;
190
+ paymentProofUrl: z.ZodNullable<z.ZodString>;
191
+ requestedAt: z.ZodISODateTime;
192
+ decidedAt: z.ZodNullable<z.ZodISODateTime>;
193
+ decidedBy: z.ZodNullable<z.ZodString>;
194
+ decisionNote: z.ZodNullable<z.ZodString>;
195
+ createdAt: z.ZodISODateTime;
196
+ updatedAt: z.ZodISODateTime;
197
+ }, z.core.$strip>;
198
+ member: z.ZodObject<{
199
+ enrolmentId: z.ZodString;
200
+ gymMemberCode: z.ZodString;
201
+ name: z.ZodString;
202
+ avatarUrl: z.ZodNullable<z.ZodString>;
203
+ }, z.core.$strip>;
204
+ }, z.core.$strip>;
205
+ export type PendingMembershipRow = z.infer<typeof pendingMembershipRowSchema>;
206
+ /** Turning a request down. The reason reaches the member. */
207
+ export declare const rejectMembershipPaymentBodySchema: z.ZodObject<{
208
+ reason: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
209
+ }, z.core.$strip>;
210
+ export type RejectMembershipPaymentBody = z.infer<typeof rejectMembershipPaymentBodySchema>;
104
211
  export declare const pauseDurationSchema: z.ZodEnum<{
105
212
  custom: "custom";
106
213
  "1w": "1w";
@@ -1 +1 @@
1
- {"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,eAAO,MAAM,mBAAmB;;;;EAAkC,CAAC;AACnE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,mBAAmB;;;;EAA2C,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;iBAQxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;iBAuC3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI1D;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;iBAYrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,mBAAmB;;;;;EAAuC,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,yBAAyB;;;;;;;;;iBASlC,CAAC;AACL,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B;;;iBAGrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,wBAAwB;;;;;;;;iBAInC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
1
+ {"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../src/membership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;EAQjC,CAAC;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAItE,eAAO,MAAM,mBAAmB;;;;EAAkC,CAAC;AACnE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,mBAAmB;;;;EAA2C,CAAC;AAC5E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;iBAQxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAIpD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgE3B,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAI1D;;;GAGG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;iBAiBrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;iBAI7C,CAAC;AACH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E,6DAA6D;AAC7D,eAAO,MAAM,iCAAiC;;iBAE5C,CAAC;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAI5F,eAAO,MAAM,mBAAmB;;;;;EAAuC,CAAC;AACxE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,yBAAyB;;;;;;;;;iBASlC,CAAC;AACL,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAI5E,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B;;;iBAGrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAI9E,eAAO,MAAM,wBAAwB;;;;;;;;iBAInC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}