@valentine-efagene/qshelter-common 2.0.98 → 2.0.100

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.
Files changed (56) hide show
  1. package/dist/generated/client/browser.d.ts +5 -0
  2. package/dist/generated/client/client.d.ts +5 -0
  3. package/dist/generated/client/commonInputTypes.d.ts +90 -0
  4. package/dist/generated/client/enums.d.ts +26 -0
  5. package/dist/generated/client/enums.js +23 -0
  6. package/dist/generated/client/internal/class.d.ts +11 -0
  7. package/dist/generated/client/internal/class.js +2 -2
  8. package/dist/generated/client/internal/prismaNamespace.d.ts +176 -1
  9. package/dist/generated/client/internal/prismaNamespace.js +95 -1
  10. package/dist/generated/client/internal/prismaNamespaceBrowser.d.ts +96 -0
  11. package/dist/generated/client/internal/prismaNamespaceBrowser.js +95 -1
  12. package/dist/generated/client/models/Amenity.d.ts +183 -3
  13. package/dist/generated/client/models/ApplicationDocument.d.ts +183 -1
  14. package/dist/generated/client/models/ApplicationEvent.d.ts +190 -14
  15. package/dist/generated/client/models/ApplicationPayment.d.ts +225 -1
  16. package/dist/generated/client/models/ApplicationPhase.d.ts +272 -26
  17. package/dist/generated/client/models/DocumentationPhase.d.ts +224 -24
  18. package/dist/generated/client/models/DocumentationStep.d.ts +237 -1
  19. package/dist/generated/client/models/DocumentationStepApproval.d.ts +159 -1
  20. package/dist/generated/client/models/DocumentationStepDocument.d.ts +150 -10
  21. package/dist/generated/client/models/EventHandlerExecution.d.ts +208 -14
  22. package/dist/generated/client/models/PaymentInstallment.d.ts +228 -14
  23. package/dist/generated/client/models/PaymentMethodPhaseDocument.d.ts +178 -14
  24. package/dist/generated/client/models/PaymentMethodPhaseField.d.ts +208 -14
  25. package/dist/generated/client/models/PaymentMethodPhaseStep.d.ts +180 -14
  26. package/dist/generated/client/models/PaymentPhase.d.ts +214 -14
  27. package/dist/generated/client/models/PhaseEventAttachment.d.ts +178 -14
  28. package/dist/generated/client/models/PropertyAmenity.d.ts +145 -11
  29. package/dist/generated/client/models/PropertyDocument.d.ts +164 -12
  30. package/dist/generated/client/models/PropertyMedia.d.ts +183 -17
  31. package/dist/generated/client/models/PropertyPaymentMethodLink.d.ts +159 -13
  32. package/dist/generated/client/models/PropertyPaymentMethodPhase.d.ts +270 -14
  33. package/dist/generated/client/models/PropertyUnit.d.ts +230 -14
  34. package/dist/generated/client/models/PropertyVariant.d.ts +256 -14
  35. package/dist/generated/client/models/PropertyVariantAmenity.d.ts +145 -11
  36. package/dist/generated/client/models/PropertyVariantMedia.d.ts +171 -13
  37. package/dist/generated/client/models/QuestionnaireField.d.ts +232 -14
  38. package/dist/generated/client/models/QuestionnairePhase.d.ts +207 -1
  39. package/dist/generated/client/models/StepEventAttachment.d.ts +178 -14
  40. package/dist/generated/client/models/Tenant.d.ts +11653 -1153
  41. package/dist/generated/client/models/WorkflowBlocker.d.ts +1432 -0
  42. package/dist/generated/client/models/WorkflowBlocker.js +1 -0
  43. package/dist/generated/client/models/index.d.ts +1 -0
  44. package/dist/generated/client/models/index.js +1 -0
  45. package/dist/generated/client/models.d.ts +1 -0
  46. package/dist/src/index.d.ts +1 -0
  47. package/dist/src/index.js +1 -0
  48. package/dist/src/middleware/auth-context.d.ts +63 -6
  49. package/dist/src/middleware/auth-context.js +132 -13
  50. package/dist/src/prisma/tenant.js +26 -32
  51. package/dist/src/types/action-status.d.ts +137 -0
  52. package/dist/src/types/action-status.js +402 -0
  53. package/package.json +1 -1
  54. package/prisma/migrations/20260113000000_remove_workflow_analytics_summary/migration.sql +5 -0
  55. package/prisma/migrations/20260113110450_add_tenant_id_to_child_models/migration.sql +334 -0
  56. package/prisma/schema.prisma +273 -60
