@overmap-ai/core 1.0.51-add-submitted-at-to-form-revisions.0 → 1.0.51-add-teams.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.
Files changed (41) hide show
  1. package/dist/forms/builder/constants.d.ts +1 -0
  2. package/dist/forms/builder/utils.d.ts +1 -1
  3. package/dist/forms/fields/QrField/QrField.d.ts +21 -0
  4. package/dist/forms/fields/QrField/QrInput.d.ts +10 -0
  5. package/dist/forms/fields/QrField/index.d.ts +2 -0
  6. package/dist/forms/fields/constants.d.ts +8 -0
  7. package/dist/forms/fields/index.d.ts +1 -0
  8. package/dist/forms/renderer/FormSubmissionBrowser/FormSubmissionBrowser.d.ts +5 -5
  9. package/dist/forms/renderer/FormSubmissionViewer/FormSubmissionViewer.d.ts +3 -3
  10. package/dist/forms/typings.d.ts +5 -2
  11. package/dist/overmap-core.js +1122 -459
  12. package/dist/overmap-core.js.map +1 -1
  13. package/dist/overmap-core.umd.cjs +1123 -461
  14. package/dist/overmap-core.umd.cjs.map +1 -1
  15. package/dist/sdk/sdk.d.ts +2 -1
  16. package/dist/sdk/services/TeamService.d.ts +12 -0
  17. package/dist/sdk/services/UserFormSubmissionService.d.ts +9 -2
  18. package/dist/sdk/services/index.d.ts +1 -0
  19. package/dist/store/slices/categorySlice.d.ts +4 -1
  20. package/dist/store/slices/documentSlice.d.ts +4 -1
  21. package/dist/store/slices/formRevisionSlice.d.ts +66 -0
  22. package/dist/store/slices/formSlice.d.ts +110 -0
  23. package/dist/store/slices/formSubmissionSlice.d.ts +47 -0
  24. package/dist/store/slices/index.d.ts +4 -1
  25. package/dist/store/slices/issueSlice.d.ts +4 -1
  26. package/dist/store/slices/projectFileSlice.d.ts +4 -1
  27. package/dist/store/slices/teamSlice.d.ts +19 -0
  28. package/dist/store/slices/utils.d.ts +1 -0
  29. package/dist/store/slices/workspaceSlice.d.ts +4 -1
  30. package/dist/store/store.d.ts +13 -4
  31. package/dist/style.css +5 -0
  32. package/dist/typings/files.d.ts +11 -1
  33. package/dist/typings/models/attachments.d.ts +8 -11
  34. package/dist/typings/models/base.d.ts +10 -0
  35. package/dist/typings/models/forms.d.ts +6 -11
  36. package/dist/typings/models/index.d.ts +1 -0
  37. package/dist/typings/models/teams.d.ts +10 -0
  38. package/dist/utils/file.d.ts +2 -0
  39. package/dist/utils/forms.d.ts +2 -0
  40. package/package.json +2 -1
  41. package/dist/store/slices/userFormSlice.d.ts +0 -145
@@ -8,7 +8,7 @@ var _a;
8
8
  import * as React from "react";
9
9
  import React__default, { useState, useEffect, useRef, memo, useMemo, useCallback, createContext, createElement, useContext, forwardRef, Children, isValidElement, cloneElement, Fragment as Fragment$1, useLayoutEffect, useReducer, lazy, Suspense } from "react";
10
10
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
11
- import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, useViewportSize, Overlay, ButtonGroup, Spinner, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, Button, ButtonList, divButtonProps, OvermapDropdownMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
11
+ import { unsafeShowToast, AlertDialogProvider, ToastProvider, DefaultTheme, Flex as Flex$1, IconButton, RiIcon, Text as Text$1, useSeverityColor, Checkbox, TextArea, Select, useToast, Badge, MultiSelect, Overlay, Button, Spinner, useViewportSize, ButtonGroup, IconColorUtility, Tooltip, Popover, useSize, ToggleButton, Separator, OvermapItem, ButtonList, divButtonProps, OvermapDropdownMenu, Input, useAlertDialog } from "@overmap-ai/blocks";
12
12
  import { DepGraph } from "dependency-graph";
13
13
  import { offline as offline$1 } from "@redux-offline/redux-offline";
14
14
  import offlineConfig from "@redux-offline/redux-offline/lib/defaults";
@@ -27,6 +27,7 @@ import { useField, useFormikContext, useFormik, FormikProvider } from "formik";
27
27
  import get from "lodash.get";
28
28
  import Linkify from "linkify-react";
29
29
  import { DragDropContext, Droppable, Draggable } from "@hello-pangea/dnd";
30
+ import QrScannerAPI from "qr-scanner";
30
31
  import { read, utils } from "xlsx";
31
32
  import { pdfjs, Document, Page } from "react-pdf";
32
33
  import "react-pdf/dist/Page/AnnotationLayer.css";
@@ -677,15 +678,15 @@ const wrapMigration = (migrator) => (state) => {
677
678
  };
678
679
  const migrations = [initialVersioning, signOut, signOut, createOutboxState];
679
680
  const manifest = Object.fromEntries(migrations.map((migration2, i) => [i, wrapMigration(migration2)]));
