@overmap-ai/core 1.0.51-add-submitted-at-to-form-revisions.1 → 1.0.51-bulk-form-submission.1

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,231 @@ 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) {
3473
- var _a2;
3474
- if (!revision) {
3475
- if (!formId2) {
3476
- throw new Error("If revision is null, formId is required.");
3477
- }
3478
- const currentLatestRevision = getLatestRevisionFromCache(formId2);
3479
- if (currentLatestRevision)
3480
- return;
3481
- LATEST_REVISION_CACHE[formId2] = null;
3482
- return;
3483
- }
3484
- if (revision.revision === "Pending") {
3485
- if (preferPending) {
3486
- LATEST_REVISION_CACHE[revision.form] = revision;
3487
- }
3488
- return;
3489
- }
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;
3484
+ const formRevisionSortFn = (formRevisionA, formRevisionB) => {
3485
+ const revisionA = formRevisionA.revision;
3486
+ const revisionB = formRevisionB.revision;
3487
+ if (revisionA === "Pending" && revisionB === "Pending") {
3488
+ return formRevisionA.submitted_at < formRevisionB.submitted_at ? 1 : -1;
3489
+ } else if (revisionA === "Pending") {
3490
+ return -1;
3491
+ } else if (revisionB === "Pending") {
3492
+ return 1;
3493
+ } else {
3494
+ return revisionA < revisionB ? 1 : -1;
3493
3495
  }
3494
- }
3495
- function getLatestRevisionFromCache(formId2) {
3496
- return LATEST_REVISION_CACHE[formId2];
3497
- }
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)),
3496
+ };
3497
+ const initialState$5 = {
3498
+ formRevisions: {},
3499
+ attachments: {}
3500
+ };
3501
+ const formRevisionsSlice = createSlice({
3502
+ name: "formRevisions",
3503
+ initialState: initialState$5,
3504
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
3509
3505
  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;
3506
+ // revision related actions
3507
+ setFormRevision: (state, action) => {
3508
+ state.formRevisions[action.payload.offline_id] = action.payload;
3518
3509
  },
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
- });
3529
- },
3530
- addUserFormRevision: (state, action) => {
3531
- state.revisions[action.payload.offline_id] = action.payload;
3532
- considerCachingRevision(action.payload);
3510
+ setFormRevisions: (state, action) => {
3511
+ state.formRevisions = {};
3512
+ for (const revision of action.payload) {
3513
+ state.formRevisions[revision.offline_id] = revision;
3514
+ }
3533
3515
  },
3534
- deleteUserFormRevision: (state, action) => {
3535
- delete state.revisions[action.payload];
3536
- delete LATEST_REVISION_CACHE[action.payload];
3516
+ addFormRevision: (state, action) => {
3517
+ if (state.formRevisions[action.payload.offline_id] !== void 0) {
3518
+ throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
3519
+ }
3520
+ state.formRevisions[action.payload.offline_id] = action.payload;
3537
3521
  },
3538
- deleteUserFormRevisions: (state, action) => {
3522
+ addFormRevisions: (state, action) => {
3539
3523
  for (const userFormRevision of action.payload) {
3540
- delete state.revisions[userFormRevision.offline_id];
3541
- delete LATEST_REVISION_CACHE[userFormRevision.offline_id];
3524
+ if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
3525
+ throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
3526
+ }
3542
3527
  }
3543
- },
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];
3528
+ for (const userFormRevision of action.payload) {
3529
+ state.formRevisions[userFormRevision.offline_id] = userFormRevision;
3554
3530
  }
3555
3531
  },
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];
3532
+ // UserFormRevisions do not get updated
3533
+ deleteFormRevision: (state, action) => {
3534
+ if (state.formRevisions[action.payload] === void 0) {
3535
+ throw new Error(`Revision with offline_id ${action.payload} does not exist`);
3563
3536
  }
3537
+ delete state.formRevisions[action.payload];
3564
3538
  },
3565
- setUserFormSubmissionAttachments: (state, action) => {
3566
- state.submissionAttachments = {};
3567
- 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];
3539
+ deleteFormRevisions: (state, action) => {
3540
+ for (const offlineId of action.payload) {
3541
+ if (state.formRevisions[offlineId] === void 0) {
3542
+ throw new Error(`Revision with offline_id ${offlineId} does not exist`);
3574
3543
  }
3575
3544
  }
3545
+ for (const offlineId of action.payload) {
3546
+ delete state.formRevisions[offlineId];
3547
+ }
3576
3548
  },
3577
- setUserFormRevisionAttachments: (state, action) => {
3578
- state.revisionAttachments = {};
3549
+ // attachment related actions
3550
+ setFormRevisionAttachments: (state, action) => {
3551
+ state.attachments = {};
3579
3552
  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];
3586
- }
3553
+ state.attachments[attachment.offline_id] = attachment;
3587
3554
  }
3588
3555
  },
3589
- deleteUserFormSubmission: (state, action) => {
3590
- delete state.submissions[action.payload];
3556
+ addFormRevisionAttachment: (state, action) => {
3557
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3558
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3559
+ }
3560
+ state.attachments[action.payload.offline_id] = action.payload;
3591
3561
  },
