@opencrvs/toolkit 1.9.2 → 1.9.3-rc.0b3cc48

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.
@@ -1969,6 +1969,9 @@ var PageTypes = import_zod16.z.enum(["FORM", "VERIFICATION"]);
1969
1969
  var PageConfigBase = import_zod16.z.object({
1970
1970
  id: import_zod16.z.string().describe("Unique identifier for the page"),
1971
1971
  title: TranslationConfig.describe("Header title of the page"),
1972
+ requireCompletionToContinue: import_zod16.z.boolean().default(false).describe(
1973
+ "If true, all required fields must be filled before continuing to the next page"
1974
+ ),
1972
1975
  fields: import_zod16.z.array(FieldConfig).describe("Fields to be rendered on the page"),
1973
1976
  conditional: Conditional.optional().describe(
1974
1977
  "Page will be shown if condition is met. If conditional is not defined, the page will be always shown."
@@ -2421,9 +2424,30 @@ var DataContext = import_zod25.z.object({
2421
2424
  $leafAdminStructureLocationIds: import_zod25.z.array(import_zod25.z.object({ id: UUID }))
2422
2425
  })
2423
2426
  });
2427
+ function resolveDataPath(rootData, dataPath, instancePath) {
2428
+ const pathParts = dataPath.split("/");
2429
+ const levels = parseInt(pathParts[0], 10);
2430
+ const referencePath = pathParts.slice(1);
2431
+ const instanceParts = instancePath.split("/").filter(Boolean);
2432
+ const traversedParts = instanceParts.slice(0, -levels);
2433
+ let current = rootData;
2434
+ for (const part of traversedParts) {
2435
+ if (current === null || current === void 0) {
2436
+ return void 0;
2437
+ }
2438
+ current = current[part];
2439
+ }
2440
+ for (const part of referencePath) {
2441
+ if (current === null || current === void 0) {
2442
+ return void 0;
2443
+ }
2444
+ current = current[part];
2445
+ }
2446
+ return current;
2447
+ }
2424
2448
  (0, import_ajv_formats.default)(ajv);
2425
2449
  ajv.addKeyword({
2426
- keyword: "daysFromNow",
2450
+ keyword: "daysFromDate",
2427
2451
  type: "string",
2428
2452
  schemaType: "object",
2429
2453
  $data: true,
@@ -2440,8 +2464,22 @@ ajv.addKeyword({
2440
2464
  if (isNaN(date.getTime())) {
2441
2465
  return false;
2442
2466
  }
2443
- const now = new Date(dataContext.rootData.$now);
2444
- const offsetDate = new Date(now.getTime() + days * 24 * 60 * 60 * 1e3);
2467
+ let referenceDate = schema.referenceDate;
2468
+ if (referenceDate && typeof referenceDate === "object" && "$data" in referenceDate) {
2469
+ referenceDate = resolveDataPath(
2470
+ dataContext.rootData,
2471
+ referenceDate.$data,
2472
+ dataContext.instancePath
2473
+ );
2474
+ }
2475
+ if (!referenceDate) {
2476
+ referenceDate = dataContext.rootData.$now;
2477
+ }
2478
+ const baseDate = new Date(referenceDate);
2479
+ if (isNaN(baseDate.getTime())) {
2480
+ return false;
2481
+ }
2482
+ const offsetDate = new Date(baseDate.getTime() + days * 24 * 60 * 60 * 1e3);
2445
2483
  return clause === "after" ? (0, import_date_fns.isAfter)(date, offsetDate) : (0, import_date_fns.isBefore)(date, offsetDate);
2446
2484
  }
2447
2485
  });
@@ -2756,6 +2794,34 @@ function getDateRangeToFieldReference(field3, comparedField, clause) {
2756
2794
  required: [field3.$$field]
2757
2795
  };
2758
2796
  }
2797
+ function getDayRangeToFieldReference(field3, comparedField, days, clause) {
2798
+ return {
2799
+ type: "object",
2800
+ properties: {
2801
+ [field3.$$field]: wrapToPath(
2802
+ {
2803
+ type: "string",
2804
+ format: "date",
2805
+ daysFromDate: {
2806
+ referenceDate: {
2807
+ $data: `${field3.$$subfield.length + 1}/${jsonFieldPath(
2808
+ comparedField
2809
+ )}`
2810
+ },
2811
+ clause,
2812
+ days
2813
+ }
2814
+ },
2815
+ field3.$$subfield
2816
+ ),
2817
+ [comparedField.$$field]: wrapToPath(
2818
+ { type: "string", format: "date" },
2819
+ comparedField.$$subfield
2820
+ )
2821
+ },
2822
+ required: [field3.$$field]
2823
+ };
2824
+ }
2759
2825
  function defineComparison(field3, value, keyword) {
2760
2826
  if (isFieldReference(value)) {
2761
2827
  const comparedField = value;
@@ -2791,16 +2857,17 @@ function defineComparison(field3, value, keyword) {
2791
2857
  });
2792
2858
  }
2793
2859
  function createFieldConditionals(fieldId) {
2794
- const getDayRange = (field3, days, clause) => ({
2860
+ const getDayRange = (field3, days, clause, referenceDate) => ({
2795
2861
  type: "object",
2796
2862
  properties: {
2797
2863
  [field3.$$field]: wrapToPath(
2798
2864
  {
2799
2865
  type: "string",
2800
2866
  format: "date",
2801
- daysFromNow: {
2867
+ daysFromDate: {
2802
2868
  days,
2803
- clause
2869
+ clause,
2870
+ referenceDate
2804
2871
  }
2805
2872
  },
2806
2873
  field3.$$subfield
@@ -2853,7 +2920,19 @@ function createFieldConditionals(fieldId) {
2853
2920
  return {
2854
2921
  days: (days) => ({
2855
2922
  inPast: () => defineFormConditional(getDayRange(this, -days, "after")),
2856
- inFuture: () => defineFormConditional(getDayRange(this, days, "after"))
2923
+ inFuture: () => defineFormConditional(getDayRange(this, days, "after")),
2924
+ fromDate: (date) => {
2925
+ if (isFieldReference(date)) {
2926
+ const comparedField = date;
2927
+ return defineFormConditional(
2928
+ getDayRangeToFieldReference(this, comparedField, days, "after")
2929
+ );
2930
+ }
2931
+ return defineFormConditional(getDayRange(this, days, "after", date));
2932
+ },
2933
+ fromNow: () => {
2934
+ return defineFormConditional(getDayRange(this, days, "after"));
2935
+ }
2857
2936
  }),
2858
2937
  date: (date) => {
2859
2938
  if (isFieldReference(date)) {
@@ -2875,7 +2954,26 @@ function createFieldConditionals(fieldId) {
2875
2954
  return {
2876
2955
  days: (days) => ({
2877
2956
  inPast: () => defineFormConditional(getDayRange(this, -days, "before")),
2878
- inFuture: () => defineFormConditional(getDayRange(this, days, "before"))
2957
+ inFuture: () => defineFormConditional(getDayRange(this, days, "before")),
2958
+ fromDate: (date) => {
2959
+ if (isFieldReference(date)) {
2960
+ const comparedField = date;
2961
+ return defineFormConditional(
2962
+ getDayRangeToFieldReference(
2963
+ this,
2964
+ comparedField,
2965
+ -days,
2966
+ "before"
2967
+ )
2968
+ );
2969
+ }
2970
+ return defineFormConditional(
2971
+ getDayRange(this, -days, "before", date)
2972
+ );
2973
+ },
2974
+ fromNow: () => {
2975
+ return defineFormConditional(getDayRange(this, -days, "before"));
2976
+ }
2879
2977
  }),
2880
2978
  date: (date) => {
2881
2979
  if (isFieldReference(date)) {
@@ -3821,6 +3919,7 @@ var PRINT_CERTIFICATE_FORM = defineActionForm({
3821
3919
  {
3822
3920
  id: "collector",
3823
3921
  type: PageTypes.enum.FORM,
3922
+ requireCompletionToContinue: true,
3824
3923
  title: {
3825
3924
  id: "event.tennis-club-membership.action.certificate.form.section.who.title",
3826
3925
  defaultMessage: "Print certified copy",
@@ -4428,6 +4527,7 @@ var PRINT_CERTIFICATE_FORM = defineActionForm({
4428
4527
  {
4429
4528
  id: "collector.identity.verify",
4430
4529
  type: PageTypes.enum.VERIFICATION,
4530
+ requireCompletionToContinue: true,
4431
4531
  conditional: field("collector.requesterId").isEqualTo("INFORMANT"),
4432
4532
  title: {
4433
4533
  id: "event.tennis-club-membership.action.print.verifyIdentity",
@@ -6026,6 +6126,220 @@ var v2BirthEvent = defineConfig({
6026
6126
  advancedSearch: []
6027
6127
  });
6028
6128
 
6129
+ // ../commons/src/fixtures/digital-identity-issuance-event.ts
6130
+ var PRINT_DIGITAL_ID_CERTIFICATE_FORM = defineActionForm({
6131
+ label: {
6132
+ id: "event.digital-identity.action.certificate.form.label",
6133
+ defaultMessage: "Digital identity certificate printer",
6134
+ description: "This is what this form is referred as in the system"
6135
+ },
6136
+ pages: [
6137
+ {
6138
+ id: "collector",
6139
+ type: PageTypes.enum.FORM,
6140
+ title: {
6141
+ id: "event.tennis-club-membership.action.certificate.form.section.who.title",
6142
+ defaultMessage: "Print certified copy",
6143
+ description: "This is the title of the section"
6144
+ },
6145
+ fields: [
6146
+ {
6147
+ id: "identity.http-fetch",
6148
+ type: FieldType.HTTP,
6149
+ label: {
6150
+ defaultMessage: "Digital identity certificate",
6151
+ description: "Fetch printable digital identity certificate",
6152
+ id: "event.digital-identity.certificate.fetch.label"
6153
+ },
6154
+ configuration: {
6155
+ trigger: field("identity.http-button"),
6156
+ url: "/api/digital-identity/certificate",
6157
+ timeout: 5e3,
6158
+ method: "POST",
6159
+ headers: {
6160
+ "Content-Type": "application/json"
6161
+ },
6162
+ body: {
6163
+ subjectId: "$event.subject.id"
6164
+ }
6165
+ }
6166
+ },
6167
+ {
6168
+ id: "identity.http-button",
6169
+ type: FieldType.BUTTON,
6170
+ label: {
6171
+ defaultMessage: "Certificate",
6172
+ description: "Certificate",
6173
+ id: "event.digital-identity.certificate.button.label"
6174
+ },
6175
+ conditionals: [
6176
+ {
6177
+ type: ConditionalType.ENABLE,
6178
+ conditional: and(
6179
+ field("identity.http-fetch").isUndefined(),
6180
+ user.isOnline()
6181
+ )
6182
+ },
6183
+ {
6184
+ type: ConditionalType.SHOW,
6185
+ conditional: and(
6186
+ field("identity.http-fetch").get("loading").isFalsy(),
6187
+ field("identity.http-fetch").get("data").isFalsy()
6188
+ )
6189
+ }
6190
+ ],
6191
+ configuration: {
6192
+ icon: "IdentificationCard",
6193
+ text: {
6194
+ defaultMessage: "Fetch certificate",
6195
+ description: "Fetch certificate",
6196
+ id: "event.digital-identity.certificate.fetch.text"
6197
+ }
6198
+ }
6199
+ },
6200
+ {
6201
+ id: "identity.http-button",
6202
+ type: FieldType.BUTTON,
6203
+ label: {
6204
+ defaultMessage: "Certificate",
6205
+ description: "Certificate",
6206
+ id: "event.digital-identity.certificate.button.label"
6207
+ },
6208
+ conditionals: [
6209
+ {
6210
+ type: ConditionalType.ENABLE,
6211
+ conditional: never()
6212
+ },
6213
+ {
6214
+ type: ConditionalType.SHOW,
6215
+ conditional: field("identity.http-fetch").get("loading").isEqualTo(true)
6216
+ }
6217
+ ],
6218
+ configuration: {
6219
+ loading: true,
6220
+ text: {
6221
+ defaultMessage: "Fetching certificate\u2026",
6222
+ description: "Fetching certificate\u2026",
6223
+ id: "event.digital-identity.certificate.fetching.text"
6224
+ }
6225
+ }
6226
+ },
6227
+ {
6228
+ id: "identity.http-button",
6229
+ type: FieldType.BUTTON,
6230
+ label: {
6231
+ defaultMessage: "Certificate",
6232
+ description: "Certificate",
6233
+ id: "event.digital-identity.certificate.button.label"
6234
+ },
6235
+ conditionals: [
6236
+ {
6237
+ type: ConditionalType.ENABLE,
6238
+ conditional: never()
6239
+ },
6240
+ {
6241
+ type: ConditionalType.SHOW,
6242
+ conditional: not(field("identity.certificateId").isFalsy())
6243
+ }
6244
+ ],
6245
+ configuration: {
6246
+ icon: "Check",
6247
+ text: {
6248
+ defaultMessage: "Certificate ready",
6249
+ description: "Certificate ready",
6250
+ id: "event.digital-identity.certificate.ready.text"
6251
+ }
6252
+ }
6253
+ },
6254
+ {
6255
+ id: "identity.certificateId",
6256
+ type: FieldType.TEXT,
6257
+ parent: field("identity.http-fetch"),
6258
+ label: {
6259
+ defaultMessage: "Certificate ID",
6260
+ description: "Issued digital identity certificate identifier",
6261
+ id: "event.digital-identity.certificate.id.label"
6262
+ },
6263
+ conditionals: [
6264
+ {
6265
+ type: ConditionalType.ENABLE,
6266
+ conditional: never()
6267
+ }
6268
+ ],
6269
+ value: field("identity.http-fetch").get("data.certificateId")
6270
+ }
6271
+ ]
6272
+ }
6273
+ ]
6274
+ });
6275
+ var digitalIdentityForm = defineDeclarationForm({
6276
+ label: {
6277
+ id: "event.digital-identity.action.declare.form.label",
6278
+ defaultMessage: "Digital identity issuance",
6279
+ description: "This is what this form is referred as in the system"
6280
+ },
6281
+ pages: [
6282
+ {
6283
+ id: "subject",
6284
+ title: {
6285
+ id: "event.digital-identity.action.declare.form.section.who.title",
6286
+ defaultMessage: "Who is the digital identity issued to?",
6287
+ description: "This is the title of the section"
6288
+ },
6289
+ fields: [
6290
+ {
6291
+ id: "subject.firstname",
6292
+ type: FieldType.TEXT,
6293
+ required: true,
6294
+ conditionals: [],
6295
+ label: {
6296
+ defaultMessage: "Subject's first name",
6297
+ description: "This is the label for the field",
6298
+ id: "event.digital-identity.action.declare.form.section.who.field.firstname.label"
6299
+ }
6300
+ },
6301
+ {
6302
+ id: "subject.surname",
6303
+ type: FieldType.TEXT,
6304
+ required: true,
6305
+ conditionals: [],
6306
+ label: {
6307
+ defaultMessage: "Subject's surname",
6308
+ description: "This is the label for the field",
6309
+ id: "event.digital-identity.action.declare.form.section.who.field.surname.label"
6310
+ }
6311
+ }
6312
+ ]
6313
+ }
6314
+ ]
6315
+ });
6316
+ var digitalIdentityEvent = defineConfig({
6317
+ id: "digital-identity",
6318
+ label: {
6319
+ defaultMessage: "Digital identity issuance",
6320
+ description: "This is what this event is referred as in the system",
6321
+ id: "event.digital-identity.label"
6322
+ },
6323
+ title: {
6324
+ defaultMessage: "{subject.firstname} {subject.surname}",
6325
+ description: "This is the title of the summary",
6326
+ id: "event.digital-identity.title"
6327
+ },
6328
+ summary: { fields: [] },
6329
+ actions: [
6330
+ {
6331
+ type: ActionType.PRINT_CERTIFICATE,
6332
+ label: {
6333
+ id: "event.football-club-membership.action.collect-certificate.label",
6334
+ defaultMessage: "Print certificate",
6335
+ description: "This is shown as the action name anywhere the user can trigger the action from"
6336
+ },
6337
+ printForm: PRINT_DIGITAL_ID_CERTIFICATE_FORM
6338
+ }
6339
+ ],
6340
+ declaration: digitalIdentityForm
6341
+ });
6342
+
6029
6343
  // ../commons/src/events/test.utils.ts
6030
6344
  var import_zod35 = require("zod");
6031
6345
  var TestUserRole = import_zod35.z.enum([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencrvs/toolkit",
3
- "version": "1.9.2",
3
+ "version": "1.9.3-rc.0b3cc48",
4
4
  "description": "OpenCRVS toolkit for building country configurations",
5
5
  "license": "MPL-2.0",
6
6
  "exports": {