@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.
@@ -2443,6 +2443,9 @@ var PageTypes = import_zod16.z.enum(["FORM", "VERIFICATION"]);
2443
2443
  var PageConfigBase = import_zod16.z.object({
2444
2444
  id: import_zod16.z.string().describe("Unique identifier for the page"),
2445
2445
  title: TranslationConfig.describe("Header title of the page"),
2446
+ requireCompletionToContinue: import_zod16.z.boolean().default(false).describe(
2447
+ "If true, all required fields must be filled before continuing to the next page"
2448
+ ),
2446
2449
  fields: import_zod16.z.array(FieldConfig).describe("Fields to be rendered on the page"),
2447
2450
  conditional: Conditional.optional().describe(
2448
2451
  "Page will be shown if condition is met. If conditional is not defined, the page will be always shown."
@@ -3182,9 +3185,30 @@ var DataContext = import_zod25.z.object({
3182
3185
  $leafAdminStructureLocationIds: import_zod25.z.array(import_zod25.z.object({ id: UUID }))
3183
3186
  })
3184
3187
  });
3188
+ function resolveDataPath(rootData, dataPath, instancePath) {
3189
+ const pathParts = dataPath.split("/");
3190
+ const levels = parseInt(pathParts[0], 10);
3191
+ const referencePath = pathParts.slice(1);
3192
+ const instanceParts = instancePath.split("/").filter(Boolean);
3193
+ const traversedParts = instanceParts.slice(0, -levels);
3194
+ let current = rootData;
3195
+ for (const part of traversedParts) {
3196
+ if (current === null || current === void 0) {
3197
+ return void 0;
3198
+ }
3199
+ current = current[part];
3200
+ }
3201
+ for (const part of referencePath) {
3202
+ if (current === null || current === void 0) {
3203
+ return void 0;
3204
+ }
3205
+ current = current[part];
3206
+ }
3207
+ return current;
3208
+ }
3185
3209
  (0, import_ajv_formats.default)(ajv);
3186
3210
  ajv.addKeyword({
3187
- keyword: "daysFromNow",
3211
+ keyword: "daysFromDate",
3188
3212
  type: "string",
3189
3213
  schemaType: "object",
3190
3214
  $data: true,
@@ -3201,8 +3225,22 @@ ajv.addKeyword({
3201
3225
  if (isNaN(date.getTime())) {
3202
3226
  return false;
3203
3227
  }
3204
- const now = new Date(dataContext.rootData.$now);
3205
- const offsetDate = new Date(now.getTime() + days * 24 * 60 * 60 * 1e3);
3228
+ let referenceDate = schema.referenceDate;
3229
+ if (referenceDate && typeof referenceDate === "object" && "$data" in referenceDate) {
3230
+ referenceDate = resolveDataPath(
3231
+ dataContext.rootData,
3232
+ referenceDate.$data,
3233
+ dataContext.instancePath
3234
+ );
3235
+ }
3236
+ if (!referenceDate) {
3237
+ referenceDate = dataContext.rootData.$now;
3238
+ }
3239
+ const baseDate = new Date(referenceDate);
3240
+ if (isNaN(baseDate.getTime())) {
3241
+ return false;
3242
+ }
3243
+ const offsetDate = new Date(baseDate.getTime() + days * 24 * 60 * 60 * 1e3);
3206
3244
  return clause === "after" ? (0, import_date_fns.isAfter)(date, offsetDate) : (0, import_date_fns.isBefore)(date, offsetDate);
3207
3245
  }
3208
3246
  });
@@ -3265,7 +3303,8 @@ function isConditionMet(conditional, values, context) {
3265
3303
  $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3266
3304
  $online: isOnline(),
3267
3305
  $user: context.user,
3268
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? []
3306
+ $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3307
+ $event: context.event
3269
3308
  });
3270
3309
  }
3271
3310
  function getConditionalActionsForField(field3, values) {
@@ -3291,7 +3330,8 @@ function isFieldConditionMet(field3, form, conditionalType, context) {
3291
3330
  $now: (0, import_date_fns.formatISO)(/* @__PURE__ */ new Date(), { representation: "date" }),
3292
3331
  $online: isOnline(),
3293
3332
  $user: context.user,
3294
- $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? []
3333
+ $leafAdminStructureLocationIds: context.leafAdminStructureLocationIds ?? [],
3334
+ $event: context.event
3295
3335
  });
3296
3336
  return validConditionals.includes(conditionalType);
3297
3337
  }