@@ -0,0 +1,402 @@
1
+ /**
2
+ * Action Status Types - Back-end driven UI indicators
3
+ *
4
+ * This module provides types for indicating who needs to act next
5
+ * at various levels of the application (application, phase, step).
6
+ *
7
+ * The frontend uses this to show:
8
+ * - "Awaiting your action" (CUSTOMER)
9
+ * - "Under review" (ADMIN)
10
+ * - "Processing..." (SYSTEM)
11
+ * - "Completed" (NONE)
12
+ * - "Awaiting payment" (CUSTOMER for payment phases)
13
+ */
14
+ /**
15
+ * The actor who needs to take the next action
16
+ */
17
+ export var NextActor;
18
+ (function (NextActor) {
19
+ /** Customer must take action (upload, sign, pay) */
20
+ NextActor["CUSTOMER"] = "CUSTOMER";
21
+ /** Admin must take action (review, approve, reject) */
22
+ NextActor["ADMIN"] = "ADMIN";
23
+ /** System is processing (auto-generation, webhook, etc.) */
24
+ NextActor["SYSTEM"] = "SYSTEM";
25
+ /** No action required - completed or waiting for external event */
26
+ NextActor["NONE"] = "NONE";
27
+ })(NextActor || (NextActor = {}));
28
+ /**
29
+ * High-level action categories for easier UI grouping
30
+ */
31
+ export var ActionCategory;
32
+ (function (ActionCategory) {
33
+ /** Document upload/reupload needed */
34
+ ActionCategory["UPLOAD"] = "UPLOAD";
35
+ /** Signature required */
36
+ ActionCategory["SIGNATURE"] = "SIGNATURE";
37
+ /** Review/approval needed */
38
+ ActionCategory["REVIEW"] = "REVIEW";
39
+ /** Payment required */
40
+ ActionCategory["PAYMENT"] = "PAYMENT";
41
+ /** Waiting for external process */
42
+ ActionCategory["PROCESSING"] = "PROCESSING";
43
+ /** Phase/step/application completed */
44
+ ActionCategory["COMPLETED"] = "COMPLETED";
45
+ /** Waiting for previous phase/step */
46
+ ActionCategory["WAITING"] = "WAITING";
47
+ })(ActionCategory || (ActionCategory = {}));
48
+ /**
49
+ * Compute action status for a documentation step
50
+ */
51
+ export function computeStepActionStatus(step, pendingDocuments, totalDocuments) {
52
+ const base = {
53
+ stepId: step.id,
54
+ stepName: step.name,
55
+ stepType: step.stepType,
56
+ stepOrder: step.order,
57
+ dueDate: step.dueDate ?? null,
58
+ isBlocking: true,
59
+ };
60
+ // Handle step status
61
+ switch (step.status) {
62
+ case 'COMPLETED':
63
+ return {
64
+ ...base,
65
+ nextActor: NextActor.NONE,
66
+ actionCategory: ActionCategory.COMPLETED,
67
+ actionRequired: 'Step completed',
68
+ isBlocking: false,
69
+ };
70
+ case 'SKIPPED':
71
+ return {
72
+ ...base,
73
+ nextActor: NextActor.NONE,
74
+ actionCategory: ActionCategory.COMPLETED,
75
+ actionRequired: 'Step skipped',
76
+ isBlocking: false,
77
+ };
78
+ case 'NEEDS_RESUBMISSION':
79
+ return {
80
+ ...base,
81
+ nextActor: NextActor.CUSTOMER,
82
+ actionCategory: ActionCategory.UPLOAD,
83
+ actionRequired: step.actionReason || 'Please resubmit the required document',
84
+ progress: 'Document was rejected - resubmission required',
85
+ };
86
+ case 'ACTION_REQUIRED':
87
+ return {
88
+ ...base,
89
+ nextActor: NextActor.CUSTOMER,
90
+ actionCategory: ActionCategory.UPLOAD,
91
+ actionRequired: step.actionReason || 'Your action is required',
92
+ };
93
+ case 'AWAITING_REVIEW':
94
+ return {
95
+ ...base,
96
+ nextActor: NextActor.ADMIN,
97
+ actionCategory: ActionCategory.REVIEW,
98
+ actionRequired: 'Document submitted - awaiting admin review',
99
+ progress: 'Under review',
100
+ };
101
+ case 'IN_PROGRESS':
102
+ case 'PENDING':
103
+ // Determine based on step type
104
+ return computeStepActionByType(step, base, pendingDocuments, totalDocuments);
105
+ case 'FAILED':
106
+ return {
107
+ ...base,
108
+ nextActor: NextActor.ADMIN,
109
+ actionCategory: ActionCategory.REVIEW,
110
+ actionRequired: 'Step failed - admin intervention required',
111
+ };
112
+ default:
113
+ return {
114
+ ...base,
115
+ nextActor: NextActor.NONE,
116
+ actionCategory: ActionCategory.WAITING,
117
+ actionRequired: 'Waiting',
118
+ };
119
+ }
120
+ }
121
+ /**
122
+ * Compute action status based on step type for PENDING/IN_PROGRESS steps
123
+ */
124
+ function computeStepActionByType(step, base, pendingDocuments, totalDocuments) {
125
+ switch (step.stepType) {
126
+ case 'UPLOAD':
127
+ const progress = totalDocuments !== undefined && pendingDocuments !== undefined
128
+ ? `${totalDocuments - pendingDocuments} of ${totalDocuments} documents uploaded`
129
+ : undefined;
130
+ return {
131
+ ...base,
132
+ nextActor: NextActor.CUSTOMER,
133
+ actionCategory: ActionCategory.UPLOAD,
134
+ actionRequired: `Upload required: ${step.name}`,
135
+ progress,
136
+ };
137
+ case 'SIGNATURE':
138
+ return {
139
+ ...base,
140
+ nextActor: NextActor.CUSTOMER,
141
+ actionCategory: ActionCategory.SIGNATURE,
142
+ actionRequired: `Signature required: ${step.name}`,
143
+ };
144
+ case 'APPROVAL':
145
+ case 'REVIEW':
146
+ return {
147
+ ...base,
148
+ nextActor: NextActor.ADMIN,
149
+ actionCategory: ActionCategory.REVIEW,
150
+ actionRequired: `Admin review required: ${step.name}`,
151
+ progress: 'Awaiting admin approval',
152
+ };
153
+ case 'GENERATE_DOCUMENT':
154
+ return {
155
+ ...base,
156
+ nextActor: NextActor.SYSTEM,
157
+ actionCategory: ActionCategory.PROCESSING,
158
+ actionRequired: `Generating document: ${step.name}`,
159
+ progress: 'System is processing',
160
+ };
161
+ case 'EXTERNAL_CHECK':
162
+ case 'WAIT':
163
+ return {
164
+ ...base,
165
+ nextActor: NextActor.SYSTEM,
166
+ actionCategory: ActionCategory.PROCESSING,
167
+ actionRequired: `Waiting for external process: ${step.name}`,
168
+ progress: 'Awaiting external verification',
169
+ };
170
+ case 'PRE_APPROVAL':
171
+ case 'UNDERWRITING':
172
+ return {
173
+ ...base,
174
+ nextActor: NextActor.SYSTEM,
175
+ actionCategory: ActionCategory.PROCESSING,
176
+ actionRequired: `Processing: ${step.name}`,
177
+ progress: 'Underwriting in progress',
178
+ };
179
+ default:
180
+ return {
181
+ ...base,
182
+ nextActor: NextActor.CUSTOMER,
183
+ actionCategory: ActionCategory.UPLOAD,
184
+ actionRequired: step.name,
185
+ };
186
+ }
187
+ }
188
+ /**
189
+ * Compute action status for a phase based on its category and current state
190
+ */
191
+ export function computePhaseActionStatus(phase) {
192
+ const base = {
193
+ phaseId: phase.id,
194
+ phaseName: phase.name,
195
+ phaseType: phase.phaseType,
196
+ phaseCategory: phase.phaseCategory,
197
+ dueDate: phase.dueDate ?? null,
198
+ };
199
+ // Handle phase status
200
+ switch (phase.status) {
201
+ case 'COMPLETED':
202
+ return {
203
+ ...base,
204
+ nextActor: NextActor.NONE,
205
+ actionCategory: ActionCategory.COMPLETED,
206
+ actionRequired: 'Phase completed',
207
+ isBlocking: false,
208
+ };
209
+ case 'SKIPPED':
210
+ case 'SUPERSEDED':
211
+ return {
212
+ ...base,
213
+ nextActor: NextActor.NONE,
214
+ actionCategory: ActionCategory.COMPLETED,
215
+ actionRequired: 'Phase skipped',
216
+ isBlocking: false,
217
+ };
218
+ case 'PENDING':
219
+ return {
220
+ ...base,
221
+ nextActor: NextActor.NONE,
222
+ actionCategory: ActionCategory.WAITING,
223
+ actionRequired: 'Waiting for previous phase to complete',
224
+ isBlocking: false,
225
+ };
226
+ case 'FAILED':
227
+ return {
228
+ ...base,
229
+ nextActor: NextActor.ADMIN,
230
+ actionCategory: ActionCategory.REVIEW,
231
+ actionRequired: 'Phase failed - admin intervention required',
232
+ isBlocking: true,
233
+ };
234
+ }
235
+ // For IN_PROGRESS/ACTIVE phases, determine based on category
236
+ switch (phase.phaseCategory) {
237
+ case 'DOCUMENTATION':
238
+ return computeDocumentationPhaseStatus(phase, base);
239
+ case 'PAYMENT':
240
+ return computePaymentPhaseStatus(phase, base);
241
+ case 'QUESTIONNAIRE':
242
+ return computeQuestionnairePhaseStatus(phase, base);
243
+ default:
244
+ return {
245
+ ...base,
246
+ nextActor: NextActor.CUSTOMER,
247
+ actionCategory: ActionCategory.UPLOAD,
248
+ actionRequired: 'Action required',
249
+ isBlocking: true,
250
+ };
251
+ }
252
+ }
253
+ function computeDocumentationPhaseStatus(phase, base) {
254
+ const docPhase = phase.documentationPhase;
255
+ if (!docPhase) {
256
+ return {
257
+ ...base,
258
+ nextActor: NextActor.CUSTOMER,
259
+ actionCategory: ActionCategory.UPLOAD,
260
+ actionRequired: 'Documentation required',
261
+ isBlocking: true,
262
+ };
263
+ }
264
+ const completedSteps = docPhase.completedStepsCount ?? 0;
265
+ const totalSteps = docPhase.totalStepsCount ?? docPhase.steps?.length ?? 0;
266
+ const stepsProgress = `${completedSteps} of ${totalSteps} steps completed`;
267
+ // Get current step status
268
+ const currentStep = docPhase.currentStep;
269
+ if (currentStep) {
270
+ const stepStatus = computeStepActionStatus(currentStep);
271
+ return {
272
+ ...base,
273
+ nextActor: stepStatus.nextActor,
274
+ actionCategory: stepStatus.actionCategory,
275
+ actionRequired: stepStatus.actionRequired,
276
+ progress: stepStatus.progress,
277
+ stepsProgress,
278
+ currentStep: stepStatus,
279
+ isBlocking: true,
280
+ };
281
+ }
282
+ // No current step - check if all steps are completed
283
+ const steps = docPhase.steps || [];
284
+ const allCompleted = steps.every((s) => s.status === 'COMPLETED');
285
+ if (allCompleted) {
286
+ return {
287
+ ...base,
288
+ nextActor: NextActor.NONE,
289
+ actionCategory: ActionCategory.COMPLETED,
290
+ actionRequired: 'All steps completed',
291
+ stepsProgress,
292
+ isBlocking: false,
293
+ };
294
+ }
295
+ // Find next pending step
296
+ const nextStep = steps.find((s) => s.status !== 'COMPLETED' && s.status !== 'SKIPPED');
297
+ if (nextStep) {
298
+ const stepStatus = computeStepActionStatus(nextStep);
299
+ return {
300
+ ...base,
301
+ nextActor: stepStatus.nextActor,
302
+ actionCategory: stepStatus.actionCategory,
303
+ actionRequired: stepStatus.actionRequired,
304
+ progress: stepStatus.progress,
305
+ stepsProgress,
306
+ currentStep: stepStatus,
307
+ isBlocking: true,
308
+ };
309
+ }
310
+ return {
311
+ ...base,
312
+ nextActor: NextActor.NONE,
313
+ actionCategory: ActionCategory.WAITING,
314
+ actionRequired: 'Waiting',
315
+ stepsProgress,
316
+ isBlocking: false,
317
+ };
318
+ }
319
+ function computePaymentPhaseStatus(phase, base) {
320
+ const payPhase = phase.paymentPhase;
321
+ if (!payPhase) {
322
+ return {
323
+ ...base,
324
+ nextActor: NextActor.CUSTOMER,
325
+ actionCategory: ActionCategory.PAYMENT,
326
+ actionRequired: 'Payment required',
327
+ isBlocking: true,
328
+ };
329
+ }
330
+ const totalAmount = payPhase.totalAmount ?? 0;
331
+ const paidAmount = payPhase.paidAmount ?? 0;
332
+ const remainingAmount = totalAmount - paidAmount;
333
+ const paymentProgress = `₦${paidAmount.toLocaleString()} of ₦${totalAmount.toLocaleString()} paid`;
334
+ if (remainingAmount <= 0) {
335
+ return {
336
+ ...base,
337
+ nextActor: NextActor.NONE,
338
+ actionCategory: ActionCategory.COMPLETED,
339
+ actionRequired: 'Payment completed',
340
+ paymentProgress,
341
+ isBlocking: false,
342
+ };
343
+ }
344
+ // Check for pending installments
345
+ const installments = payPhase.installments || [];
346
+ const pendingInstallment = installments.find((i) => i.status === 'PENDING' || i.status === 'OVERDUE' || i.status === 'PARTIALLY_PAID');
347
+ if (pendingInstallment) {
348
+ const isOverdue = pendingInstallment.status === 'OVERDUE';
349
+ return {
350
+ ...base,
351
+ nextActor: NextActor.CUSTOMER,
352
+ actionCategory: ActionCategory.PAYMENT,
353
+ actionRequired: isOverdue
354
+ ? `Overdue payment: ₦${pendingInstallment.amount.toLocaleString()}`
355
+ : `Payment due: ₦${pendingInstallment.amount.toLocaleString()}`,
356
+ paymentProgress,
357
+ dueDate: pendingInstallment.dueDate,
358
+ isBlocking: true,
359
+ };
360
+ }
361
+ return {
362
+ ...base,
363
+ nextActor: NextActor.CUSTOMER,
364
+ actionCategory: ActionCategory.PAYMENT,
365
+ actionRequired: `Remaining balance: ₦${remainingAmount.toLocaleString()}`,
366
+ paymentProgress,
367
+ isBlocking: true,
368
+ };
369
+ }
370
+ function computeQuestionnairePhaseStatus(phase, base) {
371
+ const qPhase = phase.questionnairePhase;
372
+ if (!qPhase) {
373
+ return {
374
+ ...base,
375
+ nextActor: NextActor.CUSTOMER,
376
+ actionCategory: ActionCategory.UPLOAD,
377
+ actionRequired: 'Complete questionnaire',
378
+ isBlocking: true,
379
+ };
380
+ }
381
+ const completedFields = qPhase.completedFieldsCount ?? 0;
382
+ const totalFields = qPhase.totalFieldsCount ?? 0;
383
+ const progress = `${completedFields} of ${totalFields} fields completed`;
384
+ if (completedFields >= totalFields && totalFields > 0) {
385
+ return {
386
+ ...base,
387
+ nextActor: NextActor.NONE,
388
+ actionCategory: ActionCategory.COMPLETED,
389
+ actionRequired: 'Questionnaire completed',
390
+ progress,
391
+ isBlocking: false,
392
+ };
393
+ }
394
+ return {
395
+ ...base,
396
+ nextActor: NextActor.CUSTOMER,
397
+ actionCategory: ActionCategory.UPLOAD,
398
+ actionRequired: 'Complete questionnaire fields',
399
+ progress,
400
+ isBlocking: true,
401
+ };
402
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentine-efagene/qshelter-common",
3
- "version": "2.0.98",
3
+ "version": "2.0.100",
4
4
  "description": "Shared database schemas and utilities for QShelter services",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -0,0 +1,5 @@
1
+ -- RemoveWorkflowAnalyticsSummary
2
+ -- Removes the workflow_analytics_summaries table as we compute analytics on-demand
3
+ -- from the workflow_blockers table instead of pre-aggregating.
4
+
5
+ DROP TABLE IF EXISTS `workflow_analytics_summaries`;