@overmap-ai/core 1.0.50 → 1.0.51-bulk-form-submission.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.
@@ -677,15 +677,15 @@ const wrapMigration = (migrator) => (state) => {
677
677
  };
678
678
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
679
679
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
680
- const initialState$n = {
680
+ const initialState$p = {
681
681
  accessToken: "",
682
682
  refreshToken: "",
683
683
  isLoggedIn: false
684
684
  };
685
685
  const authSlice = createSlice({
686
686
  name: "auth",
687
- initialState: initialState$n,
688
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
687
+ initialState: initialState$p,
688
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
689
689
  reducers: {
690
690
  setTokens: (state, action) => {
691
691
  state.accessToken = action.payload.accessToken;
@@ -850,6 +850,19 @@ function downloadInMemoryFile(filename, text) {
850
850
  element.click();
851
851
  document.body.removeChild(element);
852
852
  }
853
+ const constructUploadedFilePayloads = async (files) => {
854
+ const filePayloads = {};
855
+ for (const file of files) {
856
+ const sha1 = await hashFile(file);
857
+ filePayloads[sha1] = {
858
+ sha1,
859
+ extension: file.name.split(".").pop() || "",
860
+ file_type: file.type,
861
+ size: file.size
862
+ };
863
+ }
864
+ return Object.values(filePayloads);
865
+ };
853
866
  const fileToBlob = async (dataUrl) => {
854
867
  return (await fetch(dataUrl)).blob();
855
868
  };
@@ -1416,7 +1429,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1416
1429
  return getLocalDateString(date);
1417
1430
  return relative.format(days, "days");
1418
1431
  });
1419
- const initialState$m = {
1432
+ const initialState$o = {
1420
1433
  categories: {},
1421
1434
  usedCategoryColors: [],
1422
1435
  categoryVisibility: {
@@ -1426,8 +1439,8 @@ const initialState$m = {
1426
1439
  };
1427
1440
  const categorySlice = createSlice({
1428
1441
  name: "categories",
1429
- initialState: initialState$m,
1430
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1442
+ initialState: initialState$o,
1443
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
1431
1444
  reducers: {
1432
1445
  setCategories: (state, action) => {
1433
1446
  if (!Array.isArray(action.payload))
@@ -1596,14 +1609,14 @@ function removeAttachments(state, action) {
1596
1609
  delete state.attachments[attachmentId];
1597
1610
  }
1598
1611
  }
1599
- const initialState$l = {
1612
+ const initialState$n = {
1600
1613
  components: {},
1601
1614
  attachments: {}
1602
1615
  };
1603
1616
  const componentSlice = createSlice({
1604
1617
  name: "components",
1605
- initialState: initialState$l,
1606
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1618
+ initialState: initialState$n,
1619
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
1607
1620
  reducers: {
1608
1621
  addComponent: (state, action) => {
1609
1622
  state.components[action.payload.offline_id] = action.payload;
@@ -1759,13 +1772,13 @@ const {
1759
1772
  removeAllComponentsOfType
1760
1773
  } = componentSlice.actions;
1761
1774
  const componentReducer = componentSlice.reducer;
1762
- const initialState$k = {
1775
+ const initialState$m = {
1763
1776
  completionsByComponentId: {}
1764
1777
  };
1765
1778
  const componentStageCompletionSlice = createSlice({
1766
1779
  name: "componentStageCompletions",
1767
- initialState: initialState$k,
1768
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1780
+ initialState: initialState$m,
1781
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1769
1782
  reducers: {
1770
1783
  addStageCompletion: (state, action) => {
1771
1784
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1816,13 +1829,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1816
1829
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1817
1830
  };
1818
1831
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1819
- const initialState$j = {
1832
+ const initialState$l = {
1820
1833
  stages: {}
1821
1834
  };
1822
1835
  const componentStageSlice = createSlice({
1823
1836
  name: "componentStages",
1824
- initialState: initialState$j,
1825
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1837
+ initialState: initialState$l,
1838
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1826
1839
  reducers: {
1827
1840
  addStages: (state, action) => {
1828
1841
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1932,15 +1945,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
1932
1945
  );
1933
1946
  const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
1934
1947
  const componentStageReducer = componentStageSlice.reducer;
1935
- const initialState$i = {
1948
+ const initialState$k = {
1936
1949
  componentTypes: {},
1937
1950
  hiddenComponentTypeIds: {},
1938
1951
  attachments: {}
1939
1952
  };
1940
1953
  const componentTypeSlice = createSlice({
1941
1954
  name: "componentTypes",
1942
- initialState: initialState$i,
1943
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1955
+ initialState: initialState$k,
1956
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1944
1957
  reducers: {
1945
1958
  addComponentType: (state, action) => {
1946
1959
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -2051,13 +2064,13 @@ const {
2051
2064
  deleteComponentType
2052
2065
  } = componentTypeSlice.actions;
2053
2066
  const componentTypeReducer = componentTypeSlice.reducer;
2054
- const initialState$h = {
2067
+ const initialState$j = {
2055
2068
  workspaces: {},
2056
2069
  activeWorkspaceId: null
2057
2070
  };
2058
2071
  const workspaceSlice = createSlice({
2059
2072
  name: "workspace",
2060
- initialState: initialState$h,
2073
+ initialState: initialState$j,
2061
2074
  // The `reducers` field lets us define reducers and generate associated actions
2062
2075
  reducers: {
2063
2076
  setWorkspaces: (state, action) => {
@@ -2114,7 +2127,7 @@ const selectPermittedWorkspaceIds = createSelector(
2114
2127
  );
2115
2128
  const workspaceReducer = workspaceSlice.reducer;
2116
2129
  const maxRecentIssues = 10;
2117
- const initialState$g = {
2130
+ const initialState$i = {
2118
2131
  issues: {},
2119
2132
  attachments: {},
2120
2133
  comments: {},
@@ -2126,9 +2139,9 @@ const initialState$g = {
2126
2139
  };
2127
2140
  const issueSlice = createSlice({
2128
2141
  name: "issues",
2129
- initialState: initialState$g,
2142
+ initialState: initialState$i,
2130
2143
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
2131
- Object.assign(state, initialState$g);
2144
+ Object.assign(state, initialState$i);
2132
2145
  }),
2133
2146
  reducers: {
2134
2147
  setIssues: (state, action) => {
@@ -2536,15 +2549,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2536
2549
  }
2537
2550
  );
2538
2551
  const issueReducer = issueSlice.reducer;
2539
- const initialState$f = {
2552
+ const initialState$h = {
2540
2553
  s3Urls: {}
2541
2554
  };
2542
2555
  const msPerHour = 1e3 * 60 * 60;
2543
2556
  const msPerWeek = msPerHour * 24 * 7;
2544
2557
  const fileSlice = createSlice({
2545
2558
  name: "file",
2546
- initialState: initialState$f,
2547
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2559
+ initialState: initialState$h,
2560
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
2548
2561
  reducers: {
2549
2562
  setUploadUrl: (state, action) => {
2550
2563
  const { url, fields, sha1 } = action.payload;
@@ -2571,7 +2584,7 @@ const selectUploadUrl = (sha1) => (state) => {
2571
2584
  return url;
2572
2585
  };
2573
2586
  const fileReducer = fileSlice.reducer;
2574
- const initialState$e = {
2587
+ const initialState$g = {
2575
2588
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2576
2589
  mapStyle: MapStyle.SATELLITE,
2577
2590
  showTooltips: false,
@@ -2579,8 +2592,8 @@ const initialState$e = {
2579
2592
  };
2580
2593
  const mapSlice = createSlice({
2581
2594
  name: "map",
2582
- initialState: initialState$e,
2583
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2595
+ initialState: initialState$g,
2596
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
2584
2597
  reducers: {
2585
2598
  setMapStyle: (state, action) => {
2586
2599
  state.mapStyle = action.payload;
@@ -2649,7 +2662,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2649
2662
  LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
2650
2663
  return LicenseStatus2;
2651
2664
  })(LicenseStatus || {});
2652
- const initialState$d = {
2665
+ const initialState$f = {
2653
2666
  users: {},
2654
2667
  currentUser: {
2655
2668
  id: 0,
@@ -2660,8 +2673,8 @@ const initialState$d = {
2660
2673
  };
2661
2674
  const userSlice = createSlice({
2662
2675
  name: "users",
2663
- initialState: initialState$d,
2664
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2676
+ initialState: initialState$f,
2677
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2665
2678
  reducers: {
2666
2679
  setUsers: (state, action) => {
2667
2680
  const usersMapping = {};
@@ -2723,13 +2736,13 @@ const selectUser = (userId) => (state) => {
2723
2736
  const selectUsersAsMapping = (state) => state.userReducer.users;
2724
2737
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2725
2738
  const userReducer = userSlice.reducer;
2726
- const initialState$c = {
2739
+ const initialState$e = {
2727
2740
  organizationAccesses: {}
2728
2741
  };
2729
2742
  const organizationAccessSlice = createSlice({
2730
2743
  name: "organizationAccess",
2731
- initialState: initialState$c,
2732
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2744
+ initialState: initialState$e,
2745
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2733
2746
  reducers: {
2734
2747
  setOrganizationAccesses: (state, action) => {
2735
2748
  if (!Array.isArray(action.payload))
@@ -2792,13 +2805,13 @@ const selectOrganizationAccessUserMapping = (state) => {
2792
2805
  return organizationAccesses;
2793
2806
  };
2794
2807
  const organizationAccessReducer = organizationAccessSlice.reducer;
2795
- const initialState$b = {
2808
+ const initialState$d = {
2796
2809
  licenses: {}
2797
2810
  };
2798
2811
  const licenseSlice = createSlice({
2799
2812
  name: "license",
2800
- initialState: initialState$b,
2801
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2813
+ initialState: initialState$d,
2814
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2802
2815
  reducers: {
2803
2816
  setLicenses: (state, action) => {
2804
2817
  if (!Array.isArray(action.payload))
@@ -2843,13 +2856,13 @@ const selectLicensesForProjectsMapping = createSelector(
2843
2856
  (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2844
2857
  );
2845
2858
  const licenseReducer = licenseSlice.reducer;
2846
- const initialState$a = {
2859
+ const initialState$c = {
2847
2860
  projectAccesses: {}
2848
2861
  };
2849
2862
  const projectAccessSlice = createSlice({
2850
2863
  name: "projectAccess",
2851
- initialState: initialState$a,
2852
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2864
+ initialState: initialState$c,
2865
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2853
2866
  reducers: {
2854
2867
  setProjectAccesses: (state, action) => {
2855
2868
  if (!Array.isArray(action.payload))
@@ -2917,7 +2930,7 @@ const selectProjectAccessUserMapping = (state) => {
2917
2930
  return projectAccesses;
2918
2931
  };
2919
2932
  const projectAccessReducer = projectAccessSlice.reducer;
2920
- const initialState$9 = {
2933
+ const initialState$b = {
2921
2934
  projects: {},
2922
2935
  activeProjectId: null,
2923
2936
  recentProjectIds: [],
@@ -2927,7 +2940,7 @@ const initialState$9 = {
2927
2940
  };
2928
2941
  const projectSlice = createSlice({
2929
2942
  name: "projects",
2930
- initialState: initialState$9,
2943
+ initialState: initialState$b,
2931
2944
  reducers: {
2932
2945
  setProjects: (state, action) => {
2933
2946
  const projectsMap = {};
@@ -3114,14 +3127,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
3114
3127
  }
3115
3128
  )
3116
3129
  );
3117
- const initialState$8 = {
3130
+ const initialState$a = {
3118
3131
  organizations: {},
3119
3132
  activeOrganizationId: null
3120
3133
  };
3121
3134
  const organizationSlice = createSlice({
3122
3135
  name: "organizations",
3123
- initialState: initialState$8,
3124
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3136
+ initialState: initialState$a,
3137
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
3125
3138
  reducers: {
3126
3139
  setOrganizations: (state, action) => {
3127
3140
  for (const org of action.payload) {
@@ -3240,14 +3253,14 @@ const createOfflineAction = (request2, baseUrl) => {
3240
3253
  }
3241
3254
  };
3242
3255
  };
3243
- const initialState$7 = {
3256
+ const initialState$9 = {
3244
3257
  deletedRequests: [],
3245
3258
  latestRetryTime: 0
3246
3259
  };
3247
3260
  const outboxSlice = createSlice({
3248
3261
  name: "outbox",
3249
- initialState: initialState$7,
3250
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3262
+ initialState: initialState$9,
3263
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
3251
3264
  reducers: {
3252
3265
  // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
3253
3266
  // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
@@ -3279,7 +3292,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
3279
3292
  const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
3280
3293
  const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
3281
3294
  const outboxReducer = outboxSlice.reducer;
3282
- const initialState$6 = {
3295
+ const initialState$8 = {
3283
3296
  projectFiles: {},
3284
3297
  activeProjectFileId: null,
3285
3298
  isImportingProjectFile: false,
@@ -3287,8 +3300,8 @@ const initialState$6 = {
3287
3300
  };
3288
3301
  const projectFileSlice = createSlice({
3289
3302
  name: "projectFiles",
3290
- initialState: initialState$6,
3291
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3303
+ initialState: initialState$8,
3304
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3292
3305
  reducers: {
3293
3306
  addOrReplaceProjectFiles: (state, action) => {
3294
3307
  for (let fileObj of action.payload) {
@@ -3389,12 +3402,12 @@ const selectProjectFiles = createSelector(
3389
3402
  const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
3390
3403
  const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
3391
3404
  const projectFileReducer = projectFileSlice.reducer;
3392
- const initialState$5 = {
3405
+ const initialState$7 = {
3393
3406
  isRehydrated: false
3394
3407
  };
3395
3408
  const rehydratedSlice = createSlice({
3396
3409
  name: "rehydrated",
3397
- initialState: initialState$5,
3410
+ initialState: initialState$7,
3398
3411
  // The `reducers` field lets us define reducers and generate associated actions
3399
3412
  reducers: {
3400
3413
  setRehydrated: (state, action) => {
@@ -3404,7 +3417,7 @@ const rehydratedSlice = createSlice({
3404
3417
  });
3405
3418
  const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
3406
3419
  const rehydratedReducer = rehydratedSlice.reducer;
3407
- const initialState$4 = {
3420
+ const initialState$6 = {
3408
3421
  useIssueTemplate: false,
3409
3422
  placementMode: false,
3410
3423
  enableClustering: false,
@@ -3421,8 +3434,8 @@ const initialState$4 = {
3421
3434
  };
3422
3435
  const settingSlice = createSlice({
3423
3436
  name: "settings",
3424
- initialState: initialState$4,
3425
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3437
+ initialState: initialState$6,
3438
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3426
3439
  reducers: {
3427
3440
  setEnableDuplicateIssues: (state, action) => {
3428
3441
  state.useIssueTemplate = action.payload;
@@ -3468,146 +3481,248 @@ const selectAppearance = (state) => state.settingReducer.appearance;
3468
3481
  const settingReducer = settingSlice.reducer;
3469
3482
  const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3470
3483
  const selectIsLoading = (state) => state.settingReducer.isLoading;
3471
- const LATEST_REVISION_CACHE = {};
3472
- function considerCachingRevision(revision, formId2, preferPending = false) {
3484
+ const LATEST_FORM_REVISION_CACHE = {};
3485
+ function considerCachingFormRevision(formRevision, formId2, preferPending = false) {
3473
3486
  var _a2;
3474
- if (!revision) {
3487
+ if (!formRevision) {
3475
3488
  if (!formId2) {
3476
- throw new Error("If revision is null, formId is required.");
3489
+ throw new Error("If form revision is null, formId is required.");
3477
3490
  }
3478
- const currentLatestRevision = getLatestRevisionFromCache(formId2);
3479
- if (currentLatestRevision)
3491
+ const currentLatestFormRevision = getLatestFormRevisionFromCache(formId2);
3492
+ if (currentLatestFormRevision)
3480
3493
  return;
3481
- LATEST_REVISION_CACHE[formId2] = null;
3494
+ LATEST_FORM_REVISION_CACHE[formId2] = null;
3482
3495
  return;
3483
3496
  }
3484
- if (revision.revision === "Pending") {
3497
+ if (formRevision.revision === "Pending") {
3485
3498
  if (preferPending) {
3486
- LATEST_REVISION_CACHE[revision.form] = revision;
3499
+ LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
3487
3500
  }
3488
3501
  return;
3489
3502
  }
3490
- const cachedRevision = (_a2 = LATEST_REVISION_CACHE[revision.form]) == null ? void 0 : _a2.revision;
3491
- if (revision.revision > (typeof cachedRevision === "number" ? cachedRevision : -1)) {
3492
- LATEST_REVISION_CACHE[revision.form] = revision;
3503
+ const cachedFormRevision = (_a2 = LATEST_FORM_REVISION_CACHE[formRevision.form]) == null ? void 0 : _a2.revision;
3504
+ if (formRevision.revision > (typeof cachedFormRevision === "number" ? cachedFormRevision : -1)) {
3505
+ LATEST_FORM_REVISION_CACHE[formRevision.form] = formRevision;
3493
3506
  }
3494
3507
  }
3495
- function getLatestRevisionFromCache(formId2) {
3496
- return LATEST_REVISION_CACHE[formId2];
3508
+ function getLatestFormRevisionFromCache(formId2) {
3509
+ return LATEST_FORM_REVISION_CACHE[formId2];
3497
3510
  }
3498
- const initialState$3 = {
3499
- userForms: {},
3500
- revisions: {},
3501
- submissions: {},
3502
- submissionAttachments: {},
3503
- revisionAttachments: {}
3504
- };
3505
- const userFormSlice = createSlice({
3506
- name: "userForms",
3507
- initialState: initialState$3,
3508
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3511
+ const initialState$5 = {
3512
+ formRevisions: {},
3513
+ attachments: {}
3514
+ };
3515
+ const formRevisionsSlice = createSlice({
3516
+ name: "formRevisions",
3517
+ initialState: initialState$5,
3518
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
3509
3519
  reducers: {
3510
- setUserForms: (state, action) => {
3511
- state.userForms = {};
3512
- action.payload.forEach((userForm) => {
3513
- state.userForms[userForm.offline_id] = userForm;
3514
- });
3515
- },
3516
- addUserForm: (state, action) => {
3517
- state.userForms[action.payload.offline_id] = action.payload;
3518
- },
3519
- addUserForms: (state, action) => {
3520
- action.payload.forEach((userForm) => {
3521
- state.userForms[userForm.offline_id] = userForm;
3522
- });
3523
- },
3524
- addUserFormRevisions: (state, action) => {
3525
- action.payload.forEach((userFormRevision) => {
3526
- state.revisions[userFormRevision.offline_id] = userFormRevision;
3527
- considerCachingRevision(userFormRevision);
3528
- });
3520
+ // revision related actions
3521
+ setFormRevision: (state, action) => {
3522
+ state.formRevisions[action.payload.offline_id] = action.payload;
3523
+ considerCachingFormRevision(action.payload);
3529
3524
  },
3530
- addUserFormRevision: (state, action) => {
3531
- state.revisions[action.payload.offline_id] = action.payload;
3532
- considerCachingRevision(action.payload);
3525
+ setFormRevisions: (state, action) => {
3526
+ state.formRevisions = {};
3527
+ for (const revision of action.payload) {
3528
+ state.formRevisions[revision.offline_id] = revision;
3529
+ considerCachingFormRevision(revision);
3530
+ }
3533
3531
  },
3534
- deleteUserFormRevision: (state, action) => {
3535
- delete state.revisions[action.payload];
3536
- delete LATEST_REVISION_CACHE[action.payload];
3532
+ addFormRevision: (state, action) => {
3533
+ if (state.formRevisions[action.payload.offline_id] !== void 0) {
3534
+ throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
3535
+ }
3536
+ state.formRevisions[action.payload.offline_id] = action.payload;
3537
+ considerCachingFormRevision(action.payload);
3537
3538
  },
3538
- deleteUserFormRevisions: (state, action) => {
3539
+ // TODO: @Audiopolis / Magnus - do we want to standardize using PayloadAction?
3540
+ addFormRevisions: (state, action) => {
3541
+ for (const userFormRevision of action.payload) {
3542
+ if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
3543
+ throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
3544
+ }
3545
+ }
3539
3546
  for (const userFormRevision of action.payload) {
3540
- delete state.revisions[userFormRevision.offline_id];
3541
- delete LATEST_REVISION_CACHE[userFormRevision.offline_id];
3547
+ state.formRevisions[userFormRevision.offline_id] = userFormRevision;
3548
+ considerCachingFormRevision(userFormRevision);
3542
3549
  }
3543
3550
  },
3544
- updateOrCreateUserFormSubmission: (state, action) => {
3545
- state.submissions[action.payload.offline_id] = action.payload;
3546
- },
3547
- addUserFormSubmissionAttachment: (state, action) => {
3548
- const submissionId = action.payload.submission;
3549
- const submissionAttachments = state.submissionAttachments[submissionId];
3550
- if (submissionAttachments) {
3551
- submissionAttachments.push(action.payload);
3552
- } else {
3553
- state.submissionAttachments[submissionId] = [action.payload];
3551
+ // UserFormRevisions do not get updated
3552
+ deleteFormRevision: (state, action) => {
3553
+ if (state.formRevisions[action.payload] === void 0) {
3554
+ throw new Error(`Revision with offline_id ${action.payload} does not exist`);
3554
3555
  }
3556
+ delete state.formRevisions[action.payload];
3557
+ delete LATEST_FORM_REVISION_CACHE[action.payload];
3555
3558
  },
3556
- addUserFormRevisionAttachment: (state, action) => {
3557
- const revisionId = action.payload.revision;
3558
- const revisionAttachments = state.revisionAttachments[revisionId];
3559
- if (revisionAttachments) {
3560
- revisionAttachments.push(action.payload);
3561
- } else {
3562
- state.revisionAttachments[revisionId] = [action.payload];
3559
+ deleteFormRevisions: (state, action) => {
3560
+ for (const offlineId of action.payload) {
3561
+ if (state.formRevisions[offlineId] === void 0) {
3562
+ throw new Error(`Revision with offline_id ${offlineId} does not exist`);
3563
+ }
3564
+ }
3565
+ for (const offlineId of action.payload) {
3566
+ delete state.formRevisions[offlineId];
3567
+ delete LATEST_FORM_REVISION_CACHE[offlineId];
3563
3568
  }
3564
3569
  },
3565
- setUserFormSubmissionAttachments: (state, action) => {
3566
- state.submissionAttachments = {};
3570
+ // attachment related actions
3571
+ setFormRevisionAttachments: (state, action) => {
3572
+ state.attachments = {};
3567
3573
  for (const attachment of action.payload) {
3568
- const submissionId = attachment.submission;
3569
- const submissionAttachments = state.submissionAttachments[submissionId];
3570
- if (submissionAttachments) {
3571
- submissionAttachments.push(attachment);
3572
- } else {
3573
- state.submissionAttachments[submissionId] = [attachment];
3574
- }
3574
+ state.attachments[attachment.offline_id] = attachment;
3575
3575
  }
3576
3576
  },
3577
- setUserFormRevisionAttachments: (state, action) => {
3578
- state.revisionAttachments = {};
3577
+ addFormRevisionAttachment: (state, action) => {
3578
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3579
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3580
+ }
3581
+ state.attachments[action.payload.offline_id] = action.payload;
3582
+ },
3583
+ addFormRevisionAttachments: (state, action) => {
3579
3584
  for (const attachment of action.payload) {
3580
- const revisionId = attachment.revision;
3581
- const revisionAttachments = state.revisionAttachments[revisionId];
3582
- if (revisionAttachments) {
3583
- revisionAttachments.push(attachment);
3584
- } else {
3585
- state.revisionAttachments[revisionId] = [attachment];
3585
+ if (state.attachments[attachment.offline_id] !== void 0) {
3586
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3586
3587
  }
3587
3588
  }
3589
+ for (const attachment of action.payload) {
3590
+ state.attachments[attachment.offline_id] = attachment;
3591
+ }
3588
3592
  },
3589
- deleteUserFormSubmission: (state, action) => {
3590
- delete state.submissions[action.payload];
3591
- },
3592
- deleteUserFormSubmissions: (state, action) => {
3593
- for (const userFormSubmission of action.payload) {
3594
- delete state.submissions[userFormSubmission.offline_id];
3593
+ deleteFormRevisionAttachment: (state, action) => {
3594
+ if (state.attachments[action.payload] === void 0) {
3595
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3595
3596
  }
3597
+ delete state.attachments[action.payload];
3596
3598
  },
3597
- addUserFormSubmissions: (state, action) => {
3598
- for (const submission of action.payload) {
3599
- state.submissions[submission.offline_id] = submission;
3599
+ deleteFormRevisionAttachments: (state, action) => {
3600
+ for (const offlineId of action.payload) {
3601
+ if (state.attachments[offlineId] === void 0) {
3602
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3603
+ }
3600
3604
  }
3605
+ for (const offlineId of action.payload) {
3606
+ delete state.attachments[offlineId];
3607
+ }
3608
+ }
3609
+ }
3610
+ });
3611
+ const {
3612
+ setFormRevision,
3613
+ setFormRevisions,
3614
+ addFormRevision,
3615
+ addFormRevisions,
3616
+ deleteFormRevision,
3617
+ deleteFormRevisions,
3618
+ setFormRevisionAttachments,
3619
+ addFormRevisionAttachment,
3620
+ addFormRevisionAttachments,
3621
+ deleteFormRevisionAttachment,
3622
+ deleteFormRevisionAttachments
3623
+ } = formRevisionsSlice.actions;
3624
+ const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
3625
+ const selectFormRevisions = createSelector(
3626
+ [selectFormRevisionMapping],
3627
+ (formRevisions) => Object.values(formRevisions)
3628
+ );
3629
+ const selectFormRevision = (formRevisionId) => (state) => {
3630
+ return state.formRevisionReducer.formRevisions[formRevisionId];
3631
+ };
3632
+ const _selectLatestFormRevision = (formRevisions, formId2) => {
3633
+ let ret = null;
3634
+ for (const candidate of Object.values(formRevisions)) {
3635
+ if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3636
+ ret = candidate;
3637
+ }
3638
+ }
3639
+ if (!ret) {
3640
+ throw new Error("No form revision found for form " + formId2);
3641
+ }
3642
+ return ret;
3643
+ };
3644
+ const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
3645
+ createSelector([selectFormRevisionMapping, (_state, formId2) => formId2], (revisions, formId2) => {
3646
+ if (!formId2) {
3647
+ throw new Error("formId is required");
3648
+ }
3649
+ return _selectLatestFormRevision(revisions, formId2);
3650
+ })
3651
+ );
3652
+ const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
3653
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3654
+ return revisions.filter((revision) => {
3655
+ return revision.form === formId2;
3656
+ });
3657
+ })
3658
+ );
3659
+ const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
3660
+ createSelector(
3661
+ [
3662
+ (state) => state.formReducer.forms,
3663
+ selectFormRevisionMapping,
3664
+ (_state, componentTypeIds) => componentTypeIds
3665
+ ],
3666
+ (userForms, revisions, componentTypeIds) => {
3667
+ const componentTypeIdsSet = new Set(componentTypeIds);
3668
+ const ret = {};
3669
+ for (const form of Object.values(userForms)) {
3670
+ if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3671
+ ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
3672
+ }
3673
+ }
3674
+ return ret;
3675
+ }
3676
+ )
3677
+ );
3678
+ const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
3679
+ const latestRevisions = {};
3680
+ for (const revision of Object.values(revisions)) {
3681
+ const formId2 = revision.form;
3682
+ const currentLatestRevision = latestRevisions[formId2];
3683
+ if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3684
+ latestRevisions[formId2] = revision;
3685
+ }
3686
+ }
3687
+ return latestRevisions;
3688
+ });
3689
+ const selectUserFormRevisionAttachmentsMapping = (state) => {
3690
+ return state.formRevisionReducer.attachments;
3691
+ };
3692
+ const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
3693
+ createSelector(
3694
+ [selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
3695
+ (attachments, revisionId) => {
3696
+ return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
3697
+ }
3698
+ )
3699
+ );
3700
+ const formRevisionReducer = formRevisionsSlice.reducer;
3701
+ const initialState$4 = {
3702
+ forms: {}
3703
+ };
3704
+ const formSlice = createSlice({
3705
+ name: "forms",
3706
+ initialState: initialState$4,
3707
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3708
+ reducers: {
3709
+ setForms: (state, action) => {
3710
+ state.forms = {};
3711
+ action.payload.forEach((userForm) => {
3712
+ state.forms[userForm.offline_id] = userForm;
3713
+ });
3601
3714
  },
3602
- setUserFormSubmissions: (state, action) => {
3603
- state.submissions = {};
3604
- action.payload.forEach((submission) => {
3605
- state.submissions[submission.offline_id] = submission;
3715
+ addForm: (state, action) => {
3716
+ state.forms[action.payload.offline_id] = action.payload;
3717
+ },
3718
+ addForms: (state, action) => {
3719
+ action.payload.forEach((userForm) => {
3720
+ state.forms[userForm.offline_id] = userForm;
3606
3721
  });
3607
3722
  },
3608
3723
  favoriteForm: (state, action) => {
3609
3724
  const { formId: formId2 } = action.payload;
3610
- const form = state.userForms[formId2];
3725
+ const form = state.forms[formId2];
3611
3726
  if (!form) {
3612
3727
  throw new Error("No form exists with the id " + formId2);
3613
3728
  }
@@ -3615,48 +3730,23 @@ const userFormSlice = createSlice({
3615
3730
  },
3616
3731
  unfavoriteForm: (state, action) => {
3617
3732
  const { formId: formId2 } = action.payload;
3618
- const form = state.userForms[formId2];
3733
+ const form = state.forms[formId2];
3619
3734
  if (!form) {
3620
3735
  throw new Error("No form exists with the id " + formId2);
3621
3736
  }
3622
3737
  form.favorite = false;
3623
3738
  },
3624
- deleteUserForm: (state, action) => {
3625
- delete state.userForms[action.payload];
3739
+ deleteForm: (state, action) => {
3740
+ delete state.forms[action.payload];
3626
3741
  }
3627
3742
  }
3628
3743
  });
3629
- const {
3630
- addUserForm,
3631
- addUserForms,
3632
- addUserFormRevisions,
3633
- updateOrCreateUserFormSubmission,
3634
- addUserFormSubmissions,
3635
- deleteUserFormSubmission,
3636
- deleteUserFormSubmissions,
3637
- favoriteForm,
3638
- unfavoriteForm,
3639
- deleteUserForm,
3640
- deleteUserFormRevision,
3641
- deleteUserFormRevisions,
3642
- setUserFormSubmissions,
3643
- addUserFormRevision,
3644
- addUserFormSubmissionAttachment,
3645
- addUserFormRevisionAttachment,
3646
- setUserFormSubmissionAttachments,
3647
- setUserFormRevisionAttachments
3648
- } = userFormSlice.actions;
3649
- const selectSubmissionAttachments = (submissionId) => (state) => {
3650
- return state.userFormReducer.submissionAttachments[submissionId] || [];
3651
- };
3652
- const selectRevisionAttachments = (revisionId) => (state) => {
3653
- return state.userFormReducer.revisionAttachments[revisionId] || [];
3654
- };
3655
- const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3744
+ const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
3745
+ const selectFilteredForms = restructureCreateSelectorWithArgs(
3656
3746
  createSelector(
3657
3747
  [
3658
- (state) => state.userFormReducer.userForms,
3659
- (state) => state.userFormReducer.revisions,
3748
+ (state) => state.formReducer.forms,
3749
+ (state) => state.formRevisionReducer.formRevisions,
3660
3750
  (_state, search) => search
3661
3751
  ],
3662
3752
  (userForms, revisions, search) => {
@@ -3690,63 +3780,188 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3690
3780
  { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3691
3781
  )
3692
3782
  );
3693
- const selectFormRevision = (revisionId) => (state) => {
3694
- return state.userFormReducer.revisions[revisionId];
3783
+ const selectForm = (formId2) => (state) => {
3784
+ return state.formReducer.forms[formId2];
3695
3785
  };
3696
- const _selectLatestFormRevision = (revisions, formId2) => {
3697
- let ret = null;
3698
- for (const candidate of Object.values(revisions)) {
3699
- if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3700
- ret = candidate;
3701
- }
3702
- }
3703
- if (!ret) {
3704
- throw new Error("No revision found for form " + formId2);
3705
- }
3706
- return ret;
3786
+ const selectFormMapping = (state) => {
3787
+ return state.formReducer.forms;
3707
3788
  };
3708
- const selectLatestFormRevision = restructureCreateSelectorWithArgs(
3789
+ const selectFormOfComponentType = restructureCreateSelectorWithArgs(
3709
3790
  createSelector(
3710
- [(state) => state.userFormReducer.revisions, (_state, formId2) => formId2],
3711
- (revisions, formId2) => {
3712
- if (!formId2) {
3713
- throw new Error("formId is required");
3714
- }
3715
- return _selectLatestFormRevision(revisions, formId2);
3791
+ [selectFormMapping, (_state, componentTypeId) => componentTypeId],
3792
+ (userForms, componentTypeId) => {
3793
+ return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3716
3794
  }
3717
3795
  )
3718
3796
  );
3719
- const selectUserForm = (formId2) => (state) => {
3720
- return state.userFormReducer.userForms[formId2];
3721
- };
3722
- const selectSubmissionMapping = (state) => state.userFormReducer.submissions;
3723
- const selectUserFormSubmission = (submissionId) => (state) => {
3724
- return state.userFormReducer.submissions[submissionId];
3725
- };
3726
- const selectSubmissions = createSelector([selectSubmissionMapping], (submissions) => Object.values(submissions));
3727
- const selectRevisionMapping = (state) => state.userFormReducer.revisions;
3728
- const selectRevisions = createSelector([selectRevisionMapping], (revisions) => Object.values(revisions));
3729
- const selectRevisionsForForm = restructureCreateSelectorWithArgs(
3730
- createSelector([selectRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3731
- return revisions.filter((revision) => {
3732
- return revision.form === formId2;
3733
- });
3734
- })
3797
+ const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
3798
+ return Object.keys(userForms).length;
3799
+ });
3800
+ const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
3801
+ return Object.values(userForms).filter((form) => !form.component_type).length;
3802
+ });
3803
+ const formReducer = formSlice.reducer;
3804
+ const initialState$3 = {
3805
+ formSubmissions: {},
3806
+ attachments: {}
3807
+ };
3808
+ const formSubmissionSlice = createSlice({
3809
+ name: "formSubmissions",
3810
+ initialState: initialState$3,
3811
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3812
+ reducers: {
3813
+ setFormSubmission: (state, action) => {
3814
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3815
+ },
3816
+ setFormSubmissions: (state, action) => {
3817
+ state.formSubmissions = {};
3818
+ for (const submission of action.payload) {
3819
+ state.formSubmissions[submission.offline_id] = submission;
3820
+ }
3821
+ },
3822
+ addFormSubmission: (state, action) => {
3823
+ if (state.formSubmissions[action.payload.offline_id] !== void 0) {
3824
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
3825
+ }
3826
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3827
+ },
3828
+ addFormSubmissions: (state, action) => {
3829
+ for (const submission of action.payload) {
3830
+ if (state.formSubmissions[submission.offline_id] !== void 0) {
3831
+ throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
3832
+ }
3833
+ }
3834
+ for (const submission of action.payload) {
3835
+ state.formSubmissions[submission.offline_id] = submission;
3836
+ }
3837
+ },
3838
+ updateFormSubmission: (state, action) => {
3839
+ if (state.formSubmissions[action.payload.offline_id] === void 0) {
3840
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
3841
+ }
3842
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3843
+ },
3844
+ updateFormSubmissions: (state, action) => {
3845
+ for (const submission of action.payload) {
3846
+ if (state.formSubmissions[submission.offline_id] === void 0) {
3847
+ throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
3848
+ }
3849
+ }
3850
+ for (const submission of action.payload) {
3851
+ state.formSubmissions[submission.offline_id] = submission;
3852
+ }
3853
+ },
3854
+ deleteFormSubmission: (state, action) => {
3855
+ if (state.formSubmissions[action.payload] === void 0) {
3856
+ throw new Error(`Submission with offline_id ${action.payload} does not exist`);
3857
+ }
3858
+ delete state.formSubmissions[action.payload];
3859
+ },
3860
+ deleteFormSubmissions: (state, action) => {
3861
+ for (const offlineId of action.payload) {
3862
+ if (state.formSubmissions[offlineId] === void 0) {
3863
+ throw new Error(`Submission with offline_id ${offlineId} does not exist`);
3864
+ }
3865
+ delete state.formSubmissions[offlineId];
3866
+ }
3867
+ for (const offlineId of action.payload) {
3868
+ delete state.formSubmissions[offlineId];
3869
+ }
3870
+ },
3871
+ // Attachments
3872
+ addFormSubmissionAttachment: (state, action) => {
3873
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3874
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3875
+ }
3876
+ state.attachments[action.payload.offline_id] = action.payload;
3877
+ },
3878
+ addFormSubmissionAttachments: (state, action) => {
3879
+ for (const attachment of action.payload) {
3880
+ if (state.attachments[attachment.offline_id] !== void 0) {
3881
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3882
+ }
3883
+ }
3884
+ for (const attachment of action.payload) {
3885
+ state.attachments[attachment.offline_id] = attachment;
3886
+ }
3887
+ },
3888
+ // We only need a multi set for attachments because they are not updated, only added and deleted
3889
+ setFormSubmissionAttachments: (state, action) => {
3890
+ state.attachments = {};
3891
+ for (const attachment of action.payload) {
3892
+ state.attachments[attachment.offline_id] = attachment;
3893
+ }
3894
+ },
3895
+ updateFormSubmissionAttachments: (state, action) => {
3896
+ for (const attachment of action.payload) {
3897
+ if (state.attachments[attachment.offline_id] === void 0) {
3898
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} does not exist`);
3899
+ }
3900
+ }
3901
+ for (const attachment of action.payload) {
3902
+ state.attachments[attachment.offline_id] = attachment;
3903
+ }
3904
+ },
3905
+ // The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
3906
+ // Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
3907
+ deleteFormSubmissionAttachment: (state, action) => {
3908
+ if (state.attachments[action.payload] === void 0) {
3909
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3910
+ }
3911
+ delete state.attachments[action.payload];
3912
+ },
3913
+ deleteFormSubmissionAttachments: (state, action) => {
3914
+ for (const offlineId of action.payload) {
3915
+ if (state.attachments[offlineId] === void 0) {
3916
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3917
+ }
3918
+ delete state.attachments[offlineId];
3919
+ }
3920
+ }
3921
+ }
3922
+ });
3923
+ const {
3924
+ setFormSubmission,
3925
+ setFormSubmissions,
3926
+ addFormSubmission,
3927
+ addFormSubmissions,
3928
+ updateFormSubmission,
3929
+ updateFormSubmissions,
3930
+ deleteFormSubmission,
3931
+ deleteFormSubmissions,
3932
+ addFormSubmissionAttachment,
3933
+ addFormSubmissionAttachments,
3934
+ setFormSubmissionAttachments,
3935
+ updateFormSubmissionAttachments,
3936
+ deleteFormSubmissionAttachment,
3937
+ deleteFormSubmissionAttachments
3938
+ } = formSubmissionSlice.actions;
3939
+ const selectFormSubmissionsMapping = (state) => {
3940
+ return state.formSubmissionReducer.formSubmissions;
3941
+ };
3942
+ const selectFormSubmissions = createSelector(
3943
+ [selectFormSubmissionsMapping],
3944
+ (submissions) => {
3945
+ return Object.values(submissions);
3946
+ }
3735
3947
  );
3736
- const selectSubmissionsForForm = restructureCreateSelectorWithArgs(
3948
+ const selectFormSubmission = (submissionId) => (state) => {
3949
+ return state.formSubmissionReducer.formSubmissions[submissionId];
3950
+ };
3951
+ const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
3737
3952
  createSelector(
3738
- [selectSubmissions, selectRevisionMapping, (_state, formId2) => formId2],
3953
+ [selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
3739
3954
  (submissions, revisionMapping, formId2) => {
3740
- return Object.values(submissions).filter((submission) => {
3955
+ return submissions.filter((submission) => {
3741
3956
  const revision = revisionMapping[submission.form_revision];
3742
3957
  return (revision == null ? void 0 : revision.form) === formId2;
3743
3958
  });
3744
3959
  }
3745
3960
  )
3746
3961
  );
3747
- const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3962
+ const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
3748
3963
  createSelector(
3749
- [(state) => state.userFormReducer.submissions, (_state, issueId) => issueId],
3964
+ [selectFormSubmissions, (_state, issueId) => issueId],
3750
3965
  (submissions, issueId) => {
3751
3966
  return Object.values(submissions).filter((submission) => {
3752
3967
  return submission.issue === issueId;
@@ -3754,9 +3969,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3754
3969
  }
3755
3970
  )
3756
3971
  );
3757
- const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3972
+ const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
3758
3973
  createSelector(
3759
- [selectSubmissions, (_state, componentId) => componentId],
3974
+ [selectFormSubmissions, (_state, componentId) => componentId],
3760
3975
  (submissions, componentId) => {
3761
3976
  return submissions.filter((submission) => {
3762
3977
  return submission.component === componentId;
@@ -3764,8 +3979,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3764
3979
  }
3765
3980
  )
3766
3981
  );
3767
- const selectComponentSubmissionMapping = createSelector(
3768
- [selectSubmissionMapping, selectComponentsMapping],
3982
+ const selectFormSubmissionsByComponents = createSelector(
3983
+ [selectFormSubmissionsMapping, selectComponentsMapping],
3769
3984
  (submissions, components) => {
3770
3985
  var _a2;
3771
3986
  const componentSubmissionMapping = {};
@@ -3781,54 +3996,18 @@ const selectComponentSubmissionMapping = createSelector(
3781
3996
  return componentSubmissionMapping;
3782
3997
  }
3783
3998
  );
3784
- const selectUserFormMapping = (state) => {
3785
- return state.userFormReducer.userForms;
3999
+ const selectFormSubmissionAttachmentsMapping = (state) => {
4000
+ return state.formSubmissionReducer.attachments;
3786
4001
  };
3787
- const selectComponentTypeForm = restructureCreateSelectorWithArgs(
4002
+ const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
3788
4003
  createSelector(
3789
- [selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
3790
- (userForms, componentTypeId) => {
3791
- return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3792
- }
3793
- )
3794
- );
3795
- const selectLatestRevisionsFromComponentTypeIds = restructureCreateSelectorWithArgs(
3796
- createSelector(
3797
- [
3798
- selectUserFormMapping,
3799
- selectRevisionMapping,
3800
- (_state, componentTypeIds) => componentTypeIds
3801
- ],
3802
- (userForms, revisions, componentTypeIds) => {
3803
- const componentTypeIdsSet = new Set(componentTypeIds);
3804
- const ret = {};
3805
- for (const form of Object.values(userForms)) {
3806
- if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3807
- ret[form.component_type] = _selectLatestFormRevision(revisions, form.offline_id);
3808
- }
3809
- }
3810
- return ret;
4004
+ [selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
4005
+ (attachmentsMapping, submissionId) => {
4006
+ return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
3811
4007
  }
3812
4008
  )
3813
4009
  );
3814
- const selectLatestRevisionByFormId = createSelector([selectRevisionMapping], (revisions) => {
3815
- const latestRevisions = {};
3816
- for (const revision of Object.values(revisions)) {
3817
- const formId2 = revision.form;
3818
- const currentLatestRevision = latestRevisions[formId2];
3819
- if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3820
- latestRevisions[formId2] = revision;
3821
- }
3822
- }
3823
- return latestRevisions;
3824
- });
3825
- const selectNumberOfUserForms = createSelector([selectUserFormMapping], (userForms) => {
3826
- return Object.keys(userForms).length;
3827
- });
3828
- const selectNumberOfGeneralUserForms = createSelector([selectUserFormMapping], (userForms) => {
3829
- return Object.values(userForms).filter((form) => !form.component_type).length;
3830
- });
3831
- const userFormReducer = userFormSlice.reducer;
4010
+ const formSubmissionReducer = formSubmissionSlice.reducer;
3832
4011
  const initialState$2 = {
3833
4012
  emailDomains: {}
3834
4013
  };
@@ -4126,7 +4305,9 @@ const overmapReducers = {
4126
4305
  projectFileReducer,
4127
4306
  rehydratedReducer,
4128
4307
  settingReducer,
4129
- userFormReducer,
4308
+ formReducer,
4309
+ formRevisionReducer,
4310
+ formSubmissionReducer,
4130
4311
  userReducer,
4131
4312
  workspaceReducer,
4132
4313
  emailDomainsReducer,
@@ -4179,9 +4360,7 @@ function handleWorkspaceRemoval(draft, action) {
4179
4360
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
4180
4361
  }
4181
4362
  }
4182
- const indexedForms = Object.values(draft.userFormReducer.userForms).filter(
4183
- (form) => form.index_workspace === workspaceId
4184
- );
4363
+ const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
4185
4364
  for (const form of indexedForms) {
4186
4365
  form.index_workspace = mainWorkspace.offline_id;
4187
4366
  }
@@ -6809,7 +6988,7 @@ class UserFormService extends BaseApiService {
6809
6988
  ...revisionAttachmentPayload,
6810
6989
  file: URL.createObjectURL(image)
6811
6990
  };
6812
- store.dispatch(addUserFormRevisionAttachment(offlinePayload));
6991
+ store.dispatch(addFormRevisionAttachment(offlinePayload));
6813
6992
  return attach;
6814
6993
  });
6815
6994
  });
@@ -6843,8 +7022,8 @@ class UserFormService extends BaseApiService {
6843
7022
  revision: 0
6844
7023
  };
6845
7024
  const { store } = this.client;
6846
- store.dispatch(addUserForm(retForm));
6847
- store.dispatch(addUserFormRevision(retRevision));
7025
+ store.dispatch(addForm(retForm));
7026
+ store.dispatch(addFormRevision(retRevision));
6848
7027
  const formPromise = this.enqueueRequest({
6849
7028
  description: "Create form",
6850
7029
  method: HttpMethod.POST,
@@ -6862,8 +7041,8 @@ class UserFormService extends BaseApiService {
6862
7041
  });
6863
7042
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
6864
7043
  void formPromise.catch((e) => {
6865
- store.dispatch(deleteUserForm(retForm.offline_id));
6866
- store.dispatch(deleteUserFormRevision(retRevision.offline_id));
7044
+ store.dispatch(deleteForm(retForm.offline_id));
7045
+ store.dispatch(deleteFormRevision(retRevision.offline_id));
6867
7046
  throw e;
6868
7047
  });
6869
7048
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
@@ -6905,7 +7084,7 @@ class UserFormService extends BaseApiService {
6905
7084
  revision: "Pending",
6906
7085
  form: formId2
6907
7086
  };
6908
- store.dispatch(addUserFormRevision(fullRevision));
7087
+ store.dispatch(addFormRevision(fullRevision));
6909
7088
  const promise = this.enqueueRequest({
6910
7089
  description: "Create form revision",
6911
7090
  method: HttpMethod.PATCH,
@@ -6919,9 +7098,9 @@ class UserFormService extends BaseApiService {
6919
7098
  });
6920
7099
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
6921
7100
  void promise.then((result) => {
6922
- store.dispatch(addUserFormRevision(result));
7101
+ store.dispatch(setFormRevision(result));
6923
7102
  }).catch(() => {
6924
- store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
7103
+ store.dispatch(deleteFormRevision(fullRevision.offline_id));
6925
7104
  });
6926
7105
  const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
6927
7106
  return [fullRevision, settledPromise];
@@ -6963,19 +7142,19 @@ class UserFormService extends BaseApiService {
6963
7142
  async delete(formId2) {
6964
7143
  const { store } = this.client;
6965
7144
  const state = store.getState();
6966
- const userForm = selectUserForm(formId2)(state);
7145
+ const userForm = selectForm(formId2)(state);
6967
7146
  if (!userForm) {
6968
7147
  throw new Error("Expected userForm to exist");
6969
7148
  }
6970
- const userFormSubmissions = selectSubmissionsForForm(formId2)(state);
7149
+ const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
6971
7150
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6972
- store.dispatch(deleteUserFormSubmissions(userFormSubmissions));
7151
+ store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
6973
7152
  }
6974
- const userFormRevisions = selectRevisionsForForm(formId2)(state);
7153
+ const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
6975
7154
  if (userFormRevisions && userFormRevisions.length > 0) {
6976
- store.dispatch(deleteUserFormRevisions(userFormRevisions));
7155
+ store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
6977
7156
  }
6978
- store.dispatch(deleteUserForm(formId2));
7157
+ store.dispatch(deleteForm(formId2));
6979
7158
  try {
6980
7159
  return await this.enqueueRequest({
6981
7160
  description: "Delete form",
@@ -6985,12 +7164,12 @@ class UserFormService extends BaseApiService {
6985
7164
  blocks: []
6986
7165
  });
6987
7166
  } catch (e) {
6988
- store.dispatch(addUserForm(userForm));
7167
+ store.dispatch(addForm(userForm));
6989
7168
  if (userFormRevisions && userFormRevisions.length > 0) {
6990
- store.dispatch(addUserFormRevisions(userFormRevisions));
7169
+ store.dispatch(addFormRevisions(userFormRevisions));
6991
7170
  }
6992
7171
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6993
- store.dispatch(addUserFormSubmissions(userFormSubmissions));
7172
+ store.dispatch(addFormSubmissions(userFormSubmissions));
6994
7173
  }
6995
7174
  throw e;
6996
7175
  }
@@ -7004,16 +7183,15 @@ class UserFormService extends BaseApiService {
7004
7183
  blockers: [],
7005
7184
  blocks: []
7006
7185
  });
7007
- store.dispatch(addUserForms(Object.values(result.forms)));
7008
- store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
7009
- store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
7186
+ store.dispatch(setForms(Object.values(result.forms)));
7187
+ store.dispatch(setFormRevisions(Object.values(result.revisions)));
7188
+ store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
7010
7189
  }
7011
7190
  }
7012
7191
  const isArrayOfFiles = (value) => {
7013
7192
  return Array.isArray(value) && value[0] instanceof File;
7014
7193
  };
7015
- const separateFilesFromValues = (payload) => {
7016
- const { values } = payload;
7194
+ const separateFilesFromValues = (values) => {
7017
7195
  const files = {};
7018
7196
  const newValues = {};
7019
7197
  for (const key in values) {
@@ -7028,17 +7206,13 @@ const separateFilesFromValues = (payload) => {
7028
7206
  newValues[key] = value;
7029
7207
  }
7030
7208
  }
7031
- const payloadWithoutFiles = {
7032
- ...payload,
7033
- values: newValues
7034
- };
7035
- return { payloadWithoutFiles, files };
7209
+ return { values: newValues, files };
7036
7210
  };
7037
7211
  class UserFormSubmissionService extends BaseApiService {
7038
7212
  constructor() {
7039
7213
  super(...arguments);
7040
7214
  // Attach files to submission, after uploading them to S3
7041
- __publicField(this, "getAttachFilesPromises", (files, payload) => {
7215
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
7042
7216
  const { store } = this.client;
7043
7217
  return Object.entries(files).map(async ([key, fileArray]) => {
7044
7218
  const attachResults = [];
@@ -7048,24 +7222,27 @@ class UserFormSubmissionService extends BaseApiService {
7048
7222
  const [fileProps] = await this.client.files.uploadFileToS3(sha1);
7049
7223
  const submissionAttachmentPayload = offline({
7050
7224
  ...fileProps,
7051
- submission: payload.offline_id,
7225
+ submission: submission.offline_id,
7052
7226
  field_identifier: key
7053
7227
  });
7054
7228
  const attach = await this.enqueueRequest({
7055
7229
  description: "Attach file to form submission",
7056
7230
  method: HttpMethod.POST,
7057
- url: `/forms/submission/${payload.offline_id}/attachments/`,
7231
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
7058
7232
  payload: submissionAttachmentPayload,
7059
- blockers: [payload.component, payload.component_stage, payload.issue, payload.form_revision].filter(
7060
- (x) => x !== void 0
7061
- ),
7233
+ blockers: [
7234
+ submission.component,
7235
+ submission.component_stage,
7236
+ submission.issue,
7237
+ submission.form_revision
7238
+ ].filter((x) => x !== void 0),
7062
7239
  blocks: [submissionAttachmentPayload.offline_id]
7063
7240
  });
7064
7241
  const offlinePayload = {
7065
7242
  ...submissionAttachmentPayload,
7066
7243
  file: URL.createObjectURL(file)
7067
7244
  };
7068
- store.dispatch(addUserFormSubmissionAttachment(offlinePayload));
7245
+ store.dispatch(addFormSubmissionAttachment(offlinePayload));
7069
7246
  attachResults.push(attach);
7070
7247
  }
7071
7248
  return attachResults;
@@ -7079,70 +7256,165 @@ class UserFormSubmissionService extends BaseApiService {
7079
7256
  if (!activeProjectId) {
7080
7257
  throw new Error("Expected an active project");
7081
7258
  }
7082
- const { payloadWithoutFiles, files } = separateFilesFromValues(payload);
7259
+ const { values, files } = separateFilesFromValues(payload.values);
7260
+ const offlineSubmission = {
7261
+ ...payload,
7262
+ values,
7263
+ created_by: state.userReducer.currentUser.id,
7264
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7265
+ };
7083
7266
  const promise = this.enqueueRequest({
7084
7267
  description: "Respond to form",
7085
7268
  method: HttpMethod.POST,
7086
7269
  url: `/forms/revisions/${payload.form_revision}/respond/`,
7087
- payload: { ...payloadWithoutFiles, project: activeProjectId },
7270
+ payload: { ...offlineSubmission, project: activeProjectId },
7088
7271
  blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
7089
7272
  (x) => x !== void 0
7090
7273
  ),
7091
7274
  blocks: [payload.offline_id]
7092
7275
  });
7093
- const attachFilesPromises = this.getAttachFilesPromises(files, payload);
7094
- const now = (/* @__PURE__ */ new Date()).toISOString();
7095
- const fullOfflineResult = {
7096
- ...payload,
7097
- created_by: state.userReducer.currentUser.id,
7098
- created_at: now,
7099
- updated_at: now
7100
- };
7101
- const offlineResultWithoutFiles = {
7102
- ...fullOfflineResult,
7103
- ...payloadWithoutFiles
7104
- };
7105
- store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
7276
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
7277
+ store.dispatch(addFormSubmission(offlineSubmission));
7106
7278
  void promise.then((result) => {
7107
7279
  store.dispatch(addActiveProjectFormSubmissionsCount(1));
7108
- store.dispatch(updateOrCreateUserFormSubmission(result));
7280
+ store.dispatch(setFormSubmission(result));
7109
7281
  return result;
7110
7282
  }).catch(() => {
7111
- store.dispatch(deleteUserFormSubmission(payload.offline_id));
7283
+ store.dispatch(deleteFormSubmission(payload.offline_id));
7112
7284
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7113
7285
  });
7114
7286
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7115
- return [fullOfflineResult, settledPromise];
7287
+ return [offlineSubmission, settledPromise];
7116
7288
  }
7117
- update(submission) {
7289
+ // Note currently the bulkAdd method is specific to form submissions for components
7290
+ // TODO: adapt the support bulk adding to any model type
7291
+ async bulkAdd(args) {
7292
+ const { form_revision, values: argsValues, componentOfflineIds } = args;
7118
7293
  const { store } = this.client;
7119
- const { payloadWithoutFiles, files } = separateFilesFromValues(submission);
7120
- if (!("created_by" in payloadWithoutFiles) || !("created_at" in payloadWithoutFiles)) {
7121
- throw new Error("Expected payloadWithoutFiles to have created_by and created_at fields.");
7294
+ const offlineSubmissions = [];
7295
+ const offlineAttachments = [];
7296
+ const submissionOfflineIds = [];
7297
+ const submissionsPayload = [];
7298
+ const attachmentsPayload = [];
7299
+ const { values, files } = separateFilesFromValues(argsValues);
7300
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7301
+ const createdBy = store.getState().userReducer.currentUser.id;
7302
+ for (const component_id of componentOfflineIds) {
7303
+ const submission = offline({
7304
+ form_revision,
7305
+ values,
7306
+ created_by: createdBy,
7307
+ submitted_at: submittedAt,
7308
+ component: component_id
7309
+ });
7310
+ submissionOfflineIds.push(submission.offline_id);
7311
+ submissionsPayload.push({ offline_id: submission.offline_id, component_id });
7312
+ offlineSubmissions.push(submission);
7313
+ for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7314
+ for (const file of fileArray) {
7315
+ const sha1 = await hashFile(file);
7316
+ await this.client.files.addCache(file, sha1);
7317
+ const offlineAttachment = offline({
7318
+ file_name: file.name,
7319
+ file_sha1: sha1,
7320
+ file: URL.createObjectURL(file),
7321
+ submission: submission.offline_id,
7322
+ field_identifier: fieldIdentifier
7323
+ });
7324
+ offlineAttachments.push(offlineAttachment);
7325
+ attachmentsPayload.push({
7326
+ offline_id: offlineAttachment.offline_id,
7327
+ submission_id: submission.offline_id,
7328
+ sha1,
7329
+ name: file.name,
7330
+ field_identifier: fieldIdentifier
7331
+ });
7332
+ }
7333
+ }
7334
+ }
7335
+ const filesRecord = {};
7336
+ for (const file of Object.values(files).flat()) {
7337
+ const sha1 = await hashFile(file);
7338
+ filesRecord[sha1] = {
7339
+ sha1,
7340
+ extension: file.name.split(".").pop() || "",
7341
+ file_type: file.type,
7342
+ size: file.size
7343
+ };
7122
7344
  }
7345
+ store.dispatch(addFormSubmissions(offlineSubmissions));
7346
+ store.dispatch(addFormSubmissionAttachments(offlineAttachments));
7347
+ const promise = this.enqueueRequest({
7348
+ description: "Bulk add form submissions",
7349
+ method: HttpMethod.POST,
7350
+ url: `/forms/revisions/${form_revision}/bulk-respond/`,
7351
+ payload: {
7352
+ form_data: values,
7353
+ submitted_at: submittedAt,
7354
+ submissions: submissionsPayload,
7355
+ attachments: attachmentsPayload,
7356
+ files: Object.values(filesRecord)
7357
+ },
7358
+ blockers: componentOfflineIds,
7359
+ blocks: submissionOfflineIds
7360
+ });
7361
+ promise.then(({ submissions, attachments, presigned_urls }) => {
7362
+ store.dispatch(updateFormSubmissions(submissions));
7363
+ store.dispatch(updateFormSubmissionAttachments(attachments));
7364
+ for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
7365
+ const file = filesRecord[sha1];
7366
+ if (!file)
7367
+ continue;
7368
+ void this.enqueueRequest({
7369
+ url: presigned_url.url,
7370
+ description: "Upload file",
7371
+ method: HttpMethod.POST,
7372
+ isExternalUrl: true,
7373
+ isAuthNeeded: false,
7374
+ attachmentHash: sha1,
7375
+ blockers: [`s3-${file.sha1}.${file.extension}`],
7376
+ blocks: [sha1],
7377
+ s3url: presigned_url
7378
+ });
7379
+ }
7380
+ }).catch(() => {
7381
+ store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7382
+ store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
7383
+ });
7384
+ return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
7385
+ }
7386
+ update(submission) {
7387
+ const { store } = this.client;
7388
+ const { values, files } = separateFilesFromValues(submission.values);
7123
7389
  const attachFilesPromises = this.getAttachFilesPromises(files, submission);
7124
- const fullResult = {
7125
- ...payloadWithoutFiles,
7126
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
7390
+ const offlineSubmission = {
7391
+ ...submission,
7392
+ values
7127
7393
  };
7128
- store.dispatch(updateOrCreateUserFormSubmission(fullResult));
7394
+ const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
7395
+ store.dispatch(updateFormSubmission(offlineSubmission));
7129
7396
  const promise = this.enqueueRequest({
7130
7397
  description: "Patch form submission",
7131
7398
  method: HttpMethod.PATCH,
7132
7399
  url: `/forms/submissions/${submission.offline_id}/`,
7133
- payload: fullResult,
7134
- blockers: [fullResult.issue, fullResult.component, fullResult.component_stage].filter(
7400
+ payload: offlineSubmission,
7401
+ blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
7135
7402
  (x) => x !== void 0
7136
7403
  ),
7137
- blocks: [fullResult.offline_id]
7404
+ blocks: [offlineSubmission.offline_id]
7138
7405
  });
7139
- return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7406
+ promise.then((createdSubmission) => {
7407
+ store.dispatch(setFormSubmission(createdSubmission));
7408
+ }).catch(() => {
7409
+ store.dispatch(setFormSubmission(submissionToBeUpdated));
7410
+ });
7411
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
7140
7412
  }
7141
7413
  async delete(submissionId) {
7142
7414
  const { store } = this.client;
7143
7415
  const state = store.getState();
7144
- const submission = state.userFormReducer.submissions[submissionId];
7145
- store.dispatch(deleteUserFormSubmission(submissionId));
7416
+ const submission = state.formSubmissionReducer.formSubmissions[submissionId];
7417
+ store.dispatch(deleteFormSubmission(submissionId));
7146
7418
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7147
7419
  try {
7148
7420
  return await this.enqueueRequest({
@@ -7153,10 +7425,8 @@ class UserFormSubmissionService extends BaseApiService {
7153
7425
  blocks: []
7154
7426
  });
7155
7427
  } catch (e) {
7156
- if (submission) {
7157
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
7158
- store.dispatch(updateOrCreateUserFormSubmission(submission));
7159
- }
7428
+ store.dispatch(addActiveProjectFormSubmissionsCount(1));
7429
+ store.dispatch(addFormSubmission(submission));
7160
7430
  throw e;
7161
7431
  }
7162
7432
  }
@@ -7170,7 +7440,7 @@ class UserFormSubmissionService extends BaseApiService {
7170
7440
  blockers: [],
7171
7441
  blocks: []
7172
7442
  });
7173
- store.dispatch(setUserFormSubmissions(submissions));
7443
+ store.dispatch(setFormSubmissions(submissions));
7174
7444
  const attachments = await this.enqueueRequest({
7175
7445
  description: "Fetch form attachments",
7176
7446
  method: HttpMethod.GET,
@@ -7178,7 +7448,7 @@ class UserFormSubmissionService extends BaseApiService {
7178
7448
  blockers: [],
7179
7449
  blocks: []
7180
7450
  });
7181
- store.dispatch(setUserFormSubmissionAttachments(attachments));
7451
+ store.dispatch(setFormSubmissionAttachments(attachments));
7182
7452
  }
7183
7453
  }
7184
7454
  class WorkspaceService extends BaseApiService {
@@ -14036,7 +14306,7 @@ const initialFormValues = (fields, values) => {
14036
14306
  };
14037
14307
  const useAttachImagesToFormRevisionFields = (revision) => {
14038
14308
  const { sdk } = useSDK();
14039
- const attachments = useAppSelector(selectRevisionAttachments((revision == null ? void 0 : revision.offline_id) ?? ""));
14309
+ const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
14040
14310
  return useMemo(() => {
14041
14311
  if (!revision || !attachments)
14042
14312
  return revision;
@@ -14133,7 +14403,7 @@ const FormSubmissionViewer = memo(
14133
14403
  return formRevisionToSchema(revisionWithImages, { readonly: true });
14134
14404
  }, [revisionWithImages]);
14135
14405
  const submissionValuesWithAttachments = useMemo(() => {
14136
- const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
14406
+ const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
14137
14407
  const downloadedAttachments = {};
14138
14408
  for (const attachment of attachments) {
14139
14409
  const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
@@ -14183,8 +14453,8 @@ const FormBrowser = memo(
14183
14453
  }
14184
14454
  return ret;
14185
14455
  }, [filter, maxResults, ownerFilter]);
14186
- const userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? [];
14187
- const userFormMapping = useAppSelector(selectUserFormMapping);
14456
+ const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
14457
+ const userFormMapping = useAppSelector(selectFormMapping);
14188
14458
  const attachableUserForms = userForms.filter((form) => !form.component_type);
14189
14459
  const attachableUserFormMapping = Object.values(userFormMapping).filter(
14190
14460
  (form) => !form.component_type
@@ -14217,7 +14487,7 @@ const FormBrowser = memo(
14217
14487
  const handleChange = useCallback((e) => {
14218
14488
  setFilter(e.currentTarget.value);
14219
14489
  }, []);
14220
- const numberOfForms = useAppSelector(selectNumberOfGeneralUserForms) || 0;
14490
+ const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
14221
14491
  const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
14222
14492
  const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
14223
14493
  return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
@@ -14311,16 +14581,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
14311
14581
  const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
14312
14582
  const currentUser = useAppSelector(selectCurrentUser);
14313
14583
  const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
14314
- const dateToUse = getCreatedAtOrSubmittedAtDate(submission);
14315
- const formattedDateTime = isToday(dateToUse) ? dateToUse.toLocaleTimeString([], {
14316
- hour: "2-digit",
14317
- minute: "2-digit"
14318
- }) : getLocalDateString(dateToUse);
14584
+ const dateToUse = submission.submitted_at;
14585
+ const formattedDateTime = getLocalDateString(dateToUse);
14319
14586
  const revision = useAppSelector(selectFormRevision(submission.form_revision));
14320
14587
  if (!revision) {
14321
14588
  throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
14322
14589
  }
14323
- const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevision(revision.form))) == null ? void 0 : _a2.revision;
14590
+ const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
14324
14591
  const creatorProfileSrc = useFileSrc({
14325
14592
  file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
14326
14593
  fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
@@ -14351,10 +14618,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
14351
14618
  return row;
14352
14619
  });
14353
14620
  FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
14354
- const getCreatedAtOrSubmittedAtDate = (submission) => {
14355
- const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
14356
- return new Date(date);
14357
- };
14358
14621
  const FormSubmissionBrowser = memo((props) => {
14359
14622
  const {
14360
14623
  formId: formId2,
@@ -14368,10 +14631,10 @@ const FormSubmissionBrowser = memo((props) => {
14368
14631
  if (!!formId2 === !!propSubmissions) {
14369
14632
  throw new Error("Either formId or submissions must be provided, but not both.");
14370
14633
  }
14371
- const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId2));
14634
+ const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
14372
14635
  const sortedSubmissions = useMemo(
14373
14636
  () => submissions == null ? void 0 : submissions.sort((a, b) => {
14374
- return getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime();
14637
+ return a.submitted_at.localeCompare(b.submitted_at);
14375
14638
  }),
14376
14639
  [submissions]
14377
14640
  );
@@ -15689,6 +15952,7 @@ export {
15689
15952
  VerificationCodeType,
15690
15953
  WorkspaceService,
15691
15954
  YELLOW,
15955
+ _selectLatestFormRevision,
15692
15956
  _setLatestRetryTime,
15693
15957
  acceptProjectInvite,
15694
15958
  addActiveProjectFormSubmissionsCount,
@@ -15706,6 +15970,16 @@ export {
15706
15970
  addDocuments,
15707
15971
  addEmailDomain,
15708
15972
  addFavouriteProjectId,
15973
+ addForm,
15974
+ addFormRevision,
15975
+ addFormRevisionAttachment,
15976
+ addFormRevisionAttachments,
15977
+ addFormRevisions,
15978
+ addFormSubmission,
15979
+ addFormSubmissionAttachment,
15980
+ addFormSubmissionAttachments,
15981
+ addFormSubmissions,
15982
+ addForms,
15709
15983
  addIssue,
15710
15984
  addIssueAttachment,
15711
15985
  addIssueAttachments,
@@ -15726,13 +16000,6 @@ export {
15726
16000
  addStageCompletions,
15727
16001
  addStages,
15728
16002
  addToRecentIssues,
15729
- addUserForm,
15730
- addUserFormRevision,
15731
- addUserFormRevisionAttachment,
15732
- addUserFormRevisions,
15733
- addUserFormSubmissionAttachment,
15734
- addUserFormSubmissions,
15735
- addUserForms,
15736
16003
  addUsers,
15737
16004
  addWorkspace,
15738
16005
  areArraysEqual,
@@ -15753,6 +16020,7 @@ export {
15753
16020
  componentStageSlice,
15754
16021
  componentTypeReducer,
15755
16022
  componentTypeSlice,
16023
+ constructUploadedFilePayloads,
15756
16024
  coordinatesAreEqual,
15757
16025
  coordinatesToLiteral,
15758
16026
  coordinatesToPointGeometry,
@@ -15763,12 +16031,16 @@ export {
15763
16031
  defaultBadgeColor,
15764
16032
  defaultStore,
15765
16033
  deleteComponentType,
16034
+ deleteForm,
16035
+ deleteFormRevision,
16036
+ deleteFormRevisionAttachment,
16037
+ deleteFormRevisionAttachments,
16038
+ deleteFormRevisions,
16039
+ deleteFormSubmission,
16040
+ deleteFormSubmissionAttachment,
16041
+ deleteFormSubmissionAttachments,
16042
+ deleteFormSubmissions,
15766
16043
  deleteProject,
15767
- deleteUserForm,
15768
- deleteUserFormRevision,
15769
- deleteUserFormRevisions,
15770
- deleteUserFormSubmission,
15771
- deleteUserFormSubmissions,
15772
16044
  dequeue,
15773
16045
  deserialize,
15774
16046
  deserializeField,
@@ -15797,7 +16069,13 @@ export {
15797
16069
  fileSlice,
15798
16070
  fileToBlob,
15799
16071
  flipCoordinates,
16072
+ formReducer,
16073
+ formRevisionReducer,
15800
16074
  formRevisionToSchema,
16075
+ formRevisionsSlice,
16076
+ formSlice,
16077
+ formSubmissionReducer,
16078
+ formSubmissionSlice,
15801
16079
  index as forms,
15802
16080
  fullComponentMarkerSize,
15803
16081
  generateBadgeColors,
@@ -15925,6 +16203,8 @@ export {
15925
16203
  selectAttachmentsOfComponentTypeByType,
15926
16204
  selectAttachmentsOfDocument,
15927
16205
  selectAttachmentsOfDocumentByType,
16206
+ selectAttachmentsOfFormRevision,
16207
+ selectAttachmentsOfFormSubmission,
15928
16208
  selectAttachmentsOfIssue,
15929
16209
  selectAttachmentsOfIssueByType,
15930
16210
  selectAttachmentsOfProject,
@@ -15942,11 +16222,9 @@ export {
15942
16222
  selectComponent,
15943
16223
  selectComponentAttachment,
15944
16224
  selectComponentAttachmentMapping,
15945
- selectComponentSubmissionMapping,
15946
16225
  selectComponentType,
15947
16226
  selectComponentTypeAttachment,
15948
16227
  selectComponentTypeAttachmentMapping,
15949
- selectComponentTypeForm,
15950
16228
  selectComponentTypeFromComponent,
15951
16229
  selectComponentTypeFromComponents,
15952
16230
  selectComponentTypeStagesMapping,
@@ -15976,8 +16254,24 @@ export {
15976
16254
  selectExpandedSections,
15977
16255
  selectFavouriteProjects,
15978
16256
  selectFileAttachmentsOfIssue,
15979
- selectFilteredUserForms,
16257
+ selectFilteredForms,
16258
+ selectForm,
16259
+ selectFormMapping,
16260
+ selectFormOfComponentType,
15980
16261
  selectFormRevision,
16262
+ selectFormRevisionMapping,
16263
+ selectFormRevisions,
16264
+ selectFormRevisionsOfForm,
16265
+ selectFormSubmission,
16266
+ selectFormSubmissionAttachmentsMapping,
16267
+ selectFormSubmissions,
16268
+ selectFormSubmissionsByComponents,
16269
+ selectFormSubmissionsMapping,
16270
+ selectFormSubmissionsOfComponent,
16271
+ selectFormSubmissionsOfForm,
16272
+ selectFormSubmissionsOfIssue,
16273
+ selectFormsCount,
16274
+ selectGeneralFormCount,
15981
16275
  selectHiddenCategoryCount,
15982
16276
  selectHiddenComponentTypeIds,
15983
16277
  selectIsFetchingInitialData,
@@ -15992,10 +16286,10 @@ export {
15992
16286
  selectIssueUpdateMapping,
15993
16287
  selectIssueUpdatesOfIssue,
15994
16288
  selectIssues,
15995
- selectLatestFormRevision,
16289
+ selectLatestFormRevisionByForm,
16290
+ selectLatestFormRevisionOfForm,
16291
+ selectLatestFormRevisionsOfComponentTypes,
15996
16292
  selectLatestRetryTime,
15997
- selectLatestRevisionByFormId,
15998
- selectLatestRevisionsFromComponentTypeIds,
15999
16293
  selectLicense,
16000
16294
  selectLicenseForProject,
16001
16295
  selectLicenses,
@@ -16004,8 +16298,6 @@ export {
16004
16298
  selectMapStyle,
16005
16299
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
16006
16300
  selectNumberOfComponentsOfComponentType,
16007
- selectNumberOfGeneralUserForms,
16008
- selectNumberOfUserForms,
16009
16301
  selectOrganization,
16010
16302
  selectOrganizationAccess,
16011
16303
  selectOrganizationAccessForUser,
@@ -16033,8 +16325,6 @@ export {
16033
16325
  selectRecentIssuesAsSearchResults,
16034
16326
  selectRecentProjects,
16035
16327
  selectRehydrated,
16036
- selectRevisionAttachments,
16037
- selectRevisionsForForm,
16038
16328
  selectRootDocuments,
16039
16329
  selectShowTooltips,
16040
16330
  selectSortedEmailDomains,
@@ -16049,16 +16339,10 @@ export {
16049
16339
  selectStagesFromComponentType,
16050
16340
  selectStagesFromComponentTypeIds,
16051
16341
  selectStagesFromStageIds,
16052
- selectSubmissionAttachments,
16053
- selectSubmissionsForComponent,
16054
- selectSubmissionsForForm,
16055
- selectSubmissionsForIssue,
16056
16342
  selectUploadUrl,
16057
16343
  selectUsedColors,
16058
16344
  selectUser,
16059
- selectUserForm,
16060
- selectUserFormMapping,
16061
- selectUserFormSubmission,
16345
+ selectUserFormRevisionAttachmentsMapping,
16062
16346
  selectUsersAsMapping,
16063
16347
  selectVisibleStatuses,
16064
16348
  selectVisibleUserIds,
@@ -16085,6 +16369,13 @@ export {
16085
16369
  setEnableClustering,
16086
16370
  setEnableDuplicateIssues,
16087
16371
  setEnablePlacementMode,
16372
+ setFormRevision,
16373
+ setFormRevisionAttachments,
16374
+ setFormRevisions,
16375
+ setFormSubmission,
16376
+ setFormSubmissionAttachments,
16377
+ setFormSubmissions,
16378
+ setForms,
16088
16379
  setIsFetchingInitialData,
16089
16380
  setIsImportingProjectFile,
16090
16381
  setIsLoading,
@@ -16109,9 +16400,6 @@ export {
16109
16400
  setTokens,
16110
16401
  setTourStep,
16111
16402
  setUploadUrl,
16112
- setUserFormRevisionAttachments,
16113
- setUserFormSubmissionAttachments,
16114
- setUserFormSubmissions,
16115
16403
  setUsers,
16116
16404
  setVisibleStatuses,
16117
16405
  setVisibleUserIds,
@@ -16136,11 +16424,13 @@ export {
16136
16424
  updateComponentTypeAttachment,
16137
16425
  updateDocumentAttachment,
16138
16426
  updateDocuments,
16427
+ updateFormSubmission,
16428
+ updateFormSubmissionAttachments,
16429
+ updateFormSubmissions,
16139
16430
  updateIssue,
16140
16431
  updateIssueAttachment,
16141
16432
  updateLicense,
16142
16433
  updateOrCreateProject,
16143
- updateOrCreateUserFormSubmission,
16144
16434
  updateOrganizationAccess,
16145
16435
  updateProjectAccess,
16146
16436
  updateProjectAttachment,
@@ -16154,8 +16444,6 @@ export {
16154
16444
  useFormikInput,
16155
16445
  useMemoCompare,
16156
16446
  useSDK,
16157
- userFormReducer,
16158
- userFormSlice,
16159
16447
  userReducer,
16160
16448
  userSlice,
16161
16449
  valueIsFile,