@@ -4113,6 +4153,34 @@ function getDateRangeToFieldReference(field3, comparedField, clause) {
4113
4153
  required: [field3.$$field]
4114
4154
  };
4115
4155
  }
4156
+ function getDayRangeToFieldReference(field3, comparedField, days, clause) {
4157
+ return {
4158
+ type: "object",
4159
+ properties: {
4160
+ [field3.$$field]: wrapToPath(
4161
+ {
4162
+ type: "string",
4163
+ format: "date",
4164
+ daysFromDate: {
4165
+ referenceDate: {
4166
+ $data: `${field3.$$subfield.length + 1}/${jsonFieldPath(
4167
+ comparedField
4168
+ )}`
4169
+ },
4170
+ clause,
4171
+ days
4172
+ }
4173
+ },
4174
+ field3.$$subfield
4175
+ ),
4176
+ [comparedField.$$field]: wrapToPath(
4177
+ { type: "string", format: "date" },
4178
+ comparedField.$$subfield
4179
+ )
4180
+ },
4181
+ required: [field3.$$field]
4182
+ };
4183
+ }
4116
4184
  function defineComparison(field3, value, keyword) {
4117
4185
  if (isFieldReference(value)) {
4118
4186
  const comparedField = value;
@@ -4148,16 +4216,17 @@ function defineComparison(field3, value, keyword) {
4148
4216
  });
4149
4217
  }