680
- const initialState$n = {
681
+ const initialState$q = {
681
682
  accessToken: "",
682
683
  refreshToken: "",
683
684
  isLoggedIn: false
684
685
  };
685
686
  const authSlice = createSlice({
686
687
  name: "auth",
687
- initialState: initialState$n,
688
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
688
+ initialState: initialState$q,
689
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$q)),
689
690
  reducers: {
690
691
  setTokens: (state, action) => {
691
692
  state.accessToken = action.payload.accessToken;
@@ -850,6 +851,19 @@ function downloadInMemoryFile(filename, text) {
850
851
  element.click();
851
852
  document.body.removeChild(element);
852
853
  }
854
+ const constructUploadedFilePayloads = async (files) => {
855
+ const filePayloads = {};
856
+ for (const file of files) {
857
+ const sha1 = await hashFile(file);
858
+ filePayloads[sha1] = {
859
+ sha1,
860
+ extension: file.name.split(".").pop() || "",
861
+ file_type: file.type,
862
+ size: file.size
863
+ };
864
+ }
865
+ return Object.values(filePayloads);
866
+ };
853
867
  const fileToBlob = async (dataUrl) => {
854
868
  return (await fetch(dataUrl)).blob();
855
869
  };
@@ -1416,7 +1430,7 @@ const getLocalRelativeDateString = memoize((date, min, max) => {
1416
1430
  return getLocalDateString(date);
1417
1431
  return relative.format(days, "days");
1418
1432
  });
1419
- const initialState$m = {
1433
+ const initialState$p = {
1420
1434
  categories: {},
1421
1435
  usedCategoryColors: [],
1422
1436
  categoryVisibility: {
@@ -1426,8 +1440,8 @@ const initialState$m = {
1426
1440
  };
1427
1441
  const categorySlice = createSlice({
1428
1442
  name: "categories",
1429
- initialState: initialState$m,
1430
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1443
+ initialState: initialState$p,
1444
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$p)),
1431
1445
  reducers: {
1432
1446
  setCategories: (state, action) => {
1433
1447
  if (!Array.isArray(action.payload))
@@ -1596,14 +1610,14 @@ function removeAttachments(state, action) {
1596
1610
  delete state.attachments[attachmentId];
1597
1611
  }
1598
1612
  }
1599
- const initialState$l = {
1613
+ const initialState$o = {
1600
1614
  components: {},
1601
1615
  attachments: {}
1602
1616
  };
1603
1617
  const componentSlice = createSlice({
1604
1618
  name: "components",
1605
- initialState: initialState$l,
1606
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1619
+ initialState: initialState$o,
1620
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$o)),
1607
1621
  reducers: {
1608
1622
  addComponent: (state, action) => {
1609
1623
  state.components[action.payload.offline_id] = action.payload;
@@ -1759,13 +1773,13 @@ const {
1759
1773
  removeAllComponentsOfType
1760
1774
  } = componentSlice.actions;
1761
1775
  const componentReducer = componentSlice.reducer;
1762
- const initialState$k = {
1776
+ const initialState$n = {
1763
1777
  completionsByComponentId: {}
1764
1778
  };
1765
1779
  const componentStageCompletionSlice = createSlice({
1766
1780
  name: "componentStageCompletions",
1767
- initialState: initialState$k,
1768
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$k)),
1781
+ initialState: initialState$n,
1782
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$n)),
1769
1783
  reducers: {
1770
1784
  addStageCompletion: (state, action) => {
1771
1785
  let stageToCompletionDateMapping = state.completionsByComponentId[action.payload.component];
@@ -1816,13 +1830,13 @@ const selectCompletedStageIdsForComponent = (component) => (state) => {
1816
1830
  return Object.keys(state.componentStageCompletionReducer.completionsByComponentId[component.offline_id] ?? {});
1817
1831
  };
1818
1832
  const componentStageCompletionReducer = componentStageCompletionSlice.reducer;
1819
- const initialState$j = {
1833
+ const initialState$m = {
1820
1834
  stages: {}
1821
1835
  };
1822
1836
  const componentStageSlice = createSlice({
1823
1837
  name: "componentStages",
1824
- initialState: initialState$j,
1825
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$j)),
1838
+ initialState: initialState$m,
1839
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$m)),
1826
1840
  reducers: {
1827
1841
  addStages: (state, action) => {
1828
1842
  Object.assign(state.stages, toOfflineIdRecord(action.payload));
@@ -1932,15 +1946,15 @@ const selectStageFormIdsFromStageIds = restructureCreateSelectorWithArgs(
1932
1946
  );
1933
1947
  const { addStages, updateStages, removeStages, linkStageToForm, unlinkStageToForm } = componentStageSlice.actions;
1934
1948
  const componentStageReducer = componentStageSlice.reducer;
1935
- const initialState$i = {
1949
+ const initialState$l = {
1936
1950
  componentTypes: {},
1937
1951
  hiddenComponentTypeIds: {},
1938
1952
  attachments: {}
1939
1953
  };
1940
1954
  const componentTypeSlice = createSlice({
1941
1955
  name: "componentTypes",
1942
- initialState: initialState$i,
1943
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
1956
+ initialState: initialState$l,
1957
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$l)),
1944
1958
  reducers: {
1945
1959
  addComponentType: (state, action) => {
1946
1960
  state.componentTypes[action.payload.offline_id] = action.payload;
@@ -2051,13 +2065,13 @@ const {
2051
2065
  deleteComponentType
2052
2066
  } = componentTypeSlice.actions;
2053
2067
  const componentTypeReducer = componentTypeSlice.reducer;
2054
- const initialState$h = {
2068
+ const initialState$k = {
2055
2069
  workspaces: {},
2056
2070
  activeWorkspaceId: null
2057
2071
  };
2058
2072
  const workspaceSlice = createSlice({
2059
2073
  name: "workspace",
2060
- initialState: initialState$h,
2074
+ initialState: initialState$k,
2061
2075
  // The `reducers` field lets us define reducers and generate associated actions
2062
2076
  reducers: {
2063
2077
  setWorkspaces: (state, action) => {
@@ -2114,7 +2128,7 @@ const selectPermittedWorkspaceIds = createSelector(
2114
2128
  );
2115
2129
  const workspaceReducer = workspaceSlice.reducer;
2116
2130
  const maxRecentIssues = 10;
2117
- const initialState$g = {
2131
+ const initialState$j = {
2118
2132
  issues: {},
2119
2133
  attachments: {},
2120
2134
  comments: {},
@@ -2126,9 +2140,9 @@ const initialState$g = {
2126
2140
  };
2127
2141
  const issueSlice = createSlice({
2128
2142
  name: "issues",
2129
- initialState: initialState$g,
2143
+ initialState: initialState$j,
2130
2144
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
2131
- Object.assign(state, initialState$g);
2145
+ Object.assign(state, initialState$j);
2132
2146
  }),
2133
2147
  reducers: {
2134
2148
  setIssues: (state, action) => {
@@ -2536,15 +2550,15 @@ const selectRecentIssuesAsSearchResults = createSelector(
2536
2550
  }
2537
2551
  );
2538
2552
  const issueReducer = issueSlice.reducer;
2539
- const initialState$f = {
2553
+ const initialState$i = {
2540
2554
  s3Urls: {}
2541
2555
  };
2542
2556
  const msPerHour = 1e3 * 60 * 60;
2543
2557
  const msPerWeek = msPerHour * 24 * 7;
2544
2558
  const fileSlice = createSlice({
2545
2559
  name: "file",
2546
- initialState: initialState$f,
2547
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2560
+ initialState: initialState$i,
2561
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$i)),
2548
2562
  reducers: {
2549
2563
  setUploadUrl: (state, action) => {
2550
2564
  const { url, fields, sha1 } = action.payload;
@@ -2571,7 +2585,7 @@ const selectUploadUrl = (sha1) => (state) => {
2571
2585
  return url;
2572
2586
  };
2573
2587
  const fileReducer = fileSlice.reducer;
2574
- const initialState$e = {
2588
+ const initialState$h = {
2575
2589
  // TODO: Change first MapStyle.SATELLITE to MaptStyle.None when project creation map is fixed
2576
2590
  mapStyle: MapStyle.SATELLITE,
2577
2591
  showTooltips: false,
@@ -2579,8 +2593,8 @@ const initialState$e = {
2579
2593
  };
2580
2594
  const mapSlice = createSlice({
2581
2595
  name: "map",
2582
- initialState: initialState$e,
2583
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2596
+ initialState: initialState$h,
2597
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$h)),
2584
2598
  reducers: {
2585
2599
  setMapStyle: (state, action) => {
2586
2600
  state.mapStyle = action.payload;
@@ -2649,7 +2663,7 @@ var LicenseStatus = /* @__PURE__ */ ((LicenseStatus2) => {
2649
2663
  LicenseStatus2[LicenseStatus2["PAST_DUE"] = 8] = "PAST_DUE";
2650
2664
  return LicenseStatus2;
2651
2665
  })(LicenseStatus || {});
2652
- const initialState$d = {
2666
+ const initialState$g = {
2653
2667
  users: {},
2654
2668
  currentUser: {
2655
2669
  id: 0,
@@ -2660,8 +2674,8 @@ const initialState$d = {
2660
2674
  };
2661
2675
  const userSlice = createSlice({
2662
2676
  name: "users",
2663
- initialState: initialState$d,
2664
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2677
+ initialState: initialState$g,
2678
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$g)),
2665
2679
  reducers: {
2666
2680
  setUsers: (state, action) => {
2667
2681
  const usersMapping = {};
@@ -2723,13 +2737,13 @@ const selectUser = (userId) => (state) => {
2723
2737
  const selectUsersAsMapping = (state) => state.userReducer.users;
2724
2738
  const selectFavouriteProjects = (state) => state.userReducer.currentUser.profile.favourite_project_ids;
2725
2739
  const userReducer = userSlice.reducer;
2726
- const initialState$c = {
2740
+ const initialState$f = {
2727
2741
  organizationAccesses: {}
2728
2742
  };
2729
2743
  const organizationAccessSlice = createSlice({
2730
2744
  name: "organizationAccess",
2731
- initialState: initialState$c,
2732
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$c)),
2745
+ initialState: initialState$f,
2746
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$f)),
2733
2747
  reducers: {
2734
2748
  setOrganizationAccesses: (state, action) => {
2735
2749
  if (!Array.isArray(action.payload))
@@ -2792,13 +2806,13 @@ const selectOrganizationAccessUserMapping = (state) => {
2792
2806
  return organizationAccesses;
2793
2807
  };
2794
2808
  const organizationAccessReducer = organizationAccessSlice.reducer;
2795
- const initialState$b = {
2809
+ const initialState$e = {
2796
2810
  licenses: {}
2797
2811
  };
2798
2812
  const licenseSlice = createSlice({
2799
2813
  name: "license",
2800
- initialState: initialState$b,
2801
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
2814
+ initialState: initialState$e,
2815
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$e)),
2802
2816
  reducers: {
2803
2817
  setLicenses: (state, action) => {
2804
2818
  if (!Array.isArray(action.payload))
@@ -2843,13 +2857,13 @@ const selectLicensesForProjectsMapping = createSelector(
2843
2857
  (licenses) => Object.values(licenses).filter((license) => license.project).reduce((accum, license) => ({ ...accum, [license.project]: license }), {})
2844
2858
  );
2845
2859
  const licenseReducer = licenseSlice.reducer;
2846
- const initialState$a = {
2860
+ const initialState$d = {
2847
2861
  projectAccesses: {}
2848
2862
  };
2849
2863
  const projectAccessSlice = createSlice({
2850
2864
  name: "projectAccess",
2851
- initialState: initialState$a,
2852
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
2865
+ initialState: initialState$d,
2866
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$d)),
2853
2867
  reducers: {
2854
2868
  setProjectAccesses: (state, action) => {
2855
2869
  if (!Array.isArray(action.payload))
@@ -2917,7 +2931,7 @@ const selectProjectAccessUserMapping = (state) => {
2917
2931
  return projectAccesses;
2918
2932
  };
2919
2933
  const projectAccessReducer = projectAccessSlice.reducer;
2920
- const initialState$9 = {
2934
+ const initialState$c = {
2921
2935
  projects: {},
2922
2936
  activeProjectId: null,
2923
2937
  recentProjectIds: [],
@@ -2927,7 +2941,7 @@ const initialState$9 = {
2927
2941
  };
2928
2942
  const projectSlice = createSlice({
2929
2943
  name: "projects",
2930
- initialState: initialState$9,
2944
+ initialState: initialState$c,
2931
2945
  reducers: {
2932
2946
  setProjects: (state, action) => {
2933
2947
  const projectsMap = {};
@@ -3114,14 +3128,14 @@ const selectAttachmentsOfProjectByType = restructureCreateSelectorWithArgs(
3114
3128
  }
3115
3129
  )
3116
3130
  );
3117
- const initialState$8 = {
3131
+ const initialState$b = {
3118
3132
  organizations: {},
3119
3133
  activeOrganizationId: null
3120
3134
  };
3121
3135
  const organizationSlice = createSlice({
3122
3136
  name: "organizations",
3123
- initialState: initialState$8,
3124
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$8)),
3137
+ initialState: initialState$b,
3138
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$b)),
3125
3139
  reducers: {
3126
3140
  setOrganizations: (state, action) => {
3127
3141
  for (const org of action.payload) {
@@ -3240,14 +3254,14 @@ const createOfflineAction = (request2, baseUrl) => {
3240
3254
  }
3241
3255
  };
3242
3256
  };
3243
- const initialState$7 = {
3257
+ const initialState$a = {
3244
3258
  deletedRequests: [],
3245
3259
  latestRetryTime: 0
3246
3260
  };
3247
3261
  const outboxSlice = createSlice({
3248
3262
  name: "outbox",
3249
- initialState: initialState$7,
3250
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3263
+ initialState: initialState$a,
3264
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$a)),
3251
3265
  reducers: {
3252
3266
  // enqueueActions is a reducer that does nothing but enqueue API request to the Redux Offline outbox
3253
3267
  // Whenever an issue is being created, a reducer addIssue() is responsible for adding it to the offline store
@@ -3279,7 +3293,7 @@ const selectDeletedRequests = (state) => state.outboxReducer.deletedRequests;
3279
3293
  const selectLatestRetryTime = (state) => state.outboxReducer.latestRetryTime;
3280
3294
  const { enqueueRequest, markForDeletion, markAsDeleted, _setLatestRetryTime } = outboxSlice.actions;
3281
3295
  const outboxReducer = outboxSlice.reducer;
3282
- const initialState$6 = {
3296
+ const initialState$9 = {
3283
3297
  projectFiles: {},
3284
3298
  activeProjectFileId: null,
3285
3299
  isImportingProjectFile: false,
@@ -3287,8 +3301,8 @@ const initialState$6 = {
3287
3301
  };
3288
3302
  const projectFileSlice = createSlice({
3289
3303
  name: "projectFiles",
3290
- initialState: initialState$6,
3291
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3304
+ initialState: initialState$9,
3305
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$9)),
3292
3306
  reducers: {
3293
3307
  addOrReplaceProjectFiles: (state, action) => {
3294
3308
  for (let fileObj of action.payload) {
@@ -3389,12 +3403,12 @@ const selectProjectFiles = createSelector(
3389
3403
  const selectActiveProjectFileId = (state) => state.projectFileReducer.activeProjectFileId;
3390
3404
  const selectIsImportingProjectFile = (state) => state.projectFileReducer.isImportingProjectFile;
3391
3405
  const projectFileReducer = projectFileSlice.reducer;
3392
- const initialState$5 = {
3406
+ const initialState$8 = {
3393
3407
  isRehydrated: false
3394
3408
  };
3395
3409
  const rehydratedSlice = createSlice({
3396
3410
  name: "rehydrated",
3397
- initialState: initialState$5,
3411
+ initialState: initialState$8,
3398
3412
  // The `reducers` field lets us define reducers and generate associated actions
3399
3413
  reducers: {
3400
3414
  setRehydrated: (state, action) => {
@@ -3404,7 +3418,7 @@ const rehydratedSlice = createSlice({
3404
3418
  });
3405
3419
  const selectRehydrated = (state) => state.rehydratedReducer.isRehydrated;
3406
3420
  const rehydratedReducer = rehydratedSlice.reducer;
3407
- const initialState$4 = {
3421
+ const initialState$7 = {
3408
3422
  useIssueTemplate: false,
3409
3423
  placementMode: false,
3410
3424
  enableClustering: false,
@@ -3421,8 +3435,8 @@ const initialState$4 = {
3421
3435
  };
3422
3436
  const settingSlice = createSlice({
3423
3437
  name: "settings",
3424
- initialState: initialState$4,
3425
- extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3438
+ initialState: initialState$7,
3439
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$7)),
3426
3440
  reducers: {
3427
3441
  setEnableDuplicateIssues: (state, action) => {
3428
3442
  state.useIssueTemplate = action.payload;
@@ -3468,146 +3482,231 @@ const selectAppearance = (state) => state.settingReducer.appearance;
3468
3482
  const settingReducer = settingSlice.reducer;
3469
3483
  const selectIsFetchingInitialData = (state) => state.settingReducer.isFetchingInitialData;
3470
3484
  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;
3485
+ const formRevisionSortFn = (formRevisionA, formRevisionB) => {
3486
+ const revisionA = formRevisionA.revision;
3487
+ const revisionB = formRevisionB.revision;
3488
+ if (revisionA === "Pending" && revisionB === "Pending") {
3489
+ return formRevisionA.submitted_at < formRevisionB.submitted_at ? -1 : 1;
3490
+ } else if (revisionA === "Pending") {
3491
+ return 1;
3492
+ } else if (revisionB === "Pending") {
3493
+ return -1;
3494
+ } else {
3495
+ return revisionA < revisionB ? -1 : 1;
3493
3496
  }
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)),
3497
+ };
3498
+ const initialState$6 = {
3499
+ formRevisions: {},
3500
+ attachments: {}
3501
+ };
3502
+ const formRevisionsSlice = createSlice({
3503
+ name: "formRevisions",
3504
+ initialState: initialState$6,
3505
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$6)),
3509
3506
  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;
3507
+ // revision related actions
3508
+ setFormRevision: (state, action) => {
3509
+ state.formRevisions[action.payload.offline_id] = action.payload;
3518
3510
  },
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);
3511
+ setFormRevisions: (state, action) => {
3512
+ state.formRevisions = {};
3513
+ for (const revision of action.payload) {
3514
+ state.formRevisions[revision.offline_id] = revision;
3515
+ }
3533
3516
  },
3534
- deleteUserFormRevision: (state, action) => {
3535
- delete state.revisions[action.payload];
3536
- delete LATEST_REVISION_CACHE[action.payload];
3517
+ addFormRevision: (state, action) => {
3518
+ if (state.formRevisions[action.payload.offline_id] !== void 0) {
3519
+ throw new Error(`Revision with offline_id ${action.payload.offline_id} already exists`);
3520
+ }
3521
+ state.formRevisions[action.payload.offline_id] = action.payload;
3537
3522
  },
3538
- deleteUserFormRevisions: (state, action) => {
3523
+ addFormRevisions: (state, action) => {
3539
3524
  for (const userFormRevision of action.payload) {
3540
- delete state.revisions[userFormRevision.offline_id];
3541
- delete LATEST_REVISION_CACHE[userFormRevision.offline_id];
3525
+ if (state.formRevisions[userFormRevision.offline_id] !== void 0) {
3526
+ throw new Error(`Revision with offline_id ${userFormRevision.offline_id} already exists`);
3527
+ }
3542
3528
  }
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];
3529
+ for (const userFormRevision of action.payload) {
3530
+ state.formRevisions[userFormRevision.offline_id] = userFormRevision;
3554
3531
  }
3555
3532
  },
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];
3533
+ // UserFormRevisions do not get updated
3534
+ deleteFormRevision: (state, action) => {
3535
+ if (state.formRevisions[action.payload] === void 0) {
3536
+ throw new Error(`Revision with offline_id ${action.payload} does not exist`);
3563
3537
  }
3538
+ delete state.formRevisions[action.payload];
3564
3539
  },
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];
3540
+ deleteFormRevisions: (state, action) => {
3541
+ for (const offlineId of action.payload) {
3542
+ if (state.formRevisions[offlineId] === void 0) {
3543
+ throw new Error(`Revision with offline_id ${offlineId} does not exist`);
3574
3544
  }
3575
3545
  }
3546
+ for (const offlineId of action.payload) {
3547
+ delete state.formRevisions[offlineId];
3548
+ }
3576
3549
  },
3577
- setUserFormRevisionAttachments: (state, action) => {
3578
- state.revisionAttachments = {};
3550
+ // attachment related actions
3551
+ setFormRevisionAttachments: (state, action) => {
3552
+ state.attachments = {};
3579
3553
  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
- }
3554
+ state.attachments[attachment.offline_id] = attachment;
3587
3555
  }
3588
3556
  },
3589
- deleteUserFormSubmission: (state, action) => {
3590
- delete state.submissions[action.payload];
3557
+ addFormRevisionAttachment: (state, action) => {
3558
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3559
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3560
+ }
3561
+ state.attachments[action.payload.offline_id] = action.payload;
3591
3562
  },
3592
- deleteUserFormSubmissions: (state, action) => {
3593
- for (const userFormSubmission of action.payload) {
3594
- delete state.submissions[userFormSubmission.offline_id];
3563
+ addFormRevisionAttachments: (state, action) => {
3564
+ for (const attachment of action.payload) {
3565
+ if (state.attachments[attachment.offline_id] !== void 0) {
3566
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3567
+ }
3568
+ }
3569
+ for (const attachment of action.payload) {
3570
+ state.attachments[attachment.offline_id] = attachment;
3595
3571
  }
3596
3572
  },
3597
- addUserFormSubmissions: (state, action) => {
3598
- for (const submission of action.payload) {
3599
- state.submissions[submission.offline_id] = submission;
3573
+ deleteFormRevisionAttachment: (state, action) => {
3574
+ if (state.attachments[action.payload] === void 0) {
3575
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3600
3576
  }
3577
+ delete state.attachments[action.payload];
3601
3578
  },
3602
- setUserFormSubmissions: (state, action) => {
3603
- state.submissions = {};
3604
- action.payload.forEach((submission) => {
3605
- state.submissions[submission.offline_id] = submission;
3579
+ deleteFormRevisionAttachments: (state, action) => {
3580
+ for (const offlineId of action.payload) {
3581
+ if (state.attachments[offlineId] === void 0) {
3582
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3583
+ }
3584
+ }
3585
+ for (const offlineId of action.payload) {
3586
+ delete state.attachments[offlineId];
3587
+ }
3588
+ }
3589
+ }
3590
+ });
3591
+ const {
3592
+ setFormRevision,
3593
+ setFormRevisions,
3594
+ addFormRevision,
3595
+ addFormRevisions,
3596
+ deleteFormRevision,
3597
+ deleteFormRevisions,
3598
+ setFormRevisionAttachments,
3599
+ addFormRevisionAttachment,
3600
+ addFormRevisionAttachments,
3601
+ deleteFormRevisionAttachment,
3602
+ deleteFormRevisionAttachments
3603
+ } = formRevisionsSlice.actions;
3604
+ const selectFormRevisionMapping = (state) => state.formRevisionReducer.formRevisions;
3605
+ const selectFormRevisions = createSelector(
3606
+ [selectFormRevisionMapping],
3607
+ (formRevisions) => Object.values(formRevisions)
3608
+ );
3609
+ const selectFormRevision = (formRevisionId) => (state) => {
3610
+ return state.formRevisionReducer.formRevisions[formRevisionId];
3611
+ };
3612
+ const _selectLatestFormRevision = (formRevisions, formId2) => {
3613
+ let ret = null;
3614
+ for (const candidate of Object.values(formRevisions)) {
3615
+ if (candidate.form === formId2 && (!ret || ret.revision < candidate.revision)) {
3616
+ ret = candidate;
3617
+ }
3618
+ }
3619
+ if (!ret) {
3620
+ throw new Error("No form revision found for form " + formId2);
3621
+ }
3622
+ return ret;
3623
+ };
3624
+ const selectLatestFormRevisionOfForm = restructureCreateSelectorWithArgs(
3625
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3626
+ return revisions.filter((revision) => revision.form === formId2).sort(formRevisionSortFn).pop();
3627
+ })
3628
+ );
3629
+ const selectFormRevisionsOfForm = restructureCreateSelectorWithArgs(
3630
+ createSelector([selectFormRevisions, (_state, formId2) => formId2], (revisions, formId2) => {
3631
+ return revisions.filter((revision) => {
3632
+ return revision.form === formId2;
3633
+ });
3634
+ })
3635
+ );
3636
+ const selectLatestFormRevisionsOfComponentTypes = restructureCreateSelectorWithArgs(
3637
+ createSelector(
3638
+ [
3639
+ (state) => state.formReducer.forms,
3640
+ selectFormRevisionMapping,
3641
+ (_state, componentTypeIds) => componentTypeIds
3642
+ ],
3643
+ (userForms, revisions, componentTypeIds) => {
3644
+ const componentTypeIdsSet = new Set(componentTypeIds);
3645
+ const formsOfComponentTypes = {};
3646
+ const ret = {};
3647
+ for (const form of Object.values(userForms)) {
3648
+ if (form.component_type && componentTypeIdsSet.has(form.component_type)) {
3649
+ formsOfComponentTypes[form.offline_id] = form;
3650
+ }
3651
+ }
3652
+ for (const revision of Object.values(revisions)) {
3653
+ const form = formsOfComponentTypes[revision.form];
3654
+ if (!form || !form.component_type || ret[form.component_type] && formRevisionSortFn(ret[form.component_type], revision) > 0)
3655
+ continue;
3656
+ ret[form.component_type] = revision;
3657
+ }
3658
+ return ret;
3659
+ }
3660
+ )
3661
+ );
3662
+ const selectLatestFormRevisionByForm = createSelector([selectFormRevisionMapping], (revisions) => {
3663
+ const latestRevisions = {};
3664
+ for (const revision of Object.values(revisions)) {
3665
+ const formId2 = revision.form;
3666
+ const currentLatestRevision = latestRevisions[formId2];
3667
+ if (!currentLatestRevision || currentLatestRevision.revision < revision.revision) {
3668
+ latestRevisions[formId2] = revision;
3669
+ }
3670
+ }
3671
+ return latestRevisions;
3672
+ });
3673
+ const selectUserFormRevisionAttachmentsMapping = (state) => {
3674
+ return state.formRevisionReducer.attachments;
3675
+ };
3676
+ const selectAttachmentsOfFormRevision = restructureCreateSelectorWithArgs(
3677
+ createSelector(
3678
+ [selectUserFormRevisionAttachmentsMapping, (_state, revisionId) => revisionId],
3679
+ (attachments, revisionId) => {
3680
+ return Object.values(attachments).filter((attachment) => attachment.revision === revisionId);
3681
+ }
3682
+ )
3683
+ );
3684
+ const formRevisionReducer = formRevisionsSlice.reducer;
3685
+ const initialState$5 = {
3686
+ forms: {}
3687
+ };
3688
+ const formSlice = createSlice({
3689
+ name: "forms",
3690
+ initialState: initialState$5,
3691
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$5)),
3692
+ reducers: {
3693
+ setForms: (state, action) => {
3694
+ state.forms = {};
3695
+ action.payload.forEach((userForm) => {
3696
+ state.forms[userForm.offline_id] = userForm;
3606
3697
  });
3607
3698
  },
3699
+ addForm: (state, action) => {
3700
+ state.forms[action.payload.offline_id] = action.payload;
3701
+ },
3702
+ addForms: (state, action) => {
3703
+ for (const userForm of action.payload) {
3704
+ state.forms[userForm.offline_id] = userForm;
3705
+ }
3706
+ },
3608
3707
  favoriteForm: (state, action) => {
3609
3708
  const { formId: formId2 } = action.payload;
3610
- const form = state.userForms[formId2];
3709
+ const form = state.forms[formId2];
3611
3710
  if (!form) {
3612
3711
  throw new Error("No form exists with the id " + formId2);
3613
3712
  }
@@ -3615,48 +3714,23 @@ const userFormSlice = createSlice({
3615
3714
  },
3616
3715
  unfavoriteForm: (state, action) => {
3617
3716
  const { formId: formId2 } = action.payload;
3618
- const form = state.userForms[formId2];
3717
+ const form = state.forms[formId2];
3619
3718
  if (!form) {
3620
3719
  throw new Error("No form exists with the id " + formId2);
3621
3720
  }
3622
3721
  form.favorite = false;
3623
3722
  },
3624
- deleteUserForm: (state, action) => {
3625
- delete state.userForms[action.payload];
3723
+ deleteForm: (state, action) => {
3724
+ delete state.forms[action.payload];
3626
3725
  }
3627
3726
  }
3628
3727
  });
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(
3728
+ const { setForms, addForm, addForms, favoriteForm, unfavoriteForm, deleteForm } = formSlice.actions;
3729
+ const selectFilteredForms = restructureCreateSelectorWithArgs(
3656
3730
  createSelector(
3657
3731
  [
3658
- (state) => state.userFormReducer.userForms,
3659
- (state) => state.userFormReducer.revisions,
3732
+ (state) => state.formReducer.forms,
3733
+ (state) => state.formRevisionReducer.formRevisions,
3660
3734
  (_state, search) => search
3661
3735
  ],
3662
3736
  (userForms, revisions, search) => {
@@ -3690,63 +3764,188 @@ const selectFilteredUserForms = restructureCreateSelectorWithArgs(
3690
3764
  { memoizeOptions: { equalityCheck: shallowEqual$1 } }
3691
3765
  )
3692
3766
  );
3693
- const selectFormRevision = (revisionId) => (state) => {
3694
- return state.userFormReducer.revisions[revisionId];
3767
+ const selectForm = (formId2) => (state) => {
3768
+ return state.formReducer.forms[formId2];
3695
3769
  };
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;
3770
+ const selectFormMapping = (state) => {
3771
+ return state.formReducer.forms;
3707
3772
  };
3708
- const selectLatestFormRevision = restructureCreateSelectorWithArgs(
3773
+ const selectFormOfComponentType = restructureCreateSelectorWithArgs(
3709
3774
  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);
3775
+ [selectFormMapping, (_state, componentTypeId) => componentTypeId],
3776
+ (userForms, componentTypeId) => {
3777
+ return Object.values(userForms).find((userForm) => userForm.component_type === componentTypeId);
3716
3778
  }
3717
3779
  )
3718
3780
  );
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
- })
3781
+ const selectFormsCount = createSelector([selectFormMapping], (userForms) => {
3782
+ return Object.keys(userForms).length;
3783
+ });
3784
+ const selectGeneralFormCount = createSelector([selectFormMapping], (userForms) => {
3785
+ return Object.values(userForms).filter((form) => !form.component_type).length;
3786
+ });
3787
+ const formReducer = formSlice.reducer;
3788
+ const initialState$4 = {
3789
+ formSubmissions: {},
3790
+ attachments: {}
3791
+ };
3792
+ const formSubmissionSlice = createSlice({
3793
+ name: "formSubmissions",
3794
+ initialState: initialState$4,
3795
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$4)),
3796
+ reducers: {
3797
+ setFormSubmission: (state, action) => {
3798
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3799
+ },
3800
+ setFormSubmissions: (state, action) => {
3801
+ state.formSubmissions = {};
3802
+ for (const submission of action.payload) {
3803
+ state.formSubmissions[submission.offline_id] = submission;
3804
+ }
3805
+ },
3806
+ addFormSubmission: (state, action) => {
3807
+ if (action.payload.offline_id in state.formSubmissions) {
3808
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} already exists`);
3809
+ }
3810
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3811
+ },
3812
+ addFormSubmissions: (state, action) => {
3813
+ for (const submission of action.payload) {
3814
+ if (state.formSubmissions[submission.offline_id] !== void 0) {
3815
+ throw new Error(`Submission with offline_id ${submission.offline_id} already exists`);
3816
+ }
3817
+ }
3818
+ for (const submission of action.payload) {
3819
+ state.formSubmissions[submission.offline_id] = submission;
3820
+ }
3821
+ },
3822
+ updateFormSubmission: (state, action) => {
3823
+ if (state.formSubmissions[action.payload.offline_id] === void 0) {
3824
+ throw new Error(`Submission with offline_id ${action.payload.offline_id} does not exist`);
3825
+ }
3826
+ state.formSubmissions[action.payload.offline_id] = action.payload;
3827
+ },
3828
+ updateFormSubmissions: (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} does not exist`);
3832
+ }
3833
+ }
3834
+ for (const submission of action.payload) {
3835
+ state.formSubmissions[submission.offline_id] = submission;
3836
+ }
3837
+ },
3838
+ deleteFormSubmission: (state, action) => {
3839
+ if (state.formSubmissions[action.payload] === void 0) {
3840
+ throw new Error(`Submission with offline_id ${action.payload} does not exist`);
3841
+ }
3842
+ delete state.formSubmissions[action.payload];
3843
+ },
3844
+ deleteFormSubmissions: (state, action) => {
3845
+ for (const offlineId of action.payload) {
3846
+ if (state.formSubmissions[offlineId] === void 0) {
3847
+ throw new Error(`Submission with offline_id ${offlineId} does not exist`);
3848
+ }
3849
+ delete state.formSubmissions[offlineId];
3850
+ }
3851
+ for (const offlineId of action.payload) {
3852
+ delete state.formSubmissions[offlineId];
3853
+ }
3854
+ },
3855
+ // Attachments
3856
+ addFormSubmissionAttachment: (state, action) => {
3857
+ if (state.attachments[action.payload.offline_id] !== void 0) {
3858
+ throw new Error(`Attachment with offline_id ${action.payload.offline_id} already exists`);
3859
+ }
3860
+ state.attachments[action.payload.offline_id] = action.payload;
3861
+ },
3862
+ addFormSubmissionAttachments: (state, action) => {
3863
+ for (const attachment of action.payload) {
3864
+ if (state.attachments[attachment.offline_id] !== void 0) {
3865
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} already exists`);
3866
+ }
3867
+ }
3868
+ for (const attachment of action.payload) {
3869
+ state.attachments[attachment.offline_id] = attachment;
3870
+ }
3871
+ },
3872
+ // We only need a multi set for attachments because they are not updated, only added and deleted
3873
+ setFormSubmissionAttachments: (state, action) => {
3874
+ state.attachments = {};
3875
+ for (const attachment of action.payload) {
3876
+ state.attachments[attachment.offline_id] = attachment;
3877
+ }
3878
+ },
3879
+ updateFormSubmissionAttachments: (state, action) => {
3880
+ for (const attachment of action.payload) {
3881
+ if (state.attachments[attachment.offline_id] === void 0) {
3882
+ throw new Error(`Attachment with offline_id ${attachment.offline_id} does not exist`);
3883
+ }
3884
+ }
3885
+ for (const attachment of action.payload) {
3886
+ state.attachments[attachment.offline_id] = attachment;
3887
+ }
3888
+ },
3889
+ // The delete actions for UserFormSubmissionAttachments are not used in the app, but are included for completeness
3890
+ // Could be used if editing a submission is ever supported, will be applicable for supporting tip tap content in submissions
3891
+ deleteFormSubmissionAttachment: (state, action) => {
3892
+ if (state.attachments[action.payload] === void 0) {
3893
+ throw new Error(`Attachment with offline_id ${action.payload} does not exist`);
3894
+ }
3895
+ delete state.attachments[action.payload];
3896
+ },
3897
+ deleteFormSubmissionAttachments: (state, action) => {
3898
+ for (const offlineId of action.payload) {
3899
+ if (state.attachments[offlineId] === void 0) {
3900
+ throw new Error(`Attachment with offline_id ${offlineId} does not exist`);
3901
+ }
3902
+ delete state.attachments[offlineId];
3903
+ }
3904
+ }
3905
+ }
3906
+ });
3907
+ const {
3908
+ setFormSubmission,
3909
+ setFormSubmissions,
3910
+ addFormSubmission,
3911
+ addFormSubmissions,
3912
+ updateFormSubmission,
3913
+ updateFormSubmissions,
3914
+ deleteFormSubmission,
3915
+ deleteFormSubmissions,
3916
+ addFormSubmissionAttachment,
3917
+ addFormSubmissionAttachments,
3918
+ setFormSubmissionAttachments,
3919
+ updateFormSubmissionAttachments,
3920
+ deleteFormSubmissionAttachment,
3921
+ deleteFormSubmissionAttachments
3922
+ } = formSubmissionSlice.actions;
3923
+ const selectFormSubmissionsMapping = (state) => {
3924
+ return state.formSubmissionReducer.formSubmissions;
3925
+ };
3926
+ const selectFormSubmissions = createSelector(
3927
+ [selectFormSubmissionsMapping],
3928
+ (submissions) => {
3929
+ return Object.values(submissions);
3930
+ }
3735
3931
  );
3736
- const selectSubmissionsForForm = restructureCreateSelectorWithArgs(
3932
+ const selectFormSubmission = (submissionId) => (state) => {
3933
+ return state.formSubmissionReducer.formSubmissions[submissionId];
3934
+ };
3935
+ const selectFormSubmissionsOfForm = restructureCreateSelectorWithArgs(
3737
3936
  createSelector(
3738
- [selectSubmissions, selectRevisionMapping, (_state, formId2) => formId2],
3937
+ [selectFormSubmissions, selectFormRevisionMapping, (_state, formId2) => formId2],
3739
3938
  (submissions, revisionMapping, formId2) => {
3740
- return Object.values(submissions).filter((submission) => {
3939
+ return submissions.filter((submission) => {
3741
3940
  const revision = revisionMapping[submission.form_revision];
3742
3941
  return (revision == null ? void 0 : revision.form) === formId2;
3743
3942
  });
3744
3943
  }
3745
3944
  )
3746
3945
  );
3747
- const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3946
+ const selectFormSubmissionsOfIssue = restructureCreateSelectorWithArgs(
3748
3947
  createSelector(
3749
- [(state) => state.userFormReducer.submissions, (_state, issueId) => issueId],
3948
+ [selectFormSubmissions, (_state, issueId) => issueId],
3750
3949
  (submissions, issueId) => {
3751
3950
  return Object.values(submissions).filter((submission) => {
3752
3951
  return submission.issue === issueId;
@@ -3754,9 +3953,9 @@ const selectSubmissionsForIssue = restructureCreateSelectorWithArgs(
3754
3953
  }
3755
3954
  )
3756
3955
  );
3757
- const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3956
+ const selectFormSubmissionsOfComponent = restructureCreateSelectorWithArgs(
3758
3957
  createSelector(
3759
- [selectSubmissions, (_state, componentId) => componentId],
3958
+ [selectFormSubmissions, (_state, componentId) => componentId],
3760
3959
  (submissions, componentId) => {
3761
3960
  return submissions.filter((submission) => {
3762
3961
  return submission.component === componentId;
@@ -3764,8 +3963,8 @@ const selectSubmissionsForComponent = restructureCreateSelectorWithArgs(
3764
3963
  }
3765
3964
  )
3766
3965
  );
3767
- const selectComponentSubmissionMapping = createSelector(
3768
- [selectSubmissionMapping, selectComponentsMapping],
3966
+ const selectFormSubmissionsByComponents = createSelector(
3967
+ [selectFormSubmissionsMapping, selectComponentsMapping],
3769
3968
  (submissions, components) => {
3770
3969
  var _a2;
3771
3970
  const componentSubmissionMapping = {};
@@ -3781,60 +3980,24 @@ const selectComponentSubmissionMapping = createSelector(
3781
3980
  return componentSubmissionMapping;
3782
3981
  }
3783
3982
  );
3784
- const selectUserFormMapping = (state) => {
3785
- return state.userFormReducer.userForms;
3786
- };
3787
- const selectComponentTypeForm = restructureCreateSelectorWithArgs(
3788
- 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(
3983
+ const selectFormSubmissionAttachmentsMapping = (state) => {
3984
+ return state.formSubmissionReducer.attachments;
3985
+ };
3986
+ const selectAttachmentsOfFormSubmission = restructureCreateSelectorWithArgs(
3796
3987
  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;
3988
+ [selectFormSubmissionAttachmentsMapping, (_state, submissionId) => submissionId],
3989
+ (attachmentsMapping, submissionId) => {
3990
+ return Object.values(attachmentsMapping).filter((attachment) => attachment.submission === submissionId);
3811
3991
  }
3812
3992
  )
3813
3993
  );
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;
3832
- const initialState$2 = {
3994
+ const formSubmissionReducer = formSubmissionSlice.reducer;
3995
+ const initialState$3 = {
3833
3996
  emailDomains: {}
3834
3997
  };
3835
3998
  const emailDomainsSlice = createSlice({
3836
3999
  name: "emailDomains",
3837
- initialState: initialState$2,
4000
+ initialState: initialState$3,
3838
4001
  reducers: {
3839
4002
  setEmailDomains: (state, action) => {
3840
4003
  const emailDomains = {};
@@ -3861,15 +4024,15 @@ const selectSortedEmailDomains = (state) => Object.values(state.emailDomainsRedu
3861
4024
  (ed1, ed2) => ed1.domain.localeCompare(ed2.domain)
3862
4025
  );
3863
4026
  const emailDomainsReducer = emailDomainsSlice.reducer;
3864
- const initialState$1 = {
4027
+ const initialState$2 = {
3865
4028
  documents: {},
3866
4029
  attachments: {}
3867
4030
  };
3868
4031
  const documentSlice = createSlice({
3869
4032
  name: "documents",
3870
- initialState: initialState$1,
4033
+ initialState: initialState$2,
3871
4034
  extraReducers: (builder) => builder.addCase("RESET", (state) => {
3872
- Object.assign(state, initialState$1);
4035
+ Object.assign(state, initialState$2);
3873
4036
  }),
3874
4037
  reducers: {
3875
4038
  setDocuments: (state, action) => {
@@ -4085,6 +4248,62 @@ const selectAttachmentsOfDocumentByType = restructureCreateSelectorWithArgs(
4085
4248
  )
4086
4249
  );
4087
4250
  const documentsReducer = documentSlice.reducer;
4251
+ const initialState$1 = {
4252
+ teams: {}
4253
+ };
4254
+ const teamSlice = createSlice({
4255
+ name: "teams",
4256
+ initialState: initialState$1,
4257
+ extraReducers: (builder) => builder.addCase("RESET", (state) => Object.assign(state, initialState$1)),
4258
+ reducers: {
4259
+ setTeam: (state, action) => {
4260
+ state.teams[action.payload.offline_id] = action.payload;
4261
+ },
4262
+ setTeams: (state, action) => {
4263
+ state.teams = {};
4264
+ for (const team of action.payload) {
4265
+ state.teams[team.offline_id] = team;
4266
+ }
4267
+ },
4268
+ addTeam: (state, action) => {
4269
+ if (state.teams[action.payload.offline_id]) {
4270
+ throw new Error(`Team with offline_id ${action.payload.offline_id} already exists`);
4271
+ }
4272
+ state.teams[action.payload.offline_id] = action.payload;
4273
+ },
4274
+ updateTeam: (state, action) => {
4275
+ if (!state.teams[action.payload.offline_id]) {
4276
+ throw new Error(`Team with offline_id ${action.payload.offline_id} does not exist`);
4277
+ }
4278
+ state.teams[action.payload.offline_id] = action.payload;
4279
+ },
4280
+ deleteTeam: (state, action) => {
4281
+ delete state.teams[action.payload];
4282
+ }
4283
+ }
4284
+ });
4285
+ const { setTeam, setTeams, addTeam, updateTeam, deleteTeam } = teamSlice.actions;
4286
+ const selectTeamsMapping = (state) => state.teamReducer.teams;
4287
+ const selectTeams = createSelector([selectTeamsMapping], (teams) => {
4288
+ return Object.values(teams);
4289
+ });
4290
+ const selectTeam = (teamId) => (state) => {
4291
+ return state.teamReducer.teams[teamId];
4292
+ };
4293
+ const selectTeamsOfOrganization = restructureCreateSelectorWithArgs(
4294
+ createSelector(
4295
+ [selectTeams, (_state, organizationId) => organizationId],
4296
+ (teams, organizationId) => {
4297
+ return teams.filter((team) => team.organization === organizationId);
4298
+ }
4299
+ )
4300
+ );
4301
+ const selectTeamsOfUser = restructureCreateSelectorWithArgs(
4302
+ createSelector([selectTeams, (_state, userId) => userId], (teams, userId) => {
4303
+ return teams.filter((team) => team.members.includes(userId));
4304
+ })
4305
+ );
4306
+ const teamReducer = teamSlice.reducer;
4088
4307
  const initialState = {
4089
4308
  version: 0
4090
4309
  };
@@ -4126,12 +4345,15 @@ const overmapReducers = {
4126
4345
  projectFileReducer,
4127
4346
  rehydratedReducer,
4128
4347
  settingReducer,
4129
- userFormReducer,
4348
+ formReducer,
4349
+ formRevisionReducer,
4350
+ formSubmissionReducer,
4130
4351
  userReducer,
4131
4352
  workspaceReducer,
4132
4353
  emailDomainsReducer,
4133
4354
  licenseReducer,
4134
- documentsReducer
4355
+ documentsReducer,
4356
+ teamReducer
4135
4357
  };
4136
4358
  const overmapReducer = combineReducers(overmapReducers);
4137
4359
  const resetStore = "RESET";
@@ -4179,9 +4401,7 @@ function handleWorkspaceRemoval(draft, action) {
4179
4401
  throw new Error(`Failed to update index_workspace of issue ${issue.offline_id} to main workspace`);
4180
4402
  }
4181
4403
  }
4182
- const indexedForms = Object.values(draft.userFormReducer.userForms).filter(
4183
- (form) => form.index_workspace === workspaceId
4184
- );
4404
+ const indexedForms = Object.values(draft.formReducer.forms).filter((form) => form.index_workspace === workspaceId);
4185
4405
  for (const form of indexedForms) {
4186
4406
  form.index_workspace = mainWorkspace.offline_id;
4187
4407
  }
@@ -6372,6 +6592,7 @@ class MainService extends BaseApiService {
6372
6592
  }
6373
6593
  if (currentOrgId) {
6374
6594
  await this.client.organizations.fetchInitialOrganizationData(currentOrgId, false);
6595
+ void this.client.teams.refreshStore();
6375
6596
  }
6376
6597
  if (!isProjectIdValid) {
6377
6598
  if (validProjects.length !== 0) {
@@ -6809,7 +7030,7 @@ class UserFormService extends BaseApiService {
6809
7030
  ...revisionAttachmentPayload,
6810
7031
  file: URL.createObjectURL(image)
6811
7032
  };
6812
- store.dispatch(addUserFormRevisionAttachment(offlinePayload));
7033
+ store.dispatch(addFormRevisionAttachment(offlinePayload));
6813
7034
  return attach;
6814
7035
  });
6815
7036
  });
@@ -6824,13 +7045,14 @@ class UserFormService extends BaseApiService {
6824
7045
  };
6825
7046
  const currentUser = state.userReducer.currentUser;
6826
7047
  const activeWorkspaceId = state.workspaceReducer.activeWorkspaceId;
7048
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
6827
7049
  const offlineFormPayload = offline({});
6828
- const offlineRevisionPayload = offline(initialRevision);
7050
+ const offlineRevisionPayload = offline({ ...initialRevision, submitted_at: submittedAt });
6829
7051
  const retForm = {
6830
7052
  ...offlineFormPayload,
6831
7053
  index_workspace: activeWorkspaceId,
6832
7054
  favorite: true,
6833
- submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
7055
+ submitted_at: submittedAt,
6834
7056
  created_by: currentUser.id,
6835
7057
  ...componentTypeId && { component_type: componentTypeId },
6836
7058
  ...ownerAttrs
@@ -6841,11 +7063,11 @@ class UserFormService extends BaseApiService {
6841
7063
  created_by: currentUser.id,
6842
7064
  form: retForm.offline_id,
6843
7065
  revision: 0,
6844
- submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7066
+ submitted_at: submittedAt
6845
7067
  };
6846
7068
  const { store } = this.client;
6847
- store.dispatch(addUserForm(retForm));
6848
- store.dispatch(addUserFormRevision(retRevision));
7069
+ store.dispatch(addForm(retForm));
7070
+ store.dispatch(addFormRevision(retRevision));
6849
7071
  const formPromise = this.enqueueRequest({
6850
7072
  description: "Create form",
6851
7073
  method: HttpMethod.POST,
@@ -6863,8 +7085,8 @@ class UserFormService extends BaseApiService {
6863
7085
  });
6864
7086
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevisionPayload.offline_id);
6865
7087
  void formPromise.catch((e) => {
6866
- store.dispatch(deleteUserForm(retForm.offline_id));
6867
- store.dispatch(deleteUserFormRevision(retRevision.offline_id));
7088
+ store.dispatch(deleteForm(retForm.offline_id));
7089
+ store.dispatch(deleteFormRevision(retRevision.offline_id));
6868
7090
  throw e;
6869
7091
  });
6870
7092
  const settledPromise = Promise.all([formPromise, ...attachImagesPromises]).then(() => formPromise);
@@ -6907,7 +7129,7 @@ class UserFormService extends BaseApiService {
6907
7129
  form: formId2,
6908
7130
  submitted_at: (/* @__PURE__ */ new Date()).toISOString()
6909
7131
  };
6910
- store.dispatch(addUserFormRevision(fullRevision));
7132
+ store.dispatch(addFormRevision(fullRevision));
6911
7133
  const promise = this.enqueueRequest({
6912
7134
  description: "Create form revision",
6913
7135
  method: HttpMethod.PATCH,
@@ -6921,9 +7143,9 @@ class UserFormService extends BaseApiService {
6921
7143
  });
6922
7144
  const attachImagesPromises = this.getAttachImagePromises(images, offlineRevision.offline_id);
6923
7145
  void promise.then((result) => {
6924
- store.dispatch(addUserFormRevision(result));
7146
+ store.dispatch(setFormRevision(result));
6925
7147
  }).catch(() => {
6926
- store.dispatch(deleteUserFormRevision(fullRevision.offline_id));
7148
+ store.dispatch(deleteFormRevision(fullRevision.offline_id));
6927
7149
  });
6928
7150
  const settledPromise = Promise.all([promise, ...attachImagesPromises]).then(() => promise);
6929
7151
  return [fullRevision, settledPromise];
@@ -6965,19 +7187,19 @@ class UserFormService extends BaseApiService {
6965
7187
  async delete(formId2) {
6966
7188
  const { store } = this.client;
6967
7189
  const state = store.getState();
6968
- const userForm = selectUserForm(formId2)(state);
7190
+ const userForm = selectForm(formId2)(state);
6969
7191
  if (!userForm) {
6970
7192
  throw new Error("Expected userForm to exist");
6971
7193
  }
6972
- const userFormSubmissions = selectSubmissionsForForm(formId2)(state);
7194
+ const userFormSubmissions = selectFormSubmissionsOfForm(formId2)(state);
6973
7195
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6974
- store.dispatch(deleteUserFormSubmissions(userFormSubmissions));
7196
+ store.dispatch(deleteFormSubmissions(userFormSubmissions.map(({ offline_id }) => offline_id)));
6975
7197
  }
6976
- const userFormRevisions = selectRevisionsForForm(formId2)(state);
7198
+ const userFormRevisions = selectFormRevisionsOfForm(formId2)(state);
6977
7199
  if (userFormRevisions && userFormRevisions.length > 0) {
6978
- store.dispatch(deleteUserFormRevisions(userFormRevisions));
7200
+ store.dispatch(deleteFormRevisions(userFormRevisions.map(({ offline_id }) => offline_id)));
6979
7201
  }
6980
- store.dispatch(deleteUserForm(formId2));
7202
+ store.dispatch(deleteForm(formId2));
6981
7203
  try {
6982
7204
  return await this.enqueueRequest({
6983
7205
  description: "Delete form",
@@ -6987,12 +7209,12 @@ class UserFormService extends BaseApiService {
6987
7209
  blocks: []
6988
7210
  });
6989
7211
  } catch (e) {
6990
- store.dispatch(addUserForm(userForm));
7212
+ store.dispatch(addForm(userForm));
6991
7213
  if (userFormRevisions && userFormRevisions.length > 0) {
6992
- store.dispatch(addUserFormRevisions(userFormRevisions));
7214
+ store.dispatch(addFormRevisions(userFormRevisions));
6993
7215
  }
6994
7216
  if (userFormSubmissions && userFormSubmissions.length > 0) {
6995
- store.dispatch(addUserFormSubmissions(userFormSubmissions));
7217
+ store.dispatch(addFormSubmissions(userFormSubmissions));
6996
7218
  }
6997
7219
  throw e;
6998
7220
  }
@@ -7006,16 +7228,15 @@ class UserFormService extends BaseApiService {
7006
7228
  blockers: [],
7007
7229
  blocks: []
7008
7230
  });
7009
- store.dispatch(addUserForms(Object.values(result.forms)));
7010
- store.dispatch(addUserFormRevisions(Object.values(result.revisions)));
7011
- store.dispatch(setUserFormRevisionAttachments(Object.values(result.attachments)));
7231
+ store.dispatch(setForms(Object.values(result.forms)));
7232
+ store.dispatch(setFormRevisions(Object.values(result.revisions)));
7233
+ store.dispatch(setFormRevisionAttachments(Object.values(result.attachments)));
7012
7234
  }
7013
7235
  }
7014
7236
  const isArrayOfFiles = (value) => {
7015
7237
  return Array.isArray(value) && value[0] instanceof File;
7016
7238
  };
7017
- const separateFilesFromValues = (payload) => {
7018
- const { values } = payload;
7239
+ const separateFilesFromValues = (values) => {
7019
7240
  const files = {};
7020
7241
  const newValues = {};
7021
7242
  for (const key in values) {
@@ -7030,17 +7251,13 @@ const separateFilesFromValues = (payload) => {
7030
7251
  newValues[key] = value;
7031
7252
  }
7032
7253
  }
7033
- const payloadWithoutFiles = {
7034
- ...payload,
7035
- values: newValues
7036
- };
7037
- return { payloadWithoutFiles, files };
7254
+ return { values: newValues, files };
7038
7255
  };
7039
7256
  class UserFormSubmissionService extends BaseApiService {
7040
7257
  constructor() {
7041
7258
  super(...arguments);
7042
7259
  // Attach files to submission, after uploading them to S3
7043
- __publicField(this, "getAttachFilesPromises", (files, payload) => {
7260
+ __publicField(this, "getAttachFilesPromises", (files, submission) => {
7044
7261
  const { store } = this.client;
7045
7262
  return Object.entries(files).map(async ([key, fileArray]) => {
7046
7263
  const attachResults = [];
@@ -7050,24 +7267,27 @@ class UserFormSubmissionService extends BaseApiService {
7050
7267
  const [fileProps] = await this.client.files.uploadFileToS3(sha1);
7051
7268
  const submissionAttachmentPayload = offline({
7052
7269
  ...fileProps,
7053
- submission: payload.offline_id,
7270
+ submission: submission.offline_id,
7054
7271
  field_identifier: key
7055
7272
  });
7056
7273
  const attach = await this.enqueueRequest({
7057
7274
  description: "Attach file to form submission",
7058
7275
  method: HttpMethod.POST,
7059
- url: `/forms/submission/${payload.offline_id}/attachments/`,
7276
+ url: `/forms/submission/${submission.offline_id}/attachments/`,
7060
7277
  payload: submissionAttachmentPayload,
7061
- blockers: [payload.component, payload.component_stage, payload.issue, payload.form_revision].filter(
7062
- (x) => x !== void 0
7063
- ),
7278
+ blockers: [
7279
+ submission.component,
7280
+ submission.component_stage,
7281
+ submission.issue,
7282
+ submission.form_revision
7283
+ ].filter((x) => x !== void 0),
7064
7284
  blocks: [submissionAttachmentPayload.offline_id]
7065
7285
  });
7066
7286
  const offlinePayload = {
7067
7287
  ...submissionAttachmentPayload,
7068
7288
  file: URL.createObjectURL(file)
7069
7289
  };
7070
- store.dispatch(addUserFormSubmissionAttachment(offlinePayload));
7290
+ store.dispatch(addFormSubmissionAttachment(offlinePayload));
7071
7291
  attachResults.push(attach);
7072
7292
  }
7073
7293
  return attachResults;
@@ -7081,71 +7301,168 @@ class UserFormSubmissionService extends BaseApiService {
7081
7301
  if (!activeProjectId) {
7082
7302
  throw new Error("Expected an active project");
7083
7303
  }
7084
- const { payloadWithoutFiles, files } = separateFilesFromValues(payload);
7304
+ const { values, files } = separateFilesFromValues(payload.values);
7305
+ const offlineSubmission = {
7306
+ ...payload,
7307
+ values,
7308
+ created_by: state.userReducer.currentUser.id,
7309
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
7310
+ };
7085
7311
  const promise = this.enqueueRequest({
7086
7312
  description: "Respond to form",
7087
7313
  method: HttpMethod.POST,
7088
7314
  url: `/forms/revisions/${payload.form_revision}/respond/`,
7089
- payload: { ...payloadWithoutFiles, project: activeProjectId },
7315
+ payload: { ...offlineSubmission, project: activeProjectId },
7090
7316
  blockers: [payload.issue, payload.component, payload.component_stage, "add-form-entry"].filter(
7091
7317
  (x) => x !== void 0
7092
7318
  ),
7093
7319
  blocks: [payload.offline_id]
7094
7320
  });
7095
- const attachFilesPromises = this.getAttachFilesPromises(files, payload);
7096
- const now = (/* @__PURE__ */ new Date()).toISOString();
7097
- const fullOfflineResult = {
7098
- ...payload,
7099
- created_by: state.userReducer.currentUser.id,
7100
- created_at: now,
7101
- updated_at: now
7102
- };
7103
- const offlineResultWithoutFiles = {
7104
- ...fullOfflineResult,
7105
- ...payloadWithoutFiles
7106
- };
7107
- store.dispatch(updateOrCreateUserFormSubmission(offlineResultWithoutFiles));
7321
+ const attachFilesPromises = this.getAttachFilesPromises(files, offlineSubmission);
7322
+ store.dispatch(addFormSubmission(offlineSubmission));
7108
7323
  void promise.then((result) => {
7109
7324
  store.dispatch(addActiveProjectFormSubmissionsCount(1));
7110
- store.dispatch(updateOrCreateUserFormSubmission(result));
7325
+ store.dispatch(setFormSubmission(result));
7111
7326
  return result;
7112
7327
  }).catch(() => {
7113
- store.dispatch(deleteUserFormSubmission(payload.offline_id));
7328
+ store.dispatch(deleteFormSubmission(payload.offline_id));
7114
7329
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7115
7330
  });
7116
7331
  const settledPromise = Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7117
- return [fullOfflineResult, settledPromise];
7332
+ return [offlineSubmission, settledPromise];
7118
7333
  }
7119
- update(submission) {
7334
+ // Note currently the bulkAdd method is specific to form submissions for components
7335
+ // TODO: adapt the support bulk adding to any model type
7336
+ async bulkAdd(args) {
7337
+ const { formRevision, values: argsValues, componentOfflineIds } = args;
7120
7338
  const { store } = this.client;
7121
- const { payloadWithoutFiles, files } = separateFilesFromValues(submission);
7122
- if (!("created_by" in payloadWithoutFiles) || !("created_at" in payloadWithoutFiles)) {
7123
- throw new Error("Expected payloadWithoutFiles to have created_by and created_at fields.");
7339
+ const offlineSubmissions = [];
7340
+ const offlineAttachments = [];
7341
+ const submissionOfflineIds = [];
7342
+ const submissionsPayload = [];
7343
+ const attachmentsPayload = [];
7344
+ const { values, files } = separateFilesFromValues(argsValues);
7345
+ const submittedAt = (/* @__PURE__ */ new Date()).toISOString();
7346
+ const createdBy = store.getState().userReducer.currentUser.id;
7347
+ for (const component_id of componentOfflineIds) {
7348
+ const submission = offline({
7349
+ form_revision: formRevision,
7350
+ values,
7351
+ created_by: createdBy,
7352
+ submitted_at: submittedAt,
7353
+ component: component_id
7354
+ });
7355
+ submissionOfflineIds.push(submission.offline_id);
7356
+ submissionsPayload.push({ offline_id: submission.offline_id, component_id });
7357
+ offlineSubmissions.push(submission);
7358
+ for (const [fieldIdentifier, fileArray] of Object.entries(files)) {
7359
+ for (const file of fileArray) {
7360
+ const sha1 = await hashFile(file);
7361
+ await this.client.files.addCache(file, sha1);
7362
+ const offlineAttachment = offline({
7363
+ file_name: file.name,
7364
+ file_sha1: sha1,
7365
+ file: URL.createObjectURL(file),
7366
+ submission: submission.offline_id,
7367
+ field_identifier: fieldIdentifier
7368
+ });
7369
+ offlineAttachments.push(offlineAttachment);
7370
+ attachmentsPayload.push({
7371
+ offline_id: offlineAttachment.offline_id,
7372
+ submission_id: submission.offline_id,
7373
+ sha1,
7374
+ name: file.name,
7375
+ field_identifier: fieldIdentifier
7376
+ });
7377
+ }
7378
+ }
7379
+ }
7380
+ const filesRecord = {};
7381
+ for (const file of Object.values(files).flat()) {
7382
+ const sha1 = await hashFile(file);
7383
+ filesRecord[sha1] = {
7384
+ sha1,
7385
+ extension: file.name.split(".").pop() || "",
7386
+ file_type: file.type,
7387
+ size: file.size
7388
+ };
7124
7389
  }
7390
+ store.dispatch(addFormSubmissions(offlineSubmissions));
7391
+ store.dispatch(addFormSubmissionAttachments(offlineAttachments));
7392
+ const promise = this.enqueueRequest({
7393
+ description: "Bulk add form submissions",
7394
+ method: HttpMethod.POST,
7395
+ url: `/forms/revisions/${formRevision}/bulk-respond/`,
7396
+ payload: {
7397
+ form_data: values,
7398
+ submitted_at: submittedAt,
7399
+ submissions: submissionsPayload,
7400
+ attachments: attachmentsPayload,
7401
+ files: Object.values(filesRecord)
7402
+ },
7403
+ blockers: componentOfflineIds,
7404
+ blocks: submissionOfflineIds
7405
+ });
7406
+ promise.then(({ submissions, attachments, presigned_urls }) => {
7407
+ store.dispatch(updateFormSubmissions(submissions));
7408
+ store.dispatch(updateFormSubmissionAttachments(attachments));
7409
+ for (const [sha1, presigned_url] of Object.entries(presigned_urls)) {
7410
+ const file = filesRecord[sha1];
7411
+ if (!file)
7412
+ continue;
7413
+ void this.enqueueRequest({
7414
+ url: presigned_url.url,
7415
+ description: "Upload file",
7416
+ method: HttpMethod.POST,
7417
+ isExternalUrl: true,
7418
+ isAuthNeeded: false,
7419
+ attachmentHash: sha1,
7420
+ blockers: [`s3-${file.sha1}.${file.extension}`],
7421
+ blocks: [sha1],
7422
+ s3url: presigned_url
7423
+ });
7424
+ }
7425
+ }).catch(() => {
7426
+ store.dispatch(deleteFormSubmissions(submissionOfflineIds));
7427
+ store.dispatch(deleteFormSubmissionAttachments(offlineAttachments.map((x) => x.offline_id)));
7428
+ });
7429
+ return [offlineSubmissions, promise.then(({ submissions }) => submissions)];
7430
+ }
7431
+ update(submission) {
7432
+ const { store } = this.client;
7433
+ const { values, files } = separateFilesFromValues(submission.values);
7125
7434
  const attachFilesPromises = this.getAttachFilesPromises(files, submission);
7126
- const fullResult = {
7127
- ...payloadWithoutFiles,
7128
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
7435
+ const offlineSubmission = {
7436
+ ...submission,
7437
+ values
7129
7438
  };
7130
- store.dispatch(updateOrCreateUserFormSubmission(fullResult));
7439
+ const submissionToBeUpdated = store.getState().formSubmissionReducer.formSubmissions[submission.offline_id];
7440
+ store.dispatch(updateFormSubmission(offlineSubmission));
7131
7441
  const promise = this.enqueueRequest({
7132
7442
  description: "Patch form submission",
7133
7443
  method: HttpMethod.PATCH,
7134
7444
  url: `/forms/submissions/${submission.offline_id}/`,
7135
- payload: fullResult,
7136
- blockers: [fullResult.issue, fullResult.component, fullResult.component_stage].filter(
7445
+ payload: offlineSubmission,
7446
+ blockers: [offlineSubmission.issue, offlineSubmission.component, offlineSubmission.component_stage].filter(
7137
7447
  (x) => x !== void 0
7138
7448
  ),
7139
- blocks: [fullResult.offline_id]
7449
+ blocks: [offlineSubmission.offline_id]
7450
+ });
7451
+ promise.then((createdSubmission) => {
7452
+ store.dispatch(setFormSubmission(createdSubmission));
7453
+ }).catch(() => {
7454
+ store.dispatch(setFormSubmission(submissionToBeUpdated));
7140
7455
  });
7141
- return Promise.all([promise, ...attachFilesPromises]).then(() => promise);
7456
+ return [offlineSubmission, Promise.all([promise, ...attachFilesPromises]).then(() => promise)];
7142
7457
  }
7143
7458
  async delete(submissionId) {
7144
7459
  const { store } = this.client;
7145
7460
  const state = store.getState();
7146
- const submission = state.userFormReducer.submissions[submissionId];
7147
- store.dispatch(deleteUserFormSubmission(submissionId));
7461
+ const submission = state.formSubmissionReducer.formSubmissions[submissionId];
7462
+ const submissionAttachments = selectAttachmentsOfFormSubmission(submissionId)(state);
7463
+ store.dispatch(deleteFormSubmission(submissionId));
7148
7464
  store.dispatch(addActiveProjectFormSubmissionsCount(-1));
7465
+ store.dispatch(deleteFormSubmissionAttachments(submissionAttachments.map((x) => x.offline_id)));
7149
7466
  try {
7150
7467
  return await this.enqueueRequest({
7151
7468
  description: "Delete user form submissions",
@@ -7155,10 +7472,9 @@ class UserFormSubmissionService extends BaseApiService {
7155
7472
  blocks: []
7156
7473
  });
7157
7474
  } catch (e) {
7158
- if (submission) {
7159
- store.dispatch(addActiveProjectFormSubmissionsCount(1));
7160
- store.dispatch(updateOrCreateUserFormSubmission(submission));
7161
- }
7475
+ store.dispatch(addActiveProjectFormSubmissionsCount(1));
7476
+ store.dispatch(addFormSubmission(submission));
7477
+ store.dispatch(addFormSubmissionAttachments(submissionAttachments));
7162
7478
  throw e;
7163
7479
  }
7164
7480
  }
@@ -7172,7 +7488,7 @@ class UserFormSubmissionService extends BaseApiService {
7172
7488
  blockers: [],
7173
7489
  blocks: []
7174
7490
  });
7175
- store.dispatch(setUserFormSubmissions(submissions));
7491
+ store.dispatch(setFormSubmissions(submissions));
7176
7492
  const attachments = await this.enqueueRequest({
7177
7493
  description: "Fetch form attachments",
7178
7494
  method: HttpMethod.GET,
@@ -7180,7 +7496,7 @@ class UserFormSubmissionService extends BaseApiService {
7180
7496
  blockers: [],
7181
7497
  blocks: []
7182
7498
  });
7183
- store.dispatch(setUserFormSubmissionAttachments(attachments));
7499
+ store.dispatch(setFormSubmissionAttachments(attachments));
7184
7500
  }
7185
7501
  }
7186
7502
  class WorkspaceService extends BaseApiService {
@@ -7904,6 +8220,142 @@ class AgentService extends BaseApiService {
7904
8220
  });
7905
8221
  }
7906
8222
  }
8223
+ class TeamService extends BaseApiService {
8224
+ add(teamPayload) {
8225
+ const { store } = this.client;
8226
+ const state = store.getState();
8227
+ const activeOrganizationId = state.organizationReducer.activeOrganizationId;
8228
+ if (!activeOrganizationId) {
8229
+ throw new Error(`Expected active organization to be set, got ${activeOrganizationId}`);
8230
+ }
8231
+ const offlineTeam = offline({
8232
+ ...teamPayload,
8233
+ organization: activeOrganizationId,
8234
+ submitted_at: (/* @__PURE__ */ new Date()).toISOString()
8235
+ // TODO: uncomment once supported
8236
+ // created_by: state.userReducer.currentUser.id,
8237
+ });
8238
+ store.dispatch(addTeam(offlineTeam));
8239
+ const promise = this.enqueueRequest({
8240
+ description: "Create team",
8241
+ method: HttpMethod.POST,
8242
+ url: `/organizations/${activeOrganizationId}/teams/`,
8243
+ payload: offlineTeam,
8244
+ // No blocks since users and organizations are not offline
8245
+ blockers: [],
8246
+ blocks: [offlineTeam.offline_id]
8247
+ });
8248
+ promise.then((createdTeam) => {
8249
+ store.dispatch(setTeam(createdTeam));
8250
+ }).catch(() => {
8251
+ store.dispatch(deleteTeam(offlineTeam.offline_id));
8252
+ });
8253
+ return [offlineTeam, promise];
8254
+ }
8255
+ // TODO: @Audiopolis / Magnus - should we pass a offline_id as one arg and a UpdatedTeamProps as a second arg instead of this set up?
8256
+ update(team) {
8257
+ const { store } = this.client;
8258
+ const teamToBeUpdated = store.getState().teamReducer.teams[team.offline_id];
8259
+ const offlineUpdatedTeam = {
8260
+ ...teamToBeUpdated,
8261
+ ...team
8262
+ };
8263
+ store.dispatch(updateTeam(offlineUpdatedTeam));
8264
+ const promise = this.enqueueRequest({
8265
+ description: "Update team",
8266
+ method: HttpMethod.PATCH,
8267
+ url: `/organizations/teams/${team.offline_id}/`,
8268
+ payload: offlineUpdatedTeam,
8269
+ blockers: [team.offline_id],
8270
+ blocks: [team.offline_id]
8271
+ });
8272
+ promise.then((updatedTeam) => {
8273
+ store.dispatch(setTeam(updatedTeam));
8274
+ }).catch(() => {
8275
+ store.dispatch(setTeam(teamToBeUpdated));
8276
+ });
8277
+ return [offlineUpdatedTeam, promise];
8278
+ }
8279
+ async delete(teamId) {
8280
+ const { store } = this.client;
8281
+ const state = store.getState();
8282
+ const team = state.teamReducer.teams[teamId];
8283
+ if (!team) {
8284
+ throw new Error(`Expected team with id ${teamId} to exist`);
8285
+ }
8286
+ store.dispatch(deleteTeam(teamId));
8287
+ try {
8288
+ return await this.enqueueRequest({
8289
+ description: "Delete team",
8290
+ method: HttpMethod.DELETE,
8291
+ url: `/organizations/teams/${teamId}/`,
8292
+ blockers: [teamId],
8293
+ blocks: [teamId]
8294
+ });
8295
+ } catch (e) {
8296
+ store.dispatch(setTeam(team));
8297
+ throw e;
8298
+ }
8299
+ }
8300
+ async setMembers(teamId, members) {
8301
+ const { store } = this.client;
8302
+ const team = store.getState().teamReducer.teams[teamId];
8303
+ if (!team) {
8304
+ throw new Error(`Expected team with id ${teamId} to exist`);
8305
+ }
8306
+ if (members.length !== new Set(members).size) {
8307
+ throw new Error("Duplicate members found in the list");
8308
+ }
8309
+ store.dispatch(updateTeam({ ...team, members }));
8310
+ const promise = this.enqueueRequest({
8311
+ description: "Set team members",
8312
+ method: HttpMethod.PUT,
8313
+ url: `/organizations/teams/${teamId}/set-members/`,
8314
+ payload: {
8315
+ users: members
8316
+ },
8317
+ blockers: [teamId],
8318
+ blocks: [teamId]
8319
+ });
8320
+ promise.catch(() => {
8321
+ store.dispatch(setTeam(team));
8322
+ });
8323
+ return promise;
8324
+ }
8325
+ async addMembers(teamId, members) {
8326
+ const { store } = this.client;
8327
+ const team = store.getState().teamReducer.teams[teamId];
8328
+ if (!team) {
8329
+ throw new Error(`Expected team with id ${teamId} to exist`);
8330
+ }
8331
+ const newMembers = [...team.members, ...members];
8332
+ return this.setMembers(teamId, newMembers);
8333
+ }
8334
+ async removeMembers(teamId, members) {
8335
+ const { store } = this.client;
8336
+ const team = store.getState().teamReducer.teams[teamId];
8337
+ if (!team) {
8338
+ throw new Error(`Expected team with id ${teamId} to exist`);
8339
+ }
8340
+ const newMembers = team.members.filter((member) => !members.includes(member));
8341
+ return this.setMembers(teamId, newMembers);
8342
+ }
8343
+ async refreshStore() {
8344
+ const { store } = this.client;
8345
+ const activeOrganizationId = store.getState().organizationReducer.activeOrganizationId;
8346
+ if (!activeOrganizationId) {
8347
+ throw new Error(`Expected active organization to be set, got ${activeOrganizationId}`);
8348
+ }
8349
+ const result = await this.enqueueRequest({
8350
+ description: "Fetch teams",
8351
+ method: HttpMethod.GET,
8352
+ url: `/organizations/${activeOrganizationId}/teams/`,
8353
+ blockers: [],
8354
+ blocks: []
8355
+ });
8356
+ store.dispatch(setTeams(result));
8357
+ }
8358
+ }
7907
8359
  class OvermapSDK {
7908
8360
  constructor(apiUrl, store) {
7909
8361
  __publicField(this, "API_URL");
@@ -7933,6 +8385,7 @@ class OvermapSDK {
7933
8385
  __publicField(this, "emailDomains", new EmailDomainsService(this));
7934
8386
  __publicField(this, "licenses", new LicenseService(this));
7935
8387
  __publicField(this, "documents", new DocumentService(this));
8388
+ __publicField(this, "teams", new TeamService(this));
7936
8389
  this.API_URL = apiUrl;
7937
8390
  this.store = store;
7938
8391
  }
@@ -7974,7 +8427,7 @@ const tabTrigger = "_tabTrigger_1w0fq_69";
7974
8427
  const patchfieldBorder = "_patchfieldBorder_1w0fq_73";
7975
8428
  const title = "_title_1w0fq_73";
7976
8429
  const error = "_error_1w0fq_89";
7977
- const styles$c = {
8430
+ const styles$d = {
7978
8431
  description: description$2,
7979
8432
  floatingButtonContainer: floatingButtonContainer$2,
7980
8433
  FullScreenImageContainer: FullScreenImageContainer$2,
@@ -8095,7 +8548,7 @@ const fileName$1 = "_fileName_10o76_31";
8095
8548
  const longIconButton$1 = "_longIconButton_10o76_36";
8096
8549
  const previewImage$1 = "_previewImage_10o76_42";
8097
8550
  const FullScreenImage$1 = "_FullScreenImage_10o76_12";
8098
- const styles$b = {
8551
+ const styles$c = {
8099
8552
  description: description$1,
8100
8553
  floatingButtonContainer: floatingButtonContainer$1,
8101
8554
  FullScreenImageContainer: FullScreenImageContainer$1,
@@ -8119,7 +8572,7 @@ const FullScreenImagePreview = memo((props) => {
8119
8572
  /* @__PURE__ */ jsx(
8120
8573
  "button",
8121
8574
  {
8122
- className: styles$b.FullScreenImageContainer,
8575
+ className: styles$c.FullScreenImageContainer,
8123
8576
  type: "button",
8124
8577
  onClick: () => {
8125
8578
  setShowPreview(false);
@@ -8127,7 +8580,7 @@ const FullScreenImagePreview = memo((props) => {
8127
8580
  children: /* @__PURE__ */ jsx(
8128
8581
  "img",
8129
8582
  {
8130
- className: styles$b.FullScreenImage,
8583
+ className: styles$c.FullScreenImage,
8131
8584
  src: url,
8132
8585
  alt: name,
8133
8586
  onClick: (e) => {
@@ -8137,11 +8590,11 @@ const FullScreenImagePreview = memo((props) => {
8137
8590
  )
8138
8591
  }
8139
8592
  ),
8140
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.TopBarContainer, align: "center", children: [
8593
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.TopBarContainer, align: "center", children: [
8141
8594
  /* @__PURE__ */ jsx(
8142
8595
  IconButton,
8143
8596
  {
8144
- className: styles$b.longIconButton,
8597
+ className: styles$c.longIconButton,
8145
8598
  variant: "soft",
8146
8599
  "aria-label": "Exit preview",
8147
8600
  onClick: () => {
@@ -8150,11 +8603,11 @@ const FullScreenImagePreview = memo((props) => {
8150
8603
  children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiArrowLeftLine" })
8151
8604
  }
8152
8605
  ),
8153
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.fileName, children: name }),
8606
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.fileName, children: name }),
8154
8607
  /* @__PURE__ */ jsx(
8155
8608
  IconButton,
8156
8609
  {
8157
- className: styles$b.longIconButton,
8610
+ className: styles$c.longIconButton,
8158
8611
  variant: "soft",
8159
8612
  "aria-label": `Download ${name}`,
8160
8613
  onClick: handleDownload,
@@ -8182,7 +8635,7 @@ const InputWithLabel = (props) => {
8182
8635
  /* @__PURE__ */ jsx(
8183
8636
  "img",
8184
8637
  {
8185
- className: styles$b.previewImage,
8638
+ className: styles$c.previewImage,
8186
8639
  src: resolvedImageURL,
8187
8640
  alt: resolvedImage.name,
8188
8641
  onClick: () => {
@@ -8210,7 +8663,7 @@ const InputWithHelpText = (props) => {
8210
8663
  const { helpText, children, severity } = props;
8211
8664
  return /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "1", children: [
8212
8665
  children,
8213
- /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$b.description, children: helpText }) })
8666
+ /* @__PURE__ */ jsx(Flex$1, { direction: "column", children: /* @__PURE__ */ jsx(Text$1, { size: "1", severity, className: styles$c.description, children: helpText }) })
8214
8667
  ] });
8215
8668
  };
8216
8669
  const InputWithLabelAndHelpText = (props) => {
@@ -8444,6 +8897,9 @@ function RiArrowUpLine(props) {
8444
8897
  function RiCalendarLine(props) {
8445
8898
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M9 1V3H15V1H17V3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4C2 3.44772 2.44772 3 3 3H7V1H9ZM20 11H4V19H20V11ZM7 5H4V9H20V5H17V7H15V5H9V7H7V5Z" }, "child": [] }] })(props);
8446
8899
  }
8900
+ function RiQrCodeLine(props) {
8901
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M16 17V16H13V13H16V15H18V17H17V19H15V21H13V18H15V17H16ZM21 21H17V19H19V17H21V21ZM3 3H11V11H3V3ZM5 5V9H9V5H5ZM13 3H21V11H13V3ZM15 5V9H19V5H15ZM3 13H11V21H3V13ZM5 15V19H9V15H5ZM18 13H21V15H18V13ZM6 6H8V8H6V6ZM6 16H8V18H6V16ZM16 6H18V8H16V6Z" }, "child": [] }] })(props);
8902
+ }
8447
8903
  function RiFileCopyLine(props) {
8448
8904
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "d": "M6.9998 6V3C6.9998 2.44772 7.44752 2 7.9998 2H19.9998C20.5521 2 20.9998 2.44772 20.9998 3V17C20.9998 17.5523 20.5521 18 19.9998 18H16.9998V20.9991C16.9998 21.5519 16.5499 22 15.993 22H4.00666C3.45059 22 3 21.5554 3 20.9991L3.0026 7.00087C3.0027 6.44811 3.45264 6 4.00942 6H6.9998ZM5.00242 8L5.00019 20H14.9998V8H5.00242ZM8.9998 6H16.9998V16H18.9998V4H8.9998V6Z" }, "child": [] }] })(props);
8449
8905
  }
@@ -9347,9 +9803,9 @@ const Inset = React.forwardRef((props, forwardedRef) => {
9347
9803
  return React.createElement("div", { ...insetProps, ref: forwardedRef, className: classNames("rt-Inset", className, withBreakpoints(side, "rt-r-side"), withBreakpoints(clip, "rt-r-clip"), withBreakpoints(p, "rt-r-p"), withBreakpoints(px, "rt-r-px"), withBreakpoints(py, "rt-r-py"), withBreakpoints(pt, "rt-r-pt"), withBreakpoints(pr, "rt-r-pr"), withBreakpoints(pb, "rt-r-pb"), withBreakpoints(pl, "rt-r-pl"), withMarginProps(marginProps)) });
9348
9804
  });
9349
9805
  Inset.displayName = "Inset";
9350
- const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9806
+ const sizes$8 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9351
9807
  const headingPropDefs = {
9352
- size: { type: "enum", values: sizes$7, default: "6", responsive: true },
9808
+ size: { type: "enum", values: sizes$8, default: "6", responsive: true },
9353
9809
  weight: { ...weightProp, default: "bold" },
9354
9810
  align: alignProp,
9355
9811
  trim: trimProp,
@@ -9362,9 +9818,9 @@ const Heading = React.forwardRef((props, forwardedRef) => {
9362
9818
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...headingProps, ref: forwardedRef, className: classNames("rt-Heading", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9363
9819
  });
9364
9820
  Heading.displayName = "Heading";
9365
- const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9821
+ const sizes$7 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9366
9822
  const textPropDefs = {
9367
- size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
9823
+ size: { type: "enum", values: sizes$7, default: void 0, responsive: true },
9368
9824
  weight: weightProp,
9369
9825
  align: alignProp,
9370
9826
  trim: trimProp,
@@ -9377,6 +9833,21 @@ const Text = React.forwardRef((props, forwardedRef) => {
9377
9833
  return React.createElement($5e63c961fc1ce211$export$8c6ed5c666ac1360, { "data-accent-color": color, ...textProps, ref: forwardedRef, className: classNames("rt-Text", className, withBreakpoints(size, "rt-r-size"), withBreakpoints(weight, "rt-r-weight"), withBreakpoints(align, "rt-r-ta"), withBreakpoints(trim, "rt-r-lt"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) }, asChild ? children : React.createElement(Tag, null, children));
9378
9834
  });
9379
9835
  Text.displayName = "Text";
9836
+ const sizes$6 = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
9837
+ const variants$4 = ["solid", "soft", "outline", "ghost"];
9838
+ const codePropDefs = {
9839
+ size: { type: "enum", values: sizes$6, default: void 0, responsive: true },
9840
+ variant: { type: "enum", values: variants$4, default: "soft" },
9841
+ weight: weightProp,
9842
+ color: colorProp,
9843
+ highContrast: highContrastProp
9844
+ };
9845
+ const Code = React.forwardRef((props, forwardedRef) => {
9846
+ const { rest: marginRest, ...marginProps } = extractMarginProps(props);
9847
+ const { className, size = codePropDefs.size.default, variant = codePropDefs.variant.default, weight = codePropDefs.weight.default, color = codePropDefs.color.default, highContrast = codePropDefs.highContrast.default, ...codeProps } = marginRest;
9848
+ return React.createElement("code", { "data-accent-color": color, ...codeProps, ref: forwardedRef, className: classNames("rt-Code", className, withBreakpoints(size, "rt-r-size"), `rt-variant-${variant}`, withBreakpoints(weight, "rt-r-weight"), { "rt-high-contrast": highContrast }, withMarginProps(marginProps)) });
9849
+ });
9850
+ Code.displayName = "Code";
9380
9851
  const Em = React.forwardRef((props, forwardedRef) => React.createElement("em", { ...props, ref: forwardedRef, className: classNames("rt-Em", props.className) }));
9381
9852
  Em.displayName = "Em";
9382
9853
  const Strong = React.forwardRef((props, forwardedRef) => React.createElement("strong", { ...props, ref: forwardedRef, className: classNames("rt-Strong", props.className) }));
@@ -11767,7 +12238,7 @@ __publicField(StringOrTextField, "_validateMax", (path) => (value, allValues) =>
11767
12238
  });
11768
12239
  const clickableLinkContainer = "_clickableLinkContainer_1ace7_1";
11769
12240
  const TextFieldInputCopy = "_TextFieldInputCopy_1ace7_5";
11770
- const styles$a = {
12241
+ const styles$b = {
11771
12242
  clickableLinkContainer,
11772
12243
  TextFieldInputCopy
11773
12244
  };
@@ -11796,13 +12267,13 @@ const StringInput = memo((props) => {
11796
12267
  placeholder: field.placeholder,
11797
12268
  color
11798
12269
  }
11799
- ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$a.clickableLinkContainer, children: [
12270
+ ) : /* @__PURE__ */ jsxs(TextField$1.Root, { className: styles$b.clickableLinkContainer, children: [
11800
12271
  /* @__PURE__ */ jsx(
11801
12272
  "div",
11802
12273
  {
11803
12274
  className: classNames$1(
11804
12275
  "rt-TextFieldInput rt-r-size-2 rt-variant-surface",
11805
- styles$a.TextFieldInputCopy
12276
+ styles$b.TextFieldInputCopy
11806
12277
  ),
11807
12278
  children: /* @__PURE__ */ jsx(
11808
12279
  Linkify,
@@ -12374,8 +12845,7 @@ class BaseSelectField extends BaseField {
12374
12845
  description: "List possible options for the user to select from.",
12375
12846
  required: true,
12376
12847
  identifier: `${path}options`,
12377
- minimum_length: 2,
12378
- maximum_length: 20
12848
+ minimum_length: 2
12379
12849
  }),
12380
12850
  showDirectly: true
12381
12851
  }
@@ -12494,6 +12964,158 @@ __publicField(_MultiSelectField, "fieldTypeName", "Multi-select");
12494
12964
  __publicField(_MultiSelectField, "fieldTypeDescription", "Allows the user to select a multiple options from a list of options.");
12495
12965
  __publicField(_MultiSelectField, "Icon", RiCheckboxLine);
12496
12966
  let MultiSelectField = _MultiSelectField;
12967
+ const QrScannerWrapper = "_QrScannerWrapper_1puz3_1";
12968
+ const styles$a = {
12969
+ QrScannerWrapper
12970
+ };
12971
+ const QrInput = memo((props) => {
12972
+ const [{ inputId, labelId, label, helpText, size, severity, showInputOnly, field, fieldProps }, rest] = useFormikInput(props);
12973
+ const [showQrScanner, setShowQrScanner] = useState(false);
12974
+ const value = fieldProps.value;
12975
+ const handleQrScan = useCallback(
12976
+ (data) => {
12977
+ fieldProps.onChange({ target: { value: data } });
12978
+ setShowQrScanner(false);
12979
+ },
12980
+ [fieldProps]
12981
+ );
12982
+ const handleClearScanResult = useCallback(() => {
12983
+ fieldProps.onChange({ target: { value: "" } });
12984
+ }, [fieldProps]);
12985
+ const handleScanButtonClicked = useCallback(() => {
12986
+ setShowQrScanner(true);
12987
+ }, []);
12988
+ const handleQrScannerClose = useCallback(() => {
12989
+ setShowQrScanner(false);
12990
+ }, []);
12991
+ return /* @__PURE__ */ jsx(InputWithLabelAndHelpText, { helpText, severity, children: /* @__PURE__ */ jsxs(
12992
+ InputWithLabel,
12993
+ {
12994
+ size,
12995
+ severity,
12996
+ inputId,
12997
+ labelId,
12998
+ label: showInputOnly ? label : "",
12999
+ image: showInputOnly ? void 0 : field.image,
13000
+ flexProps: { direction: "column", justify: "start", align: "start", gap: "1" },
13001
+ children: [
13002
+ /* @__PURE__ */ jsx(
13003
+ Overlay,
13004
+ {
13005
+ open: showQrScanner,
13006
+ content: () => /* @__PURE__ */ jsx(QrScanner, { onQrScan: handleQrScan, onClose: handleQrScannerClose }),
13007
+ onOpenChange: setShowQrScanner
13008
+ }
13009
+ ),
13010
+ /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "1", align: "center", children: [
13011
+ /* @__PURE__ */ jsxs(Button, { ...rest, variant: "soft", onClick: handleScanButtonClicked, children: [
13012
+ /* @__PURE__ */ jsx(RiIcon, { icon: "RiQrCodeLine" }),
13013
+ "Scan"
13014
+ ] }),
13015
+ value && /* @__PURE__ */ jsx(Text, { color: "jade", size: "1", children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCheckLine", style: { verticalAlign: "bottom" } }) })
13016
+ ] }),
13017
+ value && /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex, { width: "max-content", gap: "2", align: "center", children: [
13018
+ /* @__PURE__ */ jsx(Code, { color: "gray", highContrast: true, children: value }),
13019
+ /* @__PURE__ */ jsx(
13020
+ IconButton,
13021
+ {
13022
+ severity: "info",
13023
+ variant: "ghost",
13024
+ "aria-label": "delete",
13025
+ size: "small",
13026
+ onClick: handleClearScanResult,
13027
+ children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" })
13028
+ }
13029
+ )
13030
+ ] }) })
13031
+ ]
13032
+ }
13033
+ ) });
13034
+ });
13035
+ QrInput.displayName = "QrInput";
13036
+ const QrScanner = memo((props) => {
13037
+ const { onQrScan, onClose } = props;
13038
+ const videoRef = useRef(null);
13039
+ const [isScannerLoading, setIsScannerLoading] = useState(false);
13040
+ useEffect(() => {
13041
+ if (!videoRef.current)
13042
+ return;
13043
+ const qrScanner = new QrScannerAPI(
13044
+ videoRef.current,
13045
+ (result) => {
13046
+ const data = result.data;
13047
+ onQrScan(data);
13048
+ qrScanner.destroy();
13049
+ },
13050
+ {
13051
+ highlightCodeOutline: true,
13052
+ highlightScanRegion: true,
13053
+ maxScansPerSecond: 1
13054
+ }
13055
+ );
13056
+ setIsScannerLoading(true);
13057
+ qrScanner.start().then(() => {
13058
+ setIsScannerLoading(false);
13059
+ }).catch(() => {
13060
+ setIsScannerLoading(false);
13061
+ });
13062
+ }, [onQrScan]);
13063
+ return /* @__PURE__ */ jsxs(
13064
+ Flex,
13065
+ {
13066
+ className: styles$a.QrScannerWrapper,
13067
+ width: "100%",
13068
+ height: "100%",
13069
+ direction: "column",
13070
+ gap: "2",
13071
+ justify: "center",
13072
+ position: "relative",
13073
+ children: [
13074
+ /* @__PURE__ */ jsx(Flex, { width: "100%", position: "absolute", top: "0", p: "2", children: /* @__PURE__ */ jsx(IconButton, { "aria-label": "close", variant: "soft", severity: "info", highContrast: true, onClick: onClose, children: /* @__PURE__ */ jsx(RiIcon, { icon: "RiCloseLine" }) }) }),
13075
+ /* @__PURE__ */ jsxs(Box, { style: { maxWidth: "100%", maxHeight: "100%" }, position: "relative", children: [
13076
+ /* @__PURE__ */ jsx("video", { ref: videoRef, style: { width: "100%", height: "100%" } }),
13077
+ isScannerLoading && /* @__PURE__ */ jsx(
13078
+ Flex,
13079
+ {
13080
+ position: "absolute",
13081
+ inset: "0",
13082
+ style: { background: "var(--color-background)" },
13083
+ justify: "center",
13084
+ align: "center",
13085
+ children: /* @__PURE__ */ jsx(Spinner, {})
13086
+ }
13087
+ )
13088
+ ] })
13089
+ ]
13090
+ }
13091
+ );
13092
+ });
13093
+ QrScanner.displayName = "QrScanner";
13094
+ const emptyQrField = {
13095
+ ...emptyBaseField,
13096
+ type: "qr"
13097
+ };
13098
+ const _QrField = class _QrField extends BaseField {
13099
+ constructor(options) {
13100
+ super({ ...options, type: "qr" });
13101
+ __publicField(this, "onlyValidateAfterTouched", false);
13102
+ }
13103
+ serialize() {
13104
+ return super._serialize();
13105
+ }
13106
+ static deserialize(data) {
13107
+ if (data.type !== "qr")
13108
+ throw new Error("Type mismatch.");
13109
+ return new _QrField(data);
13110
+ }
13111
+ getInput(props) {
13112
+ return /* @__PURE__ */ jsx(QrInput, { ...props, field: this });
13113
+ }
13114
+ };
13115
+ __publicField(_QrField, "fieldTypeName", "QR");
13116
+ __publicField(_QrField, "fieldTypeDescription", "Used for scanning/reading QR codes.");
13117
+ __publicField(_QrField, "Icon", RiQrCodeLine);
13118
+ let QrField = _QrField;
12497
13119
  const FieldInputCloner = memo((props) => {
12498
13120
  const { field, ...rest } = props;
12499
13121
  const [{ value: identifier }] = useField(field.options.clonedFieldIdentifier);
@@ -13751,6 +14373,7 @@ const FieldTypeToClsMapping = {
13751
14373
  text: TextField,
13752
14374
  custom: CustomField,
13753
14375
  upload: UploadField,
14376
+ qr: QrField,
13754
14377
  // TODO: Underscore
13755
14378
  "multi-string": MultiStringField,
13756
14379
  "multi-select": MultiSelectField
@@ -13764,6 +14387,7 @@ const FieldTypeToEmptyFieldMapping = {
13764
14387
  text: emptyTextField,
13765
14388
  custom: emptyCustomField,
13766
14389
  upload: emptyUploadField,
14390
+ qr: emptyQrField,
13767
14391
  // TODO: Underscore
13768
14392
  "multi-string": emptyMultiStringField,
13769
14393
  "multi-select": emptyMultiSelectField
@@ -13851,7 +14475,7 @@ const FieldSectionLayout = memo((props) => {
13851
14475
  return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "3", children: [
13852
14476
  /* @__PURE__ */ jsxs(Flex$1, { direction: "column", children: [
13853
14477
  /* @__PURE__ */ jsx(Heading, { as: "h3", size: "3", children: label }),
13854
- /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: description2 })
14478
+ /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: description2 })
13855
14479
  ] }),
13856
14480
  inputs
13857
14481
  ] }) });
@@ -14038,7 +14662,7 @@ const initialFormValues = (fields, values) => {
14038
14662
  };
14039
14663
  const useAttachImagesToFormRevisionFields = (revision) => {
14040
14664
  const { sdk } = useSDK();
14041
- const attachments = useAppSelector(selectRevisionAttachments((revision == null ? void 0 : revision.offline_id) ?? ""));
14665
+ const attachments = useAppSelector(selectAttachmentsOfFormRevision((revision == null ? void 0 : revision.offline_id) ?? ""));
14042
14666
  return useMemo(() => {
14043
14667
  if (!revision || !attachments)
14044
14668
  return revision;
@@ -14094,7 +14718,7 @@ const FormRenderer = memo(
14094
14718
  [schema.title]
14095
14719
  );
14096
14720
  const Description = useMemo(
14097
- () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$b.description, children: schema.description }) : schema.description,
14721
+ () => typeof schema.description === "string" ? /* @__PURE__ */ jsx(Text$1, { className: styles$c.description, children: schema.description }) : schema.description,
14098
14722
  [schema.description]
14099
14723
  );
14100
14724
  const inputs = useFieldInputs(schema.fields, { formId: formId2, disabled: readonly });
@@ -14110,7 +14734,7 @@ const FormRenderer = memo(
14110
14734
  !hideDescription && Description
14111
14735
  ] }) }),
14112
14736
  inputs,
14113
- !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$b.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
14737
+ !readonly && /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
14114
14738
  cancelText && /* @__PURE__ */ jsx(Button, { severity: "info", ...buttonProps, type: "button", onClick: onCancel, children: cancelText }),
14115
14739
  /* @__PURE__ */ jsx(Button, { ...buttonProps, type: "submit", disabled: !formik.isValid, children: submitText })
14116
14740
  ] })
@@ -14135,7 +14759,7 @@ const FormSubmissionViewer = memo(
14135
14759
  return formRevisionToSchema(revisionWithImages, { readonly: true });
14136
14760
  }, [revisionWithImages]);
14137
14761
  const submissionValuesWithAttachments = useMemo(() => {
14138
- const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
14762
+ const attachments = selectAttachmentsOfFormSubmission(submission.offline_id)(sdk.store.getState()) ?? [];
14139
14763
  const downloadedAttachments = {};
14140
14764
  for (const attachment of attachments) {
14141
14765
  const promise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
@@ -14185,8 +14809,8 @@ const FormBrowser = memo(
14185
14809
  }
14186
14810
  return ret;
14187
14811
  }, [filter, maxResults, ownerFilter]);
14188
- const userForms = useAppSelector(selectFilteredUserForms(ownerFilterOptions)) ?? [];
14189
- const userFormMapping = useAppSelector(selectUserFormMapping);
14812
+ const userForms = useAppSelector(selectFilteredForms(ownerFilterOptions)) ?? [];
14813
+ const userFormMapping = useAppSelector(selectFormMapping);
14190
14814
  const attachableUserForms = userForms.filter((form) => !form.component_type);
14191
14815
  const attachableUserFormMapping = Object.values(userFormMapping).filter(
14192
14816
  (form) => !form.component_type
@@ -14219,7 +14843,7 @@ const FormBrowser = memo(
14219
14843
  const handleChange = useCallback((e) => {
14220
14844
  setFilter(e.currentTarget.value);
14221
14845
  }, []);
14222
- const numberOfForms = useAppSelector(selectNumberOfGeneralUserForms) || 0;
14846
+ const numberOfForms = useAppSelector(selectGeneralFormCount) || 0;
14223
14847
  const numberOfHiddenForms = numberOfForms - attachableUserForms.length;
14224
14848
  const overflowMessage = attachableUserForms.length == maxResults && numberOfHiddenForms > 0 ? `Only the first ${maxResults} results are shown (${numberOfHiddenForms} hidden)` : numberOfHiddenForms > 0 && `${numberOfHiddenForms} hidden forms`;
14225
14849
  return /* @__PURE__ */ jsxs(Flex$1, { ref, direction: "column", gap: "2", children: [
@@ -14313,16 +14937,13 @@ const FormSubmissionBrowserEntry = memo((props) => {
14313
14937
  const { submission, onSubmissionClick, compact, labelType, rowDecorator } = props;
14314
14938
  const currentUser = useAppSelector(selectCurrentUser);
14315
14939
  const createdBy = useAppSelector(selectUser("created_by" in submission ? submission.created_by : currentUser.id));
14316
- const dateToUse = getCreatedAtOrSubmittedAtDate(submission);
14317
- const formattedDateTime = isToday(dateToUse) ? dateToUse.toLocaleTimeString([], {
14318
- hour: "2-digit",
14319
- minute: "2-digit"
14320
- }) : getLocalDateString(dateToUse);
14940
+ const dateToUse = submission.submitted_at;
14941
+ const formattedDateTime = getLocalDateString(dateToUse);
14321
14942
  const revision = useAppSelector(selectFormRevision(submission.form_revision));
14322
14943
  if (!revision) {
14323
14944
  throw new Error(`Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`);
14324
14945
  }
14325
- const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevision(revision.form))) == null ? void 0 : _a2.revision;
14946
+ const latestRevisionNumber = (_a2 = useAppSelector(selectLatestFormRevisionOfForm(revision.form))) == null ? void 0 : _a2.revision;
14326
14947
  const creatorProfileSrc = useFileSrc({
14327
14948
  file: (createdBy == null ? void 0 : createdBy.profile.file) ?? null,
14328
14949
  fileSha1: (createdBy == null ? void 0 : createdBy.profile.file_sha1) ?? null
@@ -14353,10 +14974,6 @@ const FormSubmissionBrowserEntry = memo((props) => {
14353
14974
  return row;
14354
14975
  });
14355
14976
  FormSubmissionBrowserEntry.displayName = "FormSubmissionBrowserEntry";
14356
- const getCreatedAtOrSubmittedAtDate = (submission) => {
14357
- const date = "created_at" in submission ? submission.created_at : submission.submitted_at;
14358
- return new Date(date);
14359
- };
14360
14977
  const FormSubmissionBrowser = memo((props) => {
14361
14978
  const {
14362
14979
  formId: formId2,
@@ -14370,10 +14987,10 @@ const FormSubmissionBrowser = memo((props) => {
14370
14987
  if (!!formId2 === !!propSubmissions) {
14371
14988
  throw new Error("Either formId or submissions must be provided, but not both.");
14372
14989
  }
14373
- const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectSubmissionsForForm(formId2));
14990
+ const submissions = useAppSelector(propSubmissions ? () => propSubmissions : selectFormSubmissionsOfForm(formId2));
14374
14991
  const sortedSubmissions = useMemo(
14375
14992
  () => submissions == null ? void 0 : submissions.sort((a, b) => {
14376
- return getCreatedAtOrSubmittedAtDate(b).getTime() - getCreatedAtOrSubmittedAtDate(a).getTime();
14993
+ return a.submitted_at.localeCompare(b.submitted_at);
14377
14994
  }),
14378
14995
  [submissions]
14379
14996
  );
@@ -15465,12 +16082,12 @@ const FormBuilder = memo(
15465
16082
  });
15466
16083
  const previewSchema = useMemo(() => formRevisionToSchema(formik.values), [formik.values]);
15467
16084
  return /* @__PURE__ */ jsx(Tabs.Root, { ref, defaultValue: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { direction: "column", gap: "2", children: [
15468
- showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$c.tabsList, tabsListClassName), children: [
15469
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
16085
+ showTabs && /* @__PURE__ */ jsxs(Tabs.List, { className: classNames$1(styles$d.tabsList, tabsListClassName), children: [
16086
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "edit", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15470
16087
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiPencilLine" }),
15471
16088
  "Edit"
15472
16089
  ] }) }),
15473
- /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$c.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
16090
+ /* @__PURE__ */ jsx(Tabs.Trigger, { className: styles$d.tabTrigger, value: "preview", children: /* @__PURE__ */ jsxs(Flex$1, { align: "center", gap: "2", children: [
15474
16091
  /* @__PURE__ */ jsx(RiIcon, { icon: "RiEyeLine" }),
15475
16092
  "Preview"
15476
16093
  ] }) })
@@ -15494,8 +16111,8 @@ const FormBuilder = memo(
15494
16111
  render: ({ setValue, value, meta }) => /* @__PURE__ */ jsx(InputWithHelpText, { severity: "danger", helpText: meta.error ?? null, children: /* @__PURE__ */ jsx(
15495
16112
  Input,
15496
16113
  {
15497
- className: classNames$1(styles$c.title, {
15498
- [styles$c.error]: meta.error
16114
+ className: classNames$1(styles$d.title, {
16115
+ [styles$d.error]: meta.error
15499
16116
  }),
15500
16117
  placeholder: "Form title",
15501
16118
  value,
@@ -15517,7 +16134,7 @@ const FormBuilder = memo(
15517
16134
  render: ({ setValue, value }) => /* @__PURE__ */ jsx(
15518
16135
  TextArea,
15519
16136
  {
15520
- className: styles$c.description,
16137
+ className: styles$d.description,
15521
16138
  placeholder: "Explain the purpose of this form",
15522
16139
  value,
15523
16140
  onChange: (event) => {
@@ -15535,7 +16152,7 @@ const FormBuilder = memo(
15535
16152
  /* @__PURE__ */ jsx(FieldsEditor, { fieldsOnly }),
15536
16153
  /* @__PURE__ */ jsx(Text$1, { severity: "danger", size: "1", children: typeof formik.errors.fields === "string" && formik.errors.fields })
15537
16154
  ] }),
15538
- /* @__PURE__ */ jsxs(Flex$1, { className: styles$c.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
16155
+ /* @__PURE__ */ jsxs(Flex$1, { className: styles$d.floatingButtonContainer, align: "center", justify: "end", gap: "2", children: [
15539
16156
  onCancel && /* @__PURE__ */ jsx(Button, { type: "button", variant: "solid", severity: "info", onClick: onCancel, children: "Cancel" }),
15540
16157
  /* @__PURE__ */ jsx(Button, { type: "submit", children: "Save form" })
15541
16158
  ] })
@@ -15570,6 +16187,9 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15570
16187
  NumberInput,
15571
16188
  PatchField,
15572
16189
  PatchFormProvider,
16190
+ QrField,
16191
+ QrInput,
16192
+ QrScanner,
15573
16193
  SelectField,
15574
16194
  SelectInput,
15575
16195
  StringField,
@@ -15584,6 +16204,7 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
15584
16204
  emptyMultiSelectField,
15585
16205
  emptyMultiStringField,
15586
16206
  emptyNumberField,
16207
+ emptyQrField,
15587
16208
  emptySelectField,
15588
16209
  emptyStringField,
15589
16210
  emptyTextField,
@@ -15674,6 +16295,9 @@ export {
15674
16295
  ProjectFileService,
15675
16296
  ProjectService,
15676
16297
  ProjectType,
16298
+ QrField,
16299
+ QrInput,
16300
+ QrScanner,
15677
16301
  SDKContext,
15678
16302
  SDKProvider,
15679
16303
  SUPPORTED_IMAGE_FILE_TYPES,
@@ -15684,6 +16308,7 @@ export {
15684
16308
  SpreadsheetViewer,
15685
16309
  StringField,
15686
16310
  StringInput,
16311
+ TeamService,
15687
16312
  TextField,
15688
16313
  TextInput,
15689
16314
  UserFormService,
@@ -15691,6 +16316,7 @@ export {
15691
16316
  VerificationCodeType,
15692
16317
  WorkspaceService,
15693
16318
  YELLOW,
16319
+ _selectLatestFormRevision,
15694
16320
  _setLatestRetryTime,
15695
16321
  acceptProjectInvite,
15696
16322
  addActiveProjectFormSubmissionsCount,
@@ -15708,6 +16334,16 @@ export {
15708
16334
  addDocuments,
15709
16335
  addEmailDomain,
15710
16336
  addFavouriteProjectId,
16337
+ addForm,
16338
+ addFormRevision,
16339
+ addFormRevisionAttachment,
16340
+ addFormRevisionAttachments,
16341
+ addFormRevisions,
16342
+ addFormSubmission,
16343
+ addFormSubmissionAttachment,
16344
+ addFormSubmissionAttachments,
16345
+ addFormSubmissions,
16346
+ addForms,
15711
16347
  addIssue,
15712
16348
  addIssueAttachment,
15713
16349
  addIssueAttachments,
@@ -15727,14 +16363,8 @@ export {
15727
16363
  addStageCompletion,
15728
16364
  addStageCompletions,
15729
16365
  addStages,
16366
+ addTeam,
15730
16367
  addToRecentIssues,
15731
- addUserForm,
15732
- addUserFormRevision,
15733
- addUserFormRevisionAttachment,
15734
- addUserFormRevisions,
15735
- addUserFormSubmissionAttachment,
15736
- addUserFormSubmissions,
15737
- addUserForms,
15738
16368
  addUsers,
15739
16369
  addWorkspace,
15740
16370
  areArraysEqual,
@@ -15755,6 +16385,7 @@ export {
15755
16385
  componentStageSlice,
15756
16386
  componentTypeReducer,
15757
16387
  componentTypeSlice,
16388
+ constructUploadedFilePayloads,
15758
16389
  coordinatesAreEqual,
15759
16390
  coordinatesToLiteral,
15760
16391
  coordinatesToPointGeometry,
@@ -15765,12 +16396,17 @@ export {
15765
16396
  defaultBadgeColor,
15766
16397
  defaultStore,
15767
16398
  deleteComponentType,
16399
+ deleteForm,
16400
+ deleteFormRevision,
16401
+ deleteFormRevisionAttachment,
16402
+ deleteFormRevisionAttachments,
16403
+ deleteFormRevisions,
16404
+ deleteFormSubmission,
16405
+ deleteFormSubmissionAttachment,
16406
+ deleteFormSubmissionAttachments,
16407
+ deleteFormSubmissions,
15768
16408
  deleteProject,
15769
- deleteUserForm,
15770
- deleteUserFormRevision,
15771
- deleteUserFormRevisions,
15772
- deleteUserFormSubmission,
15773
- deleteUserFormSubmissions,
16409
+ deleteTeam,
15774
16410
  dequeue,
15775
16411
  deserialize,
15776
16412
  deserializeField,
@@ -15788,6 +16424,7 @@ export {
15788
16424
  emptyMultiSelectField,
15789
16425
  emptyMultiStringField,
15790
16426
  emptyNumberField,
16427
+ emptyQrField,
15791
16428
  emptySelectField,
15792
16429
  emptyStringField,
15793
16430
  emptyTextField,
@@ -15799,7 +16436,13 @@ export {
15799
16436
  fileSlice,
15800
16437
  fileToBlob,
15801
16438
  flipCoordinates,
16439
+ formReducer,
16440
+ formRevisionReducer,
15802
16441
  formRevisionToSchema,
16442
+ formRevisionsSlice,
16443
+ formSlice,
16444
+ formSubmissionReducer,
16445
+ formSubmissionSlice,
15803
16446
  index as forms,
15804
16447
  fullComponentMarkerSize,
15805
16448
  generateBadgeColors,
@@ -15927,6 +16570,8 @@ export {
15927
16570
  selectAttachmentsOfComponentTypeByType,
15928
16571
  selectAttachmentsOfDocument,
15929
16572
  selectAttachmentsOfDocumentByType,
16573
+ selectAttachmentsOfFormRevision,
16574
+ selectAttachmentsOfFormSubmission,
15930
16575
  selectAttachmentsOfIssue,
15931
16576
  selectAttachmentsOfIssueByType,
15932
16577
  selectAttachmentsOfProject,
@@ -15944,11 +16589,9 @@ export {
15944
16589
  selectComponent,
15945
16590
  selectComponentAttachment,
15946
16591
  selectComponentAttachmentMapping,
15947
- selectComponentSubmissionMapping,
15948
16592
  selectComponentType,
15949
16593
  selectComponentTypeAttachment,
15950
16594
  selectComponentTypeAttachmentMapping,
15951
- selectComponentTypeForm,
15952
16595
  selectComponentTypeFromComponent,
15953
16596
  selectComponentTypeFromComponents,
15954
16597
  selectComponentTypeStagesMapping,
@@ -15978,8 +16621,24 @@ export {
15978
16621
  selectExpandedSections,
15979
16622
  selectFavouriteProjects,
15980
16623
  selectFileAttachmentsOfIssue,
15981
- selectFilteredUserForms,
16624
+ selectFilteredForms,
16625
+ selectForm,
16626
+ selectFormMapping,
16627
+ selectFormOfComponentType,
15982
16628
  selectFormRevision,
16629
+ selectFormRevisionMapping,
16630
+ selectFormRevisions,
16631
+ selectFormRevisionsOfForm,
16632
+ selectFormSubmission,
16633
+ selectFormSubmissionAttachmentsMapping,
16634
+ selectFormSubmissions,
16635
+ selectFormSubmissionsByComponents,
16636
+ selectFormSubmissionsMapping,
16637
+ selectFormSubmissionsOfComponent,
16638
+ selectFormSubmissionsOfForm,
16639
+ selectFormSubmissionsOfIssue,
16640
+ selectFormsCount,
16641
+ selectGeneralFormCount,
15983
16642
  selectHiddenCategoryCount,
15984
16643
  selectHiddenComponentTypeIds,
15985
16644
  selectIsFetchingInitialData,
@@ -15994,10 +16653,10 @@ export {
15994
16653
  selectIssueUpdateMapping,
15995
16654
  selectIssueUpdatesOfIssue,
15996
16655
  selectIssues,
15997
- selectLatestFormRevision,
16656
+ selectLatestFormRevisionByForm,
16657
+ selectLatestFormRevisionOfForm,
16658
+ selectLatestFormRevisionsOfComponentTypes,
15998
16659
  selectLatestRetryTime,
15999
- selectLatestRevisionByFormId,
16000
- selectLatestRevisionsFromComponentTypeIds,
16001
16660
  selectLicense,
16002
16661
  selectLicenseForProject,
16003
16662
  selectLicenses,
@@ -16006,8 +16665,6 @@ export {
16006
16665
  selectMapStyle,
16007
16666
  selectNumberOfComponentTypesMatchingCaseInsensitiveName,
16008
16667
  selectNumberOfComponentsOfComponentType,
16009
- selectNumberOfGeneralUserForms,
16010
- selectNumberOfUserForms,
16011
16668
  selectOrganization,
16012
16669
  selectOrganizationAccess,
16013
16670
  selectOrganizationAccessForUser,
@@ -16035,8 +16692,6 @@ export {
16035
16692
  selectRecentIssuesAsSearchResults,
16036
16693
  selectRecentProjects,
16037
16694
  selectRehydrated,
16038
- selectRevisionAttachments,
16039
- selectRevisionsForForm,
16040
16695
  selectRootDocuments,
16041
16696
  selectShowTooltips,
16042
16697
  selectSortedEmailDomains,
@@ -16051,16 +16706,15 @@ export {
16051
16706
  selectStagesFromComponentType,
16052
16707
  selectStagesFromComponentTypeIds,
16053
16708
  selectStagesFromStageIds,
16054
- selectSubmissionAttachments,
16055
- selectSubmissionsForComponent,
16056
- selectSubmissionsForForm,
16057
- selectSubmissionsForIssue,
16709
+ selectTeam,
16710
+ selectTeams,
16711
+ selectTeamsMapping,
16712
+ selectTeamsOfOrganization,
16713
+ selectTeamsOfUser,
16058
16714
  selectUploadUrl,
16059
16715
  selectUsedColors,
16060
16716
  selectUser,
16061
- selectUserForm,
16062
- selectUserFormMapping,
16063
- selectUserFormSubmission,
16717
+ selectUserFormRevisionAttachmentsMapping,
16064
16718
  selectUsersAsMapping,
16065
16719
  selectVisibleStatuses,
16066
16720
  selectVisibleUserIds,
@@ -16087,6 +16741,13 @@ export {
16087
16741
  setEnableClustering,
16088
16742
  setEnableDuplicateIssues,
16089
16743
  setEnablePlacementMode,
16744
+ setFormRevision,
16745
+ setFormRevisionAttachments,
16746
+ setFormRevisions,
16747
+ setFormSubmission,
16748
+ setFormSubmissionAttachments,
16749
+ setFormSubmissions,
16750
+ setForms,
16090
16751
  setIsFetchingInitialData,
16091
16752
  setIsImportingProjectFile,
16092
16753
  setIsLoading,
@@ -16108,12 +16769,11 @@ export {
16108
16769
  setSectionExpanded,
16109
16770
  setShowTooltips,
16110
16771
  setStageCompletions,
16772
+ setTeam,
16773
+ setTeams,
16111
16774
  setTokens,
16112
16775
  setTourStep,
16113
16776
  setUploadUrl,
16114
- setUserFormRevisionAttachments,
16115
- setUserFormSubmissionAttachments,
16116
- setUserFormSubmissions,
16117
16777
  setUsers,
16118
16778
  setVisibleStatuses,
16119
16779
  setVisibleUserIds,
@@ -16124,6 +16784,8 @@ export {
16124
16784
  slugify,
16125
16785
  spacesToDashesLower,
16126
16786
  successColor,
16787
+ teamReducer,
16788
+ teamSlice,
16127
16789
  toFileNameSafeString,
16128
16790
  toOfflineIdRecord,
16129
16791
  toggleComponentTypeVisibility,
@@ -16138,15 +16800,18 @@ export {
16138
16800
  updateComponentTypeAttachment,
16139
16801
  updateDocumentAttachment,
16140
16802
  updateDocuments,
16803
+ updateFormSubmission,
16804
+ updateFormSubmissionAttachments,
16805
+ updateFormSubmissions,
16141
16806
  updateIssue,
16142
16807
  updateIssueAttachment,
16143
16808
  updateLicense,
16144
16809
  updateOrCreateProject,
16145
- updateOrCreateUserFormSubmission,
16146
16810
  updateOrganizationAccess,
16147
16811
  updateProjectAccess,
16148
16812
  updateProjectAttachment,
16149
16813
  updateStages,
16814
+ updateTeam,
16150
16815
  useAppDispatch,
16151
16816
  useAppSelector,
16152
16817
  useFieldInput,
@@ -16156,8 +16821,6 @@ export {
16156
16821
  useFormikInput,
16157
16822
  useMemoCompare,
16158
16823
  useSDK,
16159
- userFormReducer,
16160
- userFormSlice,
16161
16824
  userReducer,
16162
16825
  userSlice,
16163
16826
  valueIsFile,