3592
- deleteUserFormSubmissions: (state, action) => {
3593
- for (const userFormSubmission of action.payload) {
3594
- delete state.submissions[userFormSubmission.offline_id];
3562
+ addFormRevisionAttachments: (state, action) => {
3563
+ for (const attachment of action.payload) {
3564
+ if (state.attachments[attachment.offline_id] !== void 0) {
3565
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3566
+ }
3567
+ }
3568
+ for (const attachment of action.payload) {
3569
+ state.attachments[attachment.offline_id] = attachment;
3595
3570
  }
3596
3571
  },
3597
- addUserFormSubmissions: (state, action) => {
3598
- for (const submission of action.payload) {
3599
- state.submissions[submission.offline_id] = submission;
3572
+ deleteFormRevisionAttachment: (state, action) => {
3573
+ if (state.attachments[action.payload] === void 0) {
3574
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3600
3575
  }
3576
+ delete state.attachments[action.payload];
3601
3577
  },
3602
- setUserFormSubmissions: (state, action) => {
3603
- state.submissions = {};
3604
- action.payload.forEach((submission) => {
3605
- state.submissions[submission.offline_id] = submission;
3578
+ deleteFormRevisionAttachments: (state, action) => {
3579
+ for (const offlineId of action.payload) {
3580
+ if (state.attachments[offlineId] === void 0) {
3581
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3582
+ }
3583
+ }
3584
+ for (const offlineId of action.payload) {
3585
+ delete state.attachments[offlineId];
3586
+ }
3587
+ }
3588
+ }
3589
+ });
3590
+ const {
3591
+ setFormRevision,
3592
+ setFormRevisions,
3593
+ addFormRevision,
3594
+ addFormRevisions,
3595
+ deleteFormRevision,
3596
+ deleteFormRevisions,
3597
+ setFormRevisionAttachments,
3598
+ addFormRevisionAttachment,
3599
+ addFormRevisionAttachments,
3600
+ deleteFormRevisionAttachment,
3601
+ deleteFormRevisionAttachments
3602
+ } = formRevisionsSlice.actions;
3603
+ const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
3604
+ const selectFormRevisions = createSelector(
3605
+ [selectFormRevisionMapping],
3606
+ (formRevisions) => Object.values(formRevisions)
3607
+ );
3608
+ const selectFormRevision = (formRevisionId) => (state) => {
3609
+ return state.formRevisionReducer.formRevisions[formRevisionId];
3610
+ };
3611
+ const _selectLatestFormRevision = (formRevisions, formId2) => {
3612
+ let ret = null;
3613
+ for (const candidate of Object.values(formRevisions)) {
3614
+ if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3615
+ ret = candidate;
3616
+ }
3617
+ }
3618
+ if (!ret) {
3619
+ throw new Error("No form revision found for form " + formId2);
3620
+ }
3621
+ return ret;
3622
+ };
3623
+ const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
3624
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3625
+ return revisions.filter((revision) => revision.form === formId2).sort(formRevisionSortFn).pop();
3626
+ })
3627
+ );
3628
+ const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
3629
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3630
+ return revisions.filter((revision) => {
3631
+ return revision.form === formId2;
3632
+ });
3633
+ })
3634
+ );
3635
+ const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
3636
+ createSelector(
3637
+ [
3638
+ (state) => state.formReducer.forms,
3639
+ selectFormRevisionMapping,
3640
+ (_state, componentTypeIds) => componentTypeIds
3641
+ ],
3642
+ (userForms, revisions, componentTypeIds) => {
3643
+ const componentTypeIdsSet = new Set(componentTypeIds);
3644
+ const formsOfComponentTypes = {};
3645
+ const ret = {};
3646
+ for (const form of Object.values(userForms)) {
3647
+ if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3648
+ formsOfComponentTypes[form.component_type] = form;
3649
+ }
3650
+ }
3651
+ for (const revision of Object.values(revisions)) {
3652
+ const form = formsOfComponentTypes[revision.form];
3653
+ if (!form || !form.component_type || !ret[form.component_type] || formRevisionSortFn(ret[form.component_type], revision) < 0)
3654
+ continue;
3655
+ ret[form.component_type] = revision;
3656
+ }
3657
+ return ret;
3658
+ }
3659
+ )
3660
+ );
3661
+ const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
3662
+ const latestRevisions = {};
3663
+ for (const revision of Object.values(revisions)) {
3664
+ const formId2 = revision.form;
3665
+ const currentLatestRevision = latestRevisions[formId2];
3666
+ if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3667
+ latestRevisions[formId2] = revision;
3668
+ }
3669
+ }
3670
+ return latestRevisions;
3671
+ });
3672
+ const selectUserFormRevisionAttachmentsMapping = (state) => {
3673
+ return state.formRevisionReducer.attachments;
3674
+ };
3675
+ const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
3676
+ createSelector(
3677
+ [selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
3678
+ (attachments, revisionId) => {
3679
+ return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
3680
+ }
3681
+ )
3682
+ );
3683
+ const formRevisionReducer = formRevisionsSlice.reducer;
3684
+ const initialState$4 = {
3685
+ forms: {}
3686
+ };
3687
+ const formSlice = createSlice({
3688
+ name: "forms",
3689
+ initialState: initialState$4,
3690
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3691
+ reducers: {
3692
+ setForms: (state, action) => {
3693
+ state.forms = {};
3694
+ action.payload.forEach((userForm) => {
3695
+ state.forms[userForm.offline_id] = userForm;
3606
3696
  });
3607
3697
  },
3698
+ addForm: (state, action) => {
3699
+ state.forms[action.payload.offline_id] = action.payload;
3700
+ },
3701
+ addForms: (state, action) => {
3702
+ for (const userForm of action.payload) {
3703
+ state.forms[userForm.offline_id] = userForm;
3704
+ }
3705
+ },
3608
3706
  favoriteForm: (state, action) => {
3609
3707
  const { formId: formId2 } = action.payload;
3610
- const form = state.userForms[formId2];
3708
+ const form = state.forms[formId2];
3611
3709
  if (!form) {
3612
3710
  throw new Error("No form exists with the id " + formId2);
3613
3711
  }
@@ -3615,48 +3713,23 @@ const userFormSlice = createSlice({
3615
3713
  },
3616
3714
  unfavoriteForm: (state, action) => {
3617
3715
  const { formId: formId2 } = action.payload;
3618
- const form = state.userForms[formId2];
3716
+ const form = state.forms[formId2];
3619
3717
  if (!form) {
3620
3718
  throw new Error("No form exists with the id " + formId2);
3621
3719
  }
3622
3720
  form.favorite = false;
3623
3721
  },
3624
- deleteUserForm: (state, action) => {
3625
- delete state.userForms[action.payload];
3722
+ deleteForm: (state, action) => {
3723
+ delete state.forms[action.payload];
3626
3724
  }
3627
3725
  }
3628
3726
  });
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(
3727
+ const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
3728
+ const selectFilteredForms = restructureCreateSelectorWithArgs(
3656
3729
  createSelector(
3657
3730
  [
3658
- (state) => state.userFormReducer.userForms,
3659
- (state) => state.userFormReducer.revisions,
3731
+ (state) => state.formReducer.forms,
3732
+ (state) => state.formRevisionReducer.formRevisions,
3660
3733
  (_state, search) => search
3661
3734
  ],
3662
3735
  (userForms, revisions, search) => {
@@ -3690,63 +3763,188 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3690
3763
  { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3691
3764
  )
3692
3765
  );
3693
- const selectFormRevision = (revisionId) => (state) => {
3694
- return state.userFormReducer.revisions[revisionId];
3766
+ const selectForm = (formId2) => (state) => {
3767
+ return state.formReducer.forms[formId2];
3695
3768
  };
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;
3769
+ const selectFormMapping = (state) => {
3770
+ return state.formReducer.forms;
3707
3771
  };
3708
- const selectLatestFormRevision = restructureCreateSelectorWithArgs(
3772
+ const selectFormOfComponentType = restructureCreateSelectorWithArgs(
3709
3773
  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);
3774
+ [selectFormMapping, (_state, componentTypeId) => componentTypeId],
3775
+ (userForms, componentTypeId) => {
3776
+ return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3716
3777
  }
3717
3778
  )
3718
3779
  );
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
- })
3780
+ const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
3781
+ return Object.keys(userForms).length;
3782
+ });
3783
+ const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
3784
+ return Object.values(userForms).filter((form) => !form.component_type).length;
3785
+ });
3786
+ const formReducer = formSlice.reducer;
3787
+ const initialState$3 = {
3788
+ formSubmissions: {},
3789
+ attachments: {}
3790
+ };
3791
+ const formSubmissionSlice = createSlice({
3792
+ name: "formSubmissions",
3793
+ initialState: initialState$3,
3794
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$3)),
3795
+ reducers: {
3796
+ setFormSubmission: (state, action) => {
3797
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3798
+ },
3799
+ setFormSubmissions: (state, action) => {
3800
+ state.formSubmissions = {};
3801
+ for (const submission of action.payload) {
3802
+ state.formSubmissions[submission.offline_id] = submission;
3803
+ }
3804
+ },
3805
+ addFormSubmission: (state, action) => {
3806
+ if (action.payload.offline_id in state.formSubmissions) {
3807
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
3808
+ }
3809
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3810
+ },
3811
+ addFormSubmissions: (state, action) => {
3812
+ for (const submission of action.payload) {
3813
+ if (state.formSubmissions[submission.offline_id] !== void 0) {
3814
+ throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
3815
+ }
3816
+ }
3817
+ for (const submission of action.payload) {
3818
+ state.formSubmissions[submission.offline_id] = submission;
3819
+ }
3820
+ },
3821
+ updateFormSubmission: (state, action) => {
3822
+ if (state.formSubmissions[action.payload.offline_id] === void 0) {
3823
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
3824
+ }
3825
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3826
+ },
3827
+ updateFormSubmissions: (state, action) => {
3828
+ for (const submission of action.payload) {
3829
+ if (state.formSubmissions[submission.offline_id] === void 0) {
3830
+ throw new Error(`Submission with offline_id ${submission.offline_id} does not exist`);
3831
+ }
3832
+ }
3833
+ for (const submission of action.payload) {
3834
+ state.formSubmissions[submission.offline_id] = submission;
3835
+ }
3836
+ },
3837
+ deleteFormSubmission: (state, action) => {
3838
+ if (state.formSubmissions[action.payload] === void 0) {
3839
+ throw new Error(`Submission with offline_id ${action.payload} does not exist`);
3840
+ }
3841
+ delete state.formSubmissions[action.payload];
3842
+ },
3843
+ deleteFormSubmissions: (state, action) => {
3844
+ for (const offlineId of action.payload) {
3845
+ if (state.formSubmissions[offlineId] === void 0) {
3846
+ throw new Error(`Submission with offline_id ${offlineId} does not exist`);
3847
+ }
3848
+ delete state.formSubmissions[offlineId];
3849
+ }
3850
+ for (const offlineId of action.payload) {
3851
+ delete state.formSubmissions[offlineId];
3852
+ }
3853
+ },
3854
+ // Attachments
3855
+ addFormSubmissionAttachment: (state, action) => {
3856
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3857
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3858
+ }
3859
+ state.attachments[action.payload.offline_id] = action.payload;
3860
+ },
3861
+ addFormSubmissionAttachments: (state, action) => {
3862
+ for (const attachment of action.payload) {
3863
+ if (state.attachments[attachment.offline_id] !== void 0) {
3864
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3865
+ }
3866
+ }
3867
+ for (const attachment of action.payload) {
3868
+ state.attachments[attachment.offline_id] = attachment;
3869
+ }
3870
+ },
3871
+ // We only need a multi set for attachments because they are not updated, only added and deleted
3872
+ setFormSubmissionAttachments: (state, action) => {
3873
+ state.attachments = {};
3874
+ for (const attachment of action.payload) {
3875
+ state.attachments[attachment.offline_id] = attachment;
3876
+ }
3877
+ },
3878
+ updateFormSubmissionAttachments: (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} does not exist`);
3882
+ }
3883
+ }
3884
+ for (const attachment of action.payload) {
3885
+ state.attachments[attachment.offline_id] = attachment;
3886
+ }
3887
+ },
3888
+ // The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
3889
+ // Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
3890
+ deleteFormSubmissionAttachment: (state, action) => {
3891
+ if (state.attachments[action.payload] === void 0) {
3892
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3893
+ }
3894
+ delete state.attachments[action.payload];
3895
+ },
3896
+ deleteFormSubmissionAttachments: (state, action) => {
3897
+ for (const offlineId of action.payload) {
3898
+ if (state.attachments[offlineId] === void 0) {
3899
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3900
+ }
3901
+ delete state.attachments[offlineId];
3902
+ }
3903
+ }
3904
+ }
3905
+ });
3906
+ const {
3907
+ setFormSubmission,
3908
+ setFormSubmissions,
3909
+ addFormSubmission,
3910
+ addFormSubmissions,
3911
+ updateFormSubmission,
3912
+ updateFormSubmissions,
3913
+ deleteFormSubmission,
3914
+ deleteFormSubmissions,
3915
+ addFormSubmissionAttachment,
3916
+ addFormSubmissionAttachments,
3917
+ setFormSubmissionAttachments,
3918
+ updateFormSubmissionAttachments,
3919
+ deleteFormSubmissionAttachment,
3920
+ deleteFormSubmissionAttachments
3921
+ } = formSubmissionSlice.actions;
3922
+ const selectFormSubmissionsMapping = (state) => {
3923
+ return state.formSubmissionReducer.formSubmissions;
3924
+ };
3925
+ const selectFormSubmissions = createSelector(
3926
+ [selectFormSubmissionsMapping],
3927
+ (submissions) => {
3928
+ return Object.values(submissions);
3929
+ }
3735
3930
  );
3736
- const selectSubmissionsForForm = restructureCreateSelectorWithArgs(
3931
+ const selectFormSubmission = (submissionId) => (state) => {
3932
+ return state.formSubmissionReducer.formSubmissions[submissionId];
3933
+ };
3934
+ const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
3737
3935
  createSelector(
3738
- [selectSubmissions, selectRevisionMapping, (_state, formId2) => formId2],
3936
+ [selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
3739
3937
  (submissions, revisionMapping, formId2) => {
3740
- return Object.values(submissions).filter((submission) => {
3938
+ return submissions.filter((submission) => {
3741
3939
  const revision = revisionMapping[submission.form_revision];
3742
3940
  return (revision == null ? void 0 : revision.form) === formId2;
3743
3941
  });
3744
3942
  }
3745
3943
  )
3746
3944
  );
3747
- const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3945
+ const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
3748
3946
  createSelector(
3749
- [(state) => state.userFormReducer.submissions, (_state, issueId) => issueId],
3947
+ [selectFormSubmissions, (_state, issueId) => issueId],
3750
3948
  (submissions, issueId) => {
3751
3949
  return Object.values(submissions).filter((submission) => {
3752
3950
  return submission.issue === issueId;
@@ -3754,9 +3952,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3754
3952
  }
3755
3953
  )
3756
3954
  );
3757
- const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3955
+ const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
3758
3956
  createSelector(
3759
- [selectSubmissions, (_state, componentId) => componentId],
3957
+ [selectFormSubmissions, (_state, componentId) => componentId],
3760
3958
  (submissions, componentId) => {
3761
3959
  return submissions.filter((submission) => {
3762
3960
  return submission.component === componentId;
@@ -3764,8 +3962,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3764
3962
  }
3765
3963
  )
3766
3964
  );
3767
- const selectComponentSubmissionMapping = createSelector(
3768
- [selectSubmissionMapping, selectComponentsMapping],
3965
+ const selectFormSubmissionsByComponents = createSelector(
3966
+ [selectFormSubmissionsMapping, selectComponentsMapping],
3769
3967
  (submissions, components) => {
3770
3968
  var _a2;
3771
3969
  const componentSubmissionMapping = {};
@@ -3781,54 +3979,18 @@ const selectComponentSubmissionMapping = createSelector(
3781
3979
  return componentSubmissionMapping;
3782
3980
  }
3783
3981
  );
3784
- const selectUserFormMapping = (state) => {
3785
- return state.userFormReducer.userForms;
3982
+ const selectFormSubmissionAttachmentsMapping = (state) => {
3983
+ return state.formSubmissionReducer.attachments;
3786
3984
  };
3787
- const selectComponentTypeForm = restructureCreateSelectorWithArgs(
3985
+ const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
3788
3986
  createSelector(
3789
- [selectUserFormMapping, (_state, componentTypeId) => componentTypeId],
3790
- (userForms, componentTypeId) => {
3791
- return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3987
+ [selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
3988
+ (attachmentsMapping, submissionId) => {
3989
+ return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
3792
3990
  }
3793
3991
  )
3794
3992
  );
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;
3811
- }
3812
- )
3813
- );
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;
3993
+ const formSubmissionReducer = formSubmissionSlice.reducer;
3832
3994
  const initialState$2 = {
3833
3995
  emailDomains: {}
3834
3996
  };
@@ -4126,7 +4288,9 @@ const overmapReducers = {
4126
4288
  projectFileReducer,
4127
4289
  rehydratedReducer,
4128
4290
  settingReducer,
4129
- userFormReducer,
4291
+ formReducer,
4292
+ formRevisionReducer,
4293
+ formSubmissionReducer,
4130
4294
  userReducer,
4131
4295
  workspaceReducer,
4132
4296
  emailDomainsReducer,
@@ -4179,9 +4343,7 @@ function handleWorkspaceRemoval(draft, action) {
4179
4343
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
4180
4344
  }
4181
4345
  }
4182
- const indexedForms = Object.values(draft.userFormReducer.userForms).filter(
4183
- (form) => form.index_workspace === workspaceId
4184
- );
4346
+ const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
4185
4347
  for (const form of indexedForms) {
4186
4348
  form.index_workspace = mainWorkspace.offline_id;
4187
4349
  }
@@ -6809,7 +6971,7 @@ class UserFormService extends BaseApiService {
6809
6971
  ...revisionAttachmentPayload,
6810
6972
  file: URL.createObjectURL(image)
6811
6973
  };
6812
- store.dispatch(addUserFormRevisionAttachment(offlinePayload));
6974
+ store.dispatch(addFormRevisionAttachment(offlinePayload));
6813
6975
  return attach;
6814
6976
  });
6815
6977
  });
@@ -6845,8 +7007,8 @@ class UserFormService extends BaseApiService {
6845
7007
  submitted_at: submittedAt
6846
7008
  };
6847
7009
  const { store } = this.client;
6848
- store.dispatch(addUserForm(retForm));
6849
- store.dispatch(addUserFormRevision(retRevision));
7010
+ store.dispatch(addForm(retForm));
7011
+ store.dispatch(addFormRevision(retRevision));
6850
7012
  const formPromise = this.enqueueRequest({
6851
7013
  description: "Create form",
6852
7014
  method: HttpMethod.POST,
@@ -6864,8 +7026,8 @@ class UserFormService extends BaseApiService {
6864
7026
  });
6865
7027
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
6866
7028
  void formPromise.catch((e) => {
6867
- store.dispatch(deleteUserForm(retForm.offline_id));
6868
- store.dispatch(deleteUserFormRevision(retRevision.offline_id));
7029
+ store.dispatch(deleteForm(retForm.offline_id));
7030
+ store.dispatch(deleteFormRevision(retRevision.offline_id));
6869
7031
  throw e;
6870
7032
  });
6871
7033
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
@@ -6908,7 +7070,7 @@ class UserFormService extends BaseApiService {
6908
7070
  form: formId2,
6909
7071
  submitted_at: (/* @__PURE__ */ new Date()).toISOString()
6910
7072
  };
6911
- store.dispatch(addUserFormRevision(fullRevision));
7073
+ store.dispatch(addFormRevision(fullRevision));
6912
7074
  const promise = this.enqueueRequest({
6913
7075
  description: "Create form revision",
6914
7076
  method: HttpMethod.PATCH,
@@ -6922,9 +7084,9 @@ class UserFormService extends BaseApiService {
6922
7084
  });
6923
7085
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
6924
7086
  void promise.then((result) => {
6925
- store.dispatch(addUserFormRevision(result));
7087
+ store.dispatch(setFormRevision(result));
6926
7088
  }).catch(() => {
6927
- store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
7089
+ store.dispatch(deleteFormRevision(fullRevision.offline_id));
6928
7090
  });
6929
7091
  const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
6930
7092
  return [fullRevision, settledPromise];
@@ -6966,19 +7128,19 @@ class UserFormService extends BaseApiService {
6966
7128
  async delete(formId2) {
6967
7129
  const { store } = this.client;
6968
7130
  const state = store.getState();
6969
- const userForm = selectUserForm(formId2)(state);
7131
+ const userForm = selectForm(formId2)(state);
6970
7132
  if (!userForm) {
6971
7133
  throw new Error("Expected userForm to exist");
6972
7134
  }
6973
- const userFormSubmissions = selectSubmissionsForForm(formId2)(state);
7135
+ const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
6974
7136
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6975
- store.dispatch(deleteUserFormSubmissions(userFormSubmissions));
7137
+ store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
6976
7138
  }
6977
- const userFormRevisions = selectRevisionsForForm(formId2)(state);
7139
+ const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
6978
7140
  if (userFormRevisions && userFormRevisions.length > 0) {
6979
- store.dispatch(deleteUserFormRevisions(userFormRevisions));
7141
+ store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
6980
7142
  }
6981
- store.dispatch(deleteUserForm(formId2));
7143
+ store.dispatch(deleteForm(formId2));
6982
7144
  try {
6983
7145
  return await this.enqueueRequest({
6984
7146
  description: "Delete form",
@@ -6988,12 +7150,12 @@ class UserFormService extends BaseApiService {
6988
7150
  blocks: []
6989
7151
  });
6990
7152
  } catch (e) {
6991
- store.dispatch(addUserForm(userForm));
7153
+ store.dispatch(addForm(userForm));
6992
7154
  if (userFormRevisions && userFormRevisions.length > 0) {
6993
- store.dispatch(addUserFormRevisions(userFormRevisions));
7155
+ store.dispatch(addFormRevisions(userFormRevisions));
6994
7156
  }
6995
7157
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6996
- store.dispatch(addUserFormSubmissions(userFormSubmissions));
7158
+ store.dispatch(addFormSubmissions(userFormSubmissions));
6997
7159
  }
6998
7160
  throw e;
6999
7161
  }
@@ -7007,16 +7169,15 @@ class UserFormService extends BaseApiService {
7007
7169
  blockers: [],
7008
7170
  blocks: []
7009
7171
  });
7010
- store.dispatch(addUserForms(Object.values(result.forms)));
7011
- store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
7012
- store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
7172
+ store.dispatch(setForms(Object.values(result.forms)));
7173
+ store.dispatch(setFormRevisions(Object.values(result.revisions)));
7174
+ store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
7013
7175
  }
7014
7176
  }
7015
7177
  const isArrayOfFiles = (value) => {
7016
7178
  return Array.isArray(value) && value[0] instanceof File;
7017
7179
  };
7018
- const separateFilesFromValues = (payload) => {
7019
- const { values } = payload;
7180
+ const separateFilesFromValues = (values) => {
7020
7181
  const files = {};
7021
7182
  const newValues = {};
7022
7183
  for (const key in values) {
@@ -7031,17 +7192,13 @@ const separateFilesFromValues = (payload) => {
7031
7192
  newValues[key] = value;
7032
7193
  }
7033
7194
  }
7034
- const payloadWithoutFiles = {
7035
- ...payload,
7036
- values: newValues
7037
- };
7038
- return { payloadWithoutFiles, files };
7195
+ return { values: newValues, files };
7039
7196
  };
7040
7197
  class UserFormSubmissionService extends BaseApiService {
7041
7198
  constructor() {
7042
7199
  super(...arguments);
7043
7200
  // Attach files to submission, after uploading them to S3
7044
- __publicField(this, "getAttachFilesPromises", (files, payload) => {
7201
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
7045
7202
  const { store } = this.client;
7046
7203
  return Object.entries(files).map(async ([key, fileArray]) => {
7047
7204
  const attachResults = [];
@@ -7051,24 +7208,27 @@ class UserFormSubmissionService extends BaseApiService {
7051
7208
  const [fileProps] = await this.client.files.uploadFileToS3(sha1);
7052
7209
  const submissionAttachmentPayload = offline({
7053
7210
  ...fileProps,
7054
- submission: payload.offline_id,
7211
+ submission: submission.offline_id,
7055
7212
  field_identifier: key
7056
7213
  });
7057
7214
  const attach = await this.enqueueRequest({
7058
7215
  description: "Attach file to form submission",
7059
7216
  method: HttpMethod.POST,
7060
- url: `/forms/submission/${payload.offline_id}/attachments/`,
7217
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
7061
7218
  payload: submissionAttachmentPayload,
7062
- blockers: [payload.component, payload.component_stage, payload.issue, payload.form_revision].filter(
7063
- (x) => x !== void 0
7064
- ),
7219
+ blockers: [
7220
+ submission.component,
7221
+ submission.component_stage,
7222
+ submission.issue,
7223
+ submission.form_revision
7224
+ ].filter((x) => x !== void 0),
7065
7225
  blocks: [submissionAttachmentPayload.offline_id]
7066
7226
  });
7067
7227
  const offlinePayload = {
7068
7228
  ...submissionAttachmentPayload,
7069
7229
  file: URL.createObjectURL(file)
7070
7230
  };
7071
- store.dispatch(addUserFormSubmissionAttachment(offlinePayload));
7231
+ store.dispatch(addFormSubmissionAttachment(offlinePayload));
7072
7232
  attachResults.push(attach);
7073
7233
  }
7074
7234
  return attachResults;
@@ -7082,71 +7242,168 @@ class UserFormSubmissionService extends BaseApiService {
7082
7242
  if (!activeProjectId) {
7083
7243
  throw new Error("Expected an active project");
7084
7244
  }
7085
- const { payloadWithoutFiles, files } = separateFilesFromValues(payload);
7245
+ const { values, files } = separateFilesFromValues(payload.values);
7246
+ const offlineSubmission = {
7247
+ ...payload,
7248
+ values,
7249
+ created_by: state.userReducer.currentUser.id,
7250
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7251
+ };
7086
7252
  const promise = this.enqueueRequest({
7087
7253
  description: "Respond to form",
7088
7254
  method: HttpMethod.POST,
7089
7255
  url: `/forms/revisions/${payload.form_revision}/respond/`,
7090
- payload: { ...payloadWithoutFiles, project: activeProjectId },
7256
+ payload: { ...offlineSubmission, project: activeProjectId },
7091
7257
  blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
7092
7258
  (x) => x !== void 0
7093
7259
  ),
7094
7260
  blocks: [payload.offline_id]
7095
7261
  });
7096
- const attachFilesPromises = this.getAttachFilesPromises(files, payload);
7097
- const now = (/* @__PURE__ */ new Date()).toISOString();
7098
- const fullOfflineResult = {
7099
- ...payload,
7100
- created_by: state.userReducer.currentUser.id,
7101
- created_at: now,
7102
- updated_at: now
7103
- };
7104
- const offlineResultWithoutFiles = {
7105
- ...fullOfflineResult,
7106
- ...payloadWithoutFiles
7107
- };
7108
- store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
7262
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
7263
+ store.dispatch(addFormSubmission(offlineSubmission));
7109
7264
  void promise.then((result) => {
7110
7265
  store.dispatch(addActiveProjectFormSubmissionsCount(1));
7111
- store.dispatch(updateOrCreateUserFormSubmission(result));
7266
+ store.dispatch(setFormSubmission(result));
7112
7267
  return result;
7113
7268
  }).catch(() => {
7114
- store.dispatch(deleteUserFormSubmission(payload.offline_id));
7269
+ store.dispatch(deleteFormSubmission(payload.offline_id));
7115
7270
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7116
7271
  });
7117
7272
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7118
- return [fullOfflineResult, settledPromise];
7273
+ return [offlineSubmission, settledPromise];
7119
7274
  }
7120
- update(submission) {
7275
+ // Note currently the bulkAdd method is specific to form submissions for components
7276
+ // TODO: adapt the support bulk adding to any model type
7277
+ async bulkAdd(args) {
7278
+ const { formRevision, values: argsValues, componentOfflineIds } = args;
7121
7279
  const { store } = this.client;
7122
- const { payloadWithoutFiles, files } = separateFilesFromValues(submission);
7123
- if (!("created_by" in payloadWithoutFiles) || !("created_at" in payloadWithoutFiles)) {
7124
- throw new Error("Expected payloadWithoutFiles to have created_by and created_at fields.");
7280
+ const offlineSubmissions = [];
7281
+ const offlineAttachments = [];
7282
+ const submissionOfflineIds = [];
7283
+ const submissionsPayload = [];
7284
+ const attachmentsPayload = [];
7285
+ const { values, files } = separateFilesFromValues(argsValues);
7286
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7287
+ const createdBy = store.getState().userReducer.currentUser.id;
7288
+ for (const component_id of componentOfflineIds) {
7289
+ const submission = offline({
7290
+ form_revision: formRevision,
7291
+ values,
7292
+ created_by: createdBy,
7293
+ submitted_at: submittedAt,
7294
+ component: component_id
7295
+ });
7296
+ submissionOfflineIds.push(submission.offline_id);
7297
+ submissionsPayload.push({ offline_id: submission.offline_id, component_id });
7298
+ offlineSubmissions.push(submission);
7299
+ for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7300
+ for (const file of fileArray) {
7301
+ const sha1 = await hashFile(file);
7302
+ await this.client.files.addCache(file, sha1);
7303
+ const offlineAttachment = offline({
7304
+ file_name: file.name,
7305
+ file_sha1: sha1,
7306
+ file: URL.createObjectURL(file),
7307
+ submission: submission.offline_id,
7308
+ field_identifier: fieldIdentifier
7309
+ });
7310
+ offlineAttachments.push(offlineAttachment);
7311
+ attachmentsPayload.push({
7312
+ offline_id: offlineAttachment.offline_id,
7313
+ submission_id: submission.offline_id,
7314
+ sha1,
7315
+ name: file.name,
7316
+ field_identifier: fieldIdentifier
7317
+ });
7318
+ }
7319
+ }
7125
7320
  }
7321
+ const filesRecord = {};
7322
+ for (const file of Object.values(files).flat()) {
7323
+ const sha1 = await hashFile(file);
7324
+ filesRecord[sha1] = {
7325
+ sha1,
7326
+ extension: file.name.split(".").pop() || "",
7327
+ file_type: file.type,
7328
+ size: file.size
7329
+ };
7330
+ }
7331
+ store.dispatch(addFormSubmissions(offlineSubmissions));
7332
+ store.dispatch(addFormSubmissionAttachments(offlineAttachments));
7333
+ const promise = this.enqueueRequest({
7334
+ description: "Bulk add form submissions",
7335
+ method: HttpMethod.POST,
7336
+ url: `/forms/revisions/${formRevision}/bulk-respond/`,
7337
+ payload: {
7338
+ form_data: values,
7339
+ submitted_at: submittedAt,
7340
+ submissions: submissionsPayload,
7341
+ attachments: attachmentsPayload,
7342
+ files: Object.values(filesRecord)
7343
+ },
7344
+ blockers: componentOfflineIds,
7345
+ blocks: submissionOfflineIds
7346
+ });
7347
+ promise.then(({ submissions, attachments, presigned_urls }) => {
7348
+ store.dispatch(updateFormSubmissions(submissions));
7349
+ store.dispatch(updateFormSubmissionAttachments(attachments));
7350
+ for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
7351
+ const file = filesRecord[sha1];
7352
+ if (!file)
7353
+ continue;
7354
+ void this.enqueueRequest({
7355
+ url: presigned_url.url,
7356
+ description: "Upload file",
7357
+ method: HttpMethod.POST,
7358
+ isExternalUrl: true,
7359
+ isAuthNeeded: false,
7360
+ attachmentHash: sha1,
7361
+ blockers: [`s3-${file.sha1}.${file.extension}`],
7362
+ blocks: [sha1],
7363
+ s3url: presigned_url
7364
+ });
7365
+ }
7366
+ }).catch(() => {
7367
+ store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7368
+ store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
7369
+ });
7370
+ return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
7371
+ }
7372
+ update(submission) {
7373
+ const { store } = this.client;
7374
+ const { values, files } = separateFilesFromValues(submission.values);
7126
7375
  const attachFilesPromises = this.getAttachFilesPromises(files, submission);
7127
- const fullResult = {
7128
- ...payloadWithoutFiles,
7129
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
7376
+ const offlineSubmission = {
7377
+ ...submission,
7378
+ values
7130
7379
  };
7131
- store.dispatch(updateOrCreateUserFormSubmission(fullResult));
7380
+ const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
7381
+ store.dispatch(updateFormSubmission(offlineSubmission));
7132
7382
  const promise = this.enqueueRequest({
7133
7383
  description: "Patch form submission",
7134
7384
  method: HttpMethod.PATCH,
7135
7385
  url: `/forms/submissions/${submission.offline_id}/`,
7136
- payload: fullResult,
7137
- blockers: [fullResult.issue, fullResult.component, fullResult.component_stage].filter(
7386
+ payload: offlineSubmission,
7387
+ blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
7138
7388
  (x) => x !== void 0
7139
7389
  ),
7140
- blocks: [fullResult.offline_id]
7390
+ blocks: [offlineSubmission.offline_id]
7141
7391
  });
7142
- return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7392
+ promise.then((createdSubmission) => {
7393
+ store.dispatch(setFormSubmission(createdSubmission));
7394
+ }).catch(() => {
7395
+ store.dispatch(setFormSubmission(submissionToBeUpdated));
7396
+ });
7397
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
7143
7398
  }
7144
7399
  async delete(submissionId) {
7145
7400
  const { store } = this.client;
7146
7401
  const state = store.getState();
7147
- const submission = state.userFormReducer.submissions[submissionId];
7148
- store.dispatch(deleteUserFormSubmission(submissionId));
7402
+ const submission = state.formSubmissionReducer.formSubmissions[submissionId];
7403
+ const submissionAttachments = selectAttachmentsOfFormSubmission(submissionId)(state);
7404
+ store.dispatch(deleteFormSubmission(submissionId));
7149
7405
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7406
+ store.dispatch(deleteFormSubmissionAttachments(submissionAttachments.map((x) => x.offline_id)));
7150
7407
  try {
7151
7408
  return await this.enqueueRequest({
7152
7409
  description: "Delete user form submissions",
@@ -7156,10 +7413,9 @@ class UserFormSubmissionService extends BaseApiService {
7156
7413
  blocks: []
7157
7414
  });
7158
7415
  } catch (e) {
7159
- if (submission) {
7160
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
7161
- store.dispatch(updateOrCreateUserFormSubmission(submission));
7162
- }
7416
+ store.dispatch(addActiveProjectFormSubmissionsCount(1));
7417
+ store.dispatch(addFormSubmission(submission));
7418
+ store.dispatch(addFormSubmissionAttachments(submissionAttachments));
7163
7419
  throw e;
7164
7420
  }
7165
7421
  }
@@ -7173,7 +7429,7 @@ class UserFormSubmissionService extends BaseApiService {
7173
7429
  blockers: [],
7174
7430
  blocks: []
7175
7431
  });
7176
- store.dispatch(setUserFormSubmissions(submissions));
7432
+ store.dispatch(setFormSubmissions(submissions));
7177
7433
  const attachments = await this.enqueueRequest({
7178
7434
  description: "Fetch form attachments",
7179
7435
  method: HttpMethod.GET,
@@ -7181,7 +7437,7 @@ class UserFormSubmissionService extends BaseApiService {
7181
7437
  blockers: [],
7182
7438
  blocks: []
7183
7439
  });
7184
- store.dispatch(setUserFormSubmissionAttachments(attachments));
7440
+ store.dispatch(setFormSubmissionAttachments(attachments));
7185
7441
  }
7186
7442
  }
7187
7443
  class WorkspaceService extends BaseApiService {
@@ -14039,7 +14295,7 @@ const initialFormValues = (fields, values) => {
14039
14295
  };
14040
14296
  const useAttachImagesToFormRevisionFields = (revision) => {
14041
14297
  const { sdk } = useSDK();
14042
- const attachments = useAppSelector(selectRevisionAttachments((revision == null ? void 0 : revision.offline_id) ?? ""));
14298
+ const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
14043
14299
  return useMemo(() => {
14044
14300
  if (!revision || !attachments)
14045
14301
  return revision;
@@ -14136,7 +14392,7 @@ const FormSubmissionViewer = memo(
14136
14392
  return formRevisionToSchema(revisionWithImages, { readonly: true });
14137
14393
  }, [revisionWithImages]);
14138
14394
  const submissionValuesWithAttachments = useMemo(() => {
14139
- const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
14395
+ const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
14140
14396
  const downloadedAttachments = {};
14141
14397
  for (const attachment of attachments) {
14142
14398
  const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
@@ -14186,8 +14442,8 @@ const FormBrowser = memo(
14186
14442
  }
14187
14443
  return ret;
14188
14444
  }, [filter, maxResults, ownerFilter]);
14189
- const userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? [];
14190
- const userFormMapping = useAppSelector(selectUserFormMapping);
14445
+ const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
14446
+ const userFormMapping = useAppSelector(selectFormMapping);
14191
14447
  const attachableUserForms = userForms.filter((form) => !form.component_type);
14192
14448
  const attachableUserFormMapping = Object.values(userFormMapping).filter(
14193
14449
  (form) => !form.component_type
@@ -14220,7 +14476,7 @@ const FormBrowser = memo(
14220
14476
  const handleChange = useCallback((e) => {
14221
14477
  setFilter(e.currentTarget.value);
14222
14478
  }, []);
14223
- const numberOfForms = useAppSelector(selectNumberOfGeneralUserForms) || 0;
14479
+ const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
14224
14480
  const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
14225
14481
  const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
14226
14482
  return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
@@ -14314,16 +14570,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
14314
14570
  const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
14315
14571
  const currentUser = useAppSelector(selectCurrentUser);
14316
14572
  const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
14317
- const dateToUse = getCreatedAtOrSubmittedAtDate(submission);
14318
- const formattedDateTime = isToday(dateToUse) ? dateToUse.toLocaleTimeString([], {
14319
- hour: "2-digit",
14320
- minute: "2-digit"
14321
- }) : getLocalDateString(dateToUse);
14573
+ const dateToUse = submission.submitted_at;
14574
+ const formattedDateTime = getLocalDateString(dateToUse);
14322
14575
  const revision = useAppSelector(selectFormRevision(submission.form_revision));
14323
14576
  if (!revision) {
14324
14577
  throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
14325
14578
  }
14326
- const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevision(revision.form))) == null ? void 0 : _a2.revision;
14579
+ const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
14327
14580
  const creatorProfileSrc = useFileSrc({
14328
14581
  file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
14329
14582
  fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
@@ -14354,10 +14607,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
14354
14607
  return row;
14355
14608
  });
14356
14609
  FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
14357
- const getCreatedAtOrSubmittedAtDate = (submission) => {
14358
- const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
14359
- return new Date(date);
14360
- };
14361
14610
  const FormSubmissionBrowser = memo((props) => {
14362
14611
  const {
14363
14612
  formId: formId2,
@@ -14371,10 +14620,10 @@ const FormSubmissionBrowser = memo((props) => {
14371
14620
  if (!!formId2 === !!propSubmissions) {
14372
14621
  throw new Error("Either formId or submissions must be provided, but not both.");
14373
14622
  }
14374
- const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId2));
14623
+ const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
14375
14624
  const sortedSubmissions = useMemo(
14376
14625
  () => submissions == null ? void 0 : submissions.sort((a, b) => {
14377
- return getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime();
14626
+ return a.submitted_at.localeCompare(b.submitted_at);
14378
14627
  }),
14379
14628
  [submissions]
14380
14629
  );
@@ -15692,6 +15941,7 @@ export {
15692
15941
  VerificationCodeType,
15693
15942
  WorkspaceService,
15694
15943
  YELLOW,
15944
+ _selectLatestFormRevision,
15695
15945
  _setLatestRetryTime,
15696
15946
  acceptProjectInvite,
15697
15947
  addActiveProjectFormSubmissionsCount,
@@ -15709,6 +15959,16 @@ export {
15709
15959
  addDocuments,
15710
15960
  addEmailDomain,
15711
15961
  addFavouriteProjectId,
15962
+ addForm,
15963
+ addFormRevision,
15964
+ addFormRevisionAttachment,
15965
+ addFormRevisionAttachments,
15966
+ addFormRevisions,
15967
+ addFormSubmission,
15968
+ addFormSubmissionAttachment,
15969
+ addFormSubmissionAttachments,
15970
+ addFormSubmissions,
15971
+ addForms,
15712
15972
  addIssue,
15713
15973
  addIssueAttachment,
15714
15974
  addIssueAttachments,
@@ -15729,13 +15989,6 @@ export {
15729
15989
  addStageCompletions,
15730
15990
  addStages,
15731
15991
  addToRecentIssues,
15732
- addUserForm,
15733
- addUserFormRevision,
15734
- addUserFormRevisionAttachment,
15735
- addUserFormRevisions,
15736
- addUserFormSubmissionAttachment,
15737
- addUserFormSubmissions,
15738
- addUserForms,
15739
15992
  addUsers,
15740
15993
  addWorkspace,
15741
15994
  areArraysEqual,
@@ -15756,6 +16009,7 @@ export {
15756
16009
  componentStageSlice,
15757
16010
  componentTypeReducer,
15758
16011
  componentTypeSlice,
16012
+ constructUploadedFilePayloads,
15759
16013
  coordinatesAreEqual,
15760
16014
  coordinatesToLiteral,
15761
16015
  coordinatesToPointGeometry,
@@ -15766,12 +16020,16 @@ export {
15766
16020
  defaultBadgeColor,
15767
16021
  defaultStore,
15768
16022
  deleteComponentType,
16023
+ deleteForm,
16024
+ deleteFormRevision,
16025
+ deleteFormRevisionAttachment,
16026
+ deleteFormRevisionAttachments,
16027
+ deleteFormRevisions,
16028
+ deleteFormSubmission,
16029
+ deleteFormSubmissionAttachment,
16030
+ deleteFormSubmissionAttachments,
16031
+ deleteFormSubmissions,
15769
16032
  deleteProject,
15770
- deleteUserForm,
15771
- deleteUserFormRevision,
15772
- deleteUserFormRevisions,
15773
- deleteUserFormSubmission,
15774
- deleteUserFormSubmissions,
15775
16033
  dequeue,
15776
16034
  deserialize,
15777
16035
  deserializeField,
@@ -15800,7 +16058,13 @@ export {
15800
16058
  fileSlice,
15801
16059
  fileToBlob,
15802
16060
  flipCoordinates,
16061
+ formReducer,
16062
+ formRevisionReducer,
15803
16063
  formRevisionToSchema,
16064
+ formRevisionsSlice,
16065
+ formSlice,
16066
+ formSubmissionReducer,
16067
+ formSubmissionSlice,
15804
16068
  index as forms,
15805
16069
  fullComponentMarkerSize,
15806
16070
  generateBadgeColors,
@@ -15928,6 +16192,8 @@ export {
15928
16192
  selectAttachmentsOfComponentTypeByType,
15929
16193
  selectAttachmentsOfDocument,
15930
16194
  selectAttachmentsOfDocumentByType,
16195
+ selectAttachmentsOfFormRevision,
16196
+ selectAttachmentsOfFormSubmission,
15931
16197
  selectAttachmentsOfIssue,
15932
16198
  selectAttachmentsOfIssueByType,
15933
16199
  selectAttachmentsOfProject,
@@ -15945,11 +16211,9 @@ export {
15945
16211
  selectComponent,
15946
16212
  selectComponentAttachment,
15947
16213
  selectComponentAttachmentMapping,
15948
- selectComponentSubmissionMapping,
15949
16214
  selectComponentType,
15950
16215
  selectComponentTypeAttachment,
15951
16216
  selectComponentTypeAttachmentMapping,
15952
- selectComponentTypeForm,
15953
16217
  selectComponentTypeFromComponent,
15954
16218
  selectComponentTypeFromComponents,
15955
16219
  selectComponentTypeStagesMapping,
@@ -15979,8 +16243,24 @@ export {
15979
16243
  selectExpandedSections,
15980
16244
  selectFavouriteProjects,
15981
16245
  selectFileAttachmentsOfIssue,
15982
- selectFilteredUserForms,
16246
+ selectFilteredForms,
16247
+ selectForm,
16248
+ selectFormMapping,
16249
+ selectFormOfComponentType,
15983
16250
  selectFormRevision,
16251
+ selectFormRevisionMapping,
16252
+ selectFormRevisions,
16253
+ selectFormRevisionsOfForm,
16254
+ selectFormSubmission,
16255
+ selectFormSubmissionAttachmentsMapping,
16256
+ selectFormSubmissions,
16257
+ selectFormSubmissionsByComponents,
16258
+ selectFormSubmissionsMapping,
16259
+ selectFormSubmissionsOfComponent,
16260
+ selectFormSubmissionsOfForm,
16261
+ selectFormSubmissionsOfIssue,
16262
+ selectFormsCount,
16263
+ selectGeneralFormCount,
15984
16264
  selectHiddenCategoryCount,
15985
16265
  selectHiddenComponentTypeIds,
15986
16266
  selectIsFetchingInitialData,
@@ -15995,10 +16275,10 @@ export {
15995
16275
  selectIssueUpdateMapping,
15996
16276
  selectIssueUpdatesOfIssue,
15997
16277
  selectIssues,
15998
- selectLatestFormRevision,
16278
+ selectLatestFormRevisionByForm,
16279
+ selectLatestFormRevisionOfForm,
16280
+ selectLatestFormRevisionsOfComponentTypes,
15999
16281
  selectLatestRetryTime,
16000
- selectLatestRevisionByFormId,
16001
- selectLatestRevisionsFromComponentTypeIds,
16002
16282
  selectLicense,
16003
16283
  selectLicenseForProject,
16004
16284
  selectLicenses,
@@ -16007,8 +16287,6 @@ export {
16007
16287
  selectMapStyle,
16008
16288
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
16009
16289
  selectNumberOfComponentsOfComponentType,
16010
- selectNumberOfGeneralUserForms,
16011
- selectNumberOfUserForms,
16012
16290
  selectOrganization,
16013
16291
  selectOrganizationAccess,
16014
16292
  selectOrganizationAccessForUser,
@@ -16036,8 +16314,6 @@ export {
16036
16314
  selectRecentIssuesAsSearchResults,
16037
16315
  selectRecentProjects,
16038
16316
  selectRehydrated,
16039
- selectRevisionAttachments,
16040
- selectRevisionsForForm,
16041
16317
  selectRootDocuments,
16042
16318
  selectShowTooltips,
16043
16319
  selectSortedEmailDomains,
@@ -16052,16 +16328,10 @@ export {
16052
16328
  selectStagesFromComponentType,
16053
16329
  selectStagesFromComponentTypeIds,
16054
16330
  selectStagesFromStageIds,
16055
- selectSubmissionAttachments,
16056
- selectSubmissionsForComponent,
16057
- selectSubmissionsForForm,
16058
- selectSubmissionsForIssue,
16059
16331
  selectUploadUrl,
16060
16332
  selectUsedColors,
16061
16333
  selectUser,
16062
- selectUserForm,
16063
- selectUserFormMapping,
16064
- selectUserFormSubmission,
16334
+ selectUserFormRevisionAttachmentsMapping,
16065
16335
  selectUsersAsMapping,
16066
16336
  selectVisibleStatuses,
16067
16337
  selectVisibleUserIds,
@@ -16088,6 +16358,13 @@ export {
16088
16358
  setEnableClustering,
16089
16359
  setEnableDuplicateIssues,
16090
16360
  setEnablePlacementMode,
16361
+ setFormRevision,
16362
+ setFormRevisionAttachments,
16363
+ setFormRevisions,
16364
+ setFormSubmission,
16365
+ setFormSubmissionAttachments,
16366
+ setFormSubmissions,
16367
+ setForms,
16091
16368
  setIsFetchingInitialData,
16092
16369
  setIsImportingProjectFile,
16093
16370
  setIsLoading,
@@ -16112,9 +16389,6 @@ export {
16112
16389
  setTokens,
16113
16390
  setTourStep,
16114
16391
  setUploadUrl,
16115
- setUserFormRevisionAttachments,
16116
- setUserFormSubmissionAttachments,
16117
- setUserFormSubmissions,
16118
16392
  setUsers,
16119
16393
  setVisibleStatuses,
16120
16394
  setVisibleUserIds,
@@ -16139,11 +16413,13 @@ export {
16139
16413
  updateComponentTypeAttachment,
16140
16414
  updateDocumentAttachment,
16141
16415
  updateDocuments,
16416
+ updateFormSubmission,
16417
+ updateFormSubmissionAttachments,
16418
+ updateFormSubmissions,
16142
16419
  updateIssue,
16143
16420
  updateIssueAttachment,
16144
16421
  updateLicense,
16145
16422
  updateOrCreateProject,
16146
- updateOrCreateUserFormSubmission,
16147
16423
  updateOrganizationAccess,
16148
16424
  updateProjectAccess,
16149
16425
  updateProjectAttachment,
@@ -16157,8 +16433,6 @@ export {
16157
16433
  useFormikInput,
16158
16434
  useMemoCompare,
16159
16435
  useSDK,
16160
- userFormReducer,
16161
- userFormSlice,
16162
16436
  userReducer,
16163
16437
  userSlice,
16164
16438
  valueIsFile,