4150
4218
  function createFieldConditionals(fieldId) {
4151
- const getDayRange = (field3, days, clause) => ({
4219
+ const getDayRange = (field3, days, clause, referenceDate) => ({
4152
4220
  type: "object",
4153
4221
  properties: {
4154
4222
  [field3.$$field]: wrapToPath(
4155
4223
  {
4156
4224
  type: "string",
4157
4225
  format: "date",
4158
- daysFromNow: {
4226
+ daysFromDate: {
4159
4227
  days,
4160
- clause
4228
+ clause,
4229
+ referenceDate
4161
4230
  }
4162
4231
  },
4163
4232
  field3.$$subfield
@@ -4210,7 +4279,19 @@ function createFieldConditionals(fieldId) {
4210
4279
  return {
4211
4280
  days: (days) => ({
4212
4281
  inPast: () => defineFormConditional(getDayRange(this, -days, "after")),
4213
- inFuture: () => defineFormConditional(getDayRange(this, days, "after"))
4282
+ inFuture: () => defineFormConditional(getDayRange(this, days, "after")),
4283
+ fromDate: (date) => {
4284
+ if (isFieldReference(date)) {
4285
+ const comparedField = date;
4286
+ return defineFormConditional(
4287
+ getDayRangeToFieldReference(this, comparedField, days, "after")
4288
+ );
4289
+ }
4290
+ return defineFormConditional(getDayRange(this, days, "after", date));
4291
+ },
4292
+ fromNow: () => {
4293
+ return defineFormConditional(getDayRange(this, days, "after"));
4294
+ }
4214
4295
  }),
4215
4296
  date: (date) => {
4216
4297
  if (isFieldReference(date)) {
@@ -4232,7 +4313,26 @@ function createFieldConditionals(fieldId) {
4232
4313
  return {
4233
4314
  days: (days) => ({
4234
4315
  inPast: () => defineFormConditional(getDayRange(this, -days, "before")),
4235
- inFuture: () => defineFormConditional(getDayRange(this, days, "before"))
4316
+ inFuture: () => defineFormConditional(getDayRange(this, days, "before")),
4317
+ fromDate: (date) => {
4318
+ if (isFieldReference(date)) {
4319
+ const comparedField = date;
4320
+ return defineFormConditional(
4321
+ getDayRangeToFieldReference(
4322
+ this,
4323
+ comparedField,
4324
+ -days,
4325
+ "before"
4326
+ )
4327
+ );
4328
+ }
4329
+ return defineFormConditional(
4330
+ getDayRange(this, -days, "before", date)
4331
+ );
4332
+ },
4333
+ fromNow: () => {
4334
+ return defineFormConditional(getDayRange(this, -days, "before"));
4335
+ }
4236
4336
  }),
4237
4337
  date: (date) => {
4238
4338
  if (isFieldReference(date)) {
@@ -5555,6 +5655,7 @@ var PRINT_CERTIFICATE_FORM = defineActionForm({
5555
5655
  {
5556
5656
  id: "collector",
5557
5657
  type: PageTypes.enum.FORM,
5658
+ requireCompletionToContinue: true,
5558
5659
  title: {
5559
5660
  id: "event.tennis-club-membership.action.certificate.form.section.who.title",
5560
5661
  defaultMessage: "Print certified copy",
@@ -6162,6 +6263,7 @@ var PRINT_CERTIFICATE_FORM = defineActionForm({
6162
6263
  {
6163
6264
  id: "collector.identity.verify",
6164
6265
  type: PageTypes.enum.VERIFICATION,
6266
+ requireCompletionToContinue: true,
6165
6267
  conditional: field("collector.requesterId").isEqualTo("INFORMANT"),
6166
6268
  title: {
6167
6269
  id: "event.tennis-club-membership.action.print.verifyIdentity",
@@ -7760,6 +7862,220 @@ var v2BirthEvent = defineConfig({
7760
7862
  advancedSearch: []
7761
7863
  });
7762
7864
 
7865
+ // ../commons/src/fixtures/digital-identity-issuance-event.ts
7866
+ var PRINT_DIGITAL_ID_CERTIFICATE_FORM = defineActionForm({
7867
+ label: {
7868
+ id: "event.digital-identity.action.certificate.form.label",
7869
+ defaultMessage: "Digital identity certificate printer",
7870
+ description: "This is what this form is referred as in the system"
7871
+ },
7872
+ pages: [
7873
+ {
7874
+ id: "collector",
7875
+ type: PageTypes.enum.FORM,
7876
+ title: {
7877
+ id: "event.tennis-club-membership.action.certificate.form.section.who.title",
7878
+ defaultMessage: "Print certified copy",
7879
+ description: "This is the title of the section"
7880
+ },
7881
+ fields: [
7882
+ {
7883
+ id: "identity.http-fetch",
7884
+ type: FieldType.HTTP,
7885
+ label: {
7886
+ defaultMessage: "Digital identity certificate",
7887
+ description: "Fetch printable digital identity certificate",
7888
+ id: "event.digital-identity.certificate.fetch.label"
7889
+ },
7890
+ configuration: {
7891
+ trigger: field("identity.http-button"),
7892
+ url: "/api/digital-identity/certificate",
7893
+ timeout: 5e3,
7894
+ method: "POST",
7895
+ headers: {
7896
+ "Content-Type": "application/json"
7897
+ },
7898
+ body: {
7899
+ subjectId: "$event.subject.id"
7900
+ }
7901
+ }
7902
+ },
7903
+ {
7904
+ id: "identity.http-button",
7905
+ type: FieldType.BUTTON,
7906
+ label: {
7907
+ defaultMessage: "Certificate",
7908
+ description: "Certificate",
7909
+ id: "event.digital-identity.certificate.button.label"
7910
+ },
7911
+ conditionals: [
7912
+ {
7913
+ type: ConditionalType.ENABLE,
7914
+ conditional: and(
7915
+ field("identity.http-fetch").isUndefined(),
7916
+ user.isOnline()
7917
+ )
7918
+ },
7919
+ {
7920
+ type: ConditionalType.SHOW,
7921
+ conditional: and(
7922
+ field("identity.http-fetch").get("loading").isFalsy(),
7923
+ field("identity.http-fetch").get("data").isFalsy()
7924
+ )
7925
+ }
7926
+ ],
7927
+ configuration: {
7928
+ icon: "IdentificationCard",
7929
+ text: {
7930
+ defaultMessage: "Fetch certificate",
7931
+ description: "Fetch certificate",
7932
+ id: "event.digital-identity.certificate.fetch.text"
7933
+ }
7934
+ }
7935
+ },
7936
+ {
7937
+ id: "identity.http-button",
7938
+ type: FieldType.BUTTON,
7939
+ label: {
7940
+ defaultMessage: "Certificate",
7941
+ description: "Certificate",
7942
+ id: "event.digital-identity.certificate.button.label"
7943
+ },
7944
+ conditionals: [
7945
+ {
7946
+ type: ConditionalType.ENABLE,
7947
+ conditional: never()
7948
+ },
7949
+ {
7950
+ type: ConditionalType.SHOW,
7951
+ conditional: field("identity.http-fetch").get("loading").isEqualTo(true)
7952
+ }
7953
+ ],
7954
+ configuration: {
7955
+ loading: true,
7956
+ text: {
7957
+ defaultMessage: "Fetching certificate\u2026",
7958
+ description: "Fetching certificate\u2026",
7959
+ id: "event.digital-identity.certificate.fetching.text"
7960
+ }
7961
+ }
7962
+ },
7963
+ {
7964
+ id: "identity.http-button",
7965
+ type: FieldType.BUTTON,
7966
+ label: {
7967
+ defaultMessage: "Certificate",
7968
+ description: "Certificate",
7969
+ id: "event.digital-identity.certificate.button.label"
7970
+ },
7971
+ conditionals: [
7972
+ {
7973
+ type: ConditionalType.ENABLE,
7974
+ conditional: never()
7975
+ },
7976
+ {
7977
+ type: ConditionalType.SHOW,
7978
+ conditional: not(field("identity.certificateId").isFalsy())
7979
+ }
7980
+ ],
7981
+ configuration: {
7982
+ icon: "Check",
7983
+ text: {
7984
+ defaultMessage: "Certificate ready",
7985
+ description: "Certificate ready",
7986
+ id: "event.digital-identity.certificate.ready.text"
7987
+ }
7988
+ }
7989
+ },
7990
+ {
7991
+ id: "identity.certificateId",
7992
+ type: FieldType.TEXT,
7993
+ parent: field("identity.http-fetch"),
7994
+ label: {
7995
+ defaultMessage: "Certificate ID",
7996
+ description: "Issued digital identity certificate identifier",
7997
+ id: "event.digital-identity.certificate.id.label"
7998
+ },
7999
+ conditionals: [
8000
+ {
8001
+ type: ConditionalType.ENABLE,
8002
+ conditional: never()
8003
+ }
8004
+ ],
8005
+ value: field("identity.http-fetch").get("data.certificateId")
8006
+ }
8007
+ ]
8008
+ }
8009
+ ]
8010
+ });
8011
+ var digitalIdentityForm = defineDeclarationForm({
8012
+ label: {
8013
+ id: "event.digital-identity.action.declare.form.label",
8014
+ defaultMessage: "Digital identity issuance",
8015
+ description: "This is what this form is referred as in the system"
8016
+ },
8017
+ pages: [
8018
+ {
8019
+ id: "subject",
8020
+ title: {
8021
+ id: "event.digital-identity.action.declare.form.section.who.title",
8022
+ defaultMessage: "Who is the digital identity issued to?",
8023
+ description: "This is the title of the section"
8024
+ },
8025
+ fields: [
8026
+ {
8027
+ id: "subject.firstname",
8028
+ type: FieldType.TEXT,
8029
+ required: true,
8030
+ conditionals: [],
8031
+ label: {
8032
+ defaultMessage: "Subject's first name",
8033
+ description: "This is the label for the field",
8034
+ id: "event.digital-identity.action.declare.form.section.who.field.firstname.label"
8035
+ }
8036
+ },
8037
+ {
8038
+ id: "subject.surname",
8039
+ type: FieldType.TEXT,
8040
+ required: true,
8041
+ conditionals: [],
8042
+ label: {
8043
+ defaultMessage: "Subject's surname",
8044
+ description: "This is the label for the field",
8045
+ id: "event.digital-identity.action.declare.form.section.who.field.surname.label"
8046
+ }
8047
+ }
8048
+ ]
8049
+ }
8050
+ ]
8051
+ });
8052
+ var digitalIdentityEvent = defineConfig({
8053
+ id: "digital-identity",
8054
+ label: {
8055
+ defaultMessage: "Digital identity issuance",
8056
+ description: "This is what this event is referred as in the system",
8057
+ id: "event.digital-identity.label"
8058
+ },
8059
+ title: {
8060
+ defaultMessage: "{subject.firstname} {subject.surname}",
8061
+ description: "This is the title of the summary",
8062
+ id: "event.digital-identity.title"
8063
+ },
8064
+ summary: { fields: [] },
8065
+ actions: [
8066
+ {
8067
+ type: ActionType.PRINT_CERTIFICATE,
8068
+ label: {
8069
+ id: "event.football-club-membership.action.collect-certificate.label",
8070
+ defaultMessage: "Print certificate",
8071
+ description: "This is shown as the action name anywhere the user can trigger the action from"
8072
+ },
8073
+ printForm: PRINT_DIGITAL_ID_CERTIFICATE_FORM
8074
+ }
8075
+ ],
8076
+ declaration: digitalIdentityForm
8077
+ });
8078
+
7763
8079
  // ../commons/src/events/test.utils.ts
7764
8080
  var import_zod35 = require("zod");
7765
8081
  var TEST_SYSTEM_IANA_TIMEZONE = "Asia/Dhaka";