@overmap-ai/core 1.0.35-add-image-to-forms.16 → 1.0.35-add-image-to-forms.18

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.
@@ -30,7 +30,7 @@ export declare abstract class BaseField<TValue extends FieldValue, TIdentifier e
30
30
  private readonly formValidators;
31
31
  private readonly fieldValidators;
32
32
  readonly label: string;
33
- readonly image: File | undefined;
33
+ readonly image: File | Promise<File> | undefined;
34
34
  /**
35
35
  * By default, validation doesn't execute on `onChange` events when editing fields
36
36
  * until the field has been `touched`. This can be overridden by setting this to `false`
@@ -7,7 +7,7 @@ interface InputWithLabelProps {
7
7
  inputId: string;
8
8
  labelId: string;
9
9
  label: string;
10
- image: File | undefined;
10
+ image: File | Promise<File> | undefined;
11
11
  children: ReactNode;
12
12
  flexProps?: ComponentProps<typeof Flex>;
13
13
  }
@@ -19,7 +19,7 @@ export declare abstract class BaseSelectField<TValue extends FieldValue, TIdenti
19
19
  options: SelectFieldOption[];
20
20
  label: string;
21
21
  required: boolean;
22
- image?: File | undefined;
22
+ image?: File | Promise<File> | undefined;
23
23
  description?: string | null | undefined;
24
24
  identifier: string;
25
25
  type: TIdentifier;
@@ -25,7 +25,7 @@ export interface BaseSerializedObject<TIdentifier extends FieldTypeIdentifier =
25
25
  export interface BaseSerializedField<TIdentifier extends FieldTypeIdentifier = FieldTypeIdentifier> extends BaseSerializedObject<TIdentifier> {
26
26
  label: string;
27
27
  required: boolean;
28
- image?: File;
28
+ image?: File | Promise<File>;
29
29
  }
30
30
  /** All the possible field values */
31
31
  export type FieldValue = string | number | boolean | string[] | SelectFieldOption[] | File[] | Date | Marker | null;
@@ -2,6 +2,8 @@ import { FormikErrors } from "formik";
2
2
  import { BaseFormElement, ISchema } from "./fields";
3
3
  import { Form } from "./typings";
4
4
  import { FormikUserFormRevision } from "./builder";
5
+ import { UserFormRevision } from "../typings";
5
6
  export declare const hasKeys: (errors: object) => boolean;
6
7
  export declare const validateForm: (schema: ISchema, form: Form | FormikUserFormRevision) => FormikErrors<Form> | FormikErrors<import('./builder/typings').NewForm> | undefined;
7
8
  export declare const initialFormValues: (fields: BaseFormElement[], values: Form) => Form;
9
+ export declare const useAttachImagesToFormRevisionFields: (revision: UserFormRevision) => UserFormRevision;
@@ -5330,6 +5330,9 @@ const separateImageFromFields = (payload) => {
5330
5330
  const newSectionFields = [];
5331
5331
  for (const field of sectionFields) {
5332
5332
  if (field.image) {
5333
+ if (!(field.image instanceof File)) {
5334
+ throw new Error(`Expected image to be a File, got ${typeof field.image} instead.`);
5335
+ }
5333
5336
  images[field.identifier] = field.image;
5334
5337
  delete field.image;
5335
5338
  }
@@ -6859,16 +6862,24 @@ const FullScreenImagePreview = memo((props) => {
6859
6862
  FullScreenImagePreview.displayName = "FullScreenImagePreview";
6860
6863
  const InputWithLabel = (props) => {
6861
6864
  const { label, children, size, severity, inputId, labelId, image, flexProps } = props;
6865
+ const [resolvedImage, setResolvedImage] = useState(void 0);
6862
6866
  const [showImagePreview, setShowImagePreview] = useState(false);
6863
- const imageURL = image ? URL.createObjectURL(image) : void 0;
6867
+ useEffect(() => {
6868
+ if (image instanceof Promise) {
6869
+ image.then(setResolvedImage).catch(console.error);
6870
+ } else {
6871
+ setResolvedImage(image);
6872
+ }
6873
+ }, [image]);
6874
+ const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
6864
6875
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "2", ...flexProps, children: [
6865
- image && /* @__PURE__ */ jsxs(Fragment, { children: [
6876
+ resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
6866
6877
  /* @__PURE__ */ jsx(
6867
6878
  "img",
6868
6879
  {
6869
6880
  className: styles$6.previewImage,
6870
- src: imageURL,
6871
- alt: image.name,
6881
+ src: resolvedImageURL,
6882
+ alt: resolvedImage.name,
6872
6883
  onClick: () => {
6873
6884
  setShowImagePreview(true);
6874
6885
  }
@@ -6877,9 +6888,9 @@ const InputWithLabel = (props) => {
6877
6888
  showImagePreview && /* @__PURE__ */ jsx(
6878
6889
  FullScreenImagePreview,
6879
6890
  {
6880
- file: image,
6881
- url: imageURL,
6882
- name: image.name,
6891
+ file: resolvedImage,
6892
+ url: resolvedImageURL,
6893
+ name: resolvedImage.name,
6883
6894
  setShowPreview: setShowImagePreview
6884
6895
  }
6885
6896
  )
@@ -10112,6 +10123,24 @@ const initialFormValues = (fields, values) => {
10112
10123
  cloneDeep(values)
10113
10124
  );
10114
10125
  };
10126
+ const useAttachImagesToFormRevisionFields = (revision) => {
10127
+ const { sdk } = useSDK();
10128
+ const revisionCopy = JSON.parse(JSON.stringify(revision));
10129
+ const attachments = selectRevisionAttachments(revisionCopy.offline_id)(sdk.store.getState()) ?? [];
10130
+ for (const attachment of attachments) {
10131
+ const filePromise = sdk.files.fetchFileFromUrl(attachment.file, attachment.file_sha1, attachment.file_name);
10132
+ let sectionIndex = -1;
10133
+ let fieldIndex = -1;
10134
+ sectionIndex = revisionCopy.fields.findIndex((section) => {
10135
+ fieldIndex = section.fields.findIndex((field) => field.identifier === attachment.field_identifier);
10136
+ return fieldIndex !== -1;
10137
+ });
10138
+ if (sectionIndex !== -1 && fieldIndex !== -1) {
10139
+ set(revisionCopy, `fields[${sectionIndex}].fields[${fieldIndex}].image`, filePromise);
10140
+ }
10141
+ }
10142
+ return revisionCopy;
10143
+ };
10115
10144
  const defaultHandleSubmit = () => {
10116
10145
  throw new Error("onSubmit must be provided if form is not readonly.");
10117
10146
  };
@@ -10180,9 +10209,10 @@ const FormSubmissionViewer = memo(
10180
10209
  `Could not find revision ${submission.form_revision} for submission ${submission.offline_id}.`
10181
10210
  );
10182
10211
  }
10212
+ const revisionWithImages = useAttachImagesToFormRevisionFields(revision);
10183
10213
  const schema = useMemo(() => {
10184
- return formRevisionToSchema(revision, { readonly: true });
10185
- }, [revision]);
10214
+ return formRevisionToSchema(revisionWithImages, { readonly: true });
10215
+ }, [revisionWithImages]);
10186
10216
  const submissionValuesWithAttachments = useMemo(() => {
10187
10217
  const attachments = selectSubmissionAttachments(submission.offline_id)(sdk.store.getState()) ?? [];
10188
10218
  const downloadedAttachments = {};
@@ -10677,6 +10707,9 @@ const useFieldTypeItems = (onSelect = () => null) => {
10677
10707
  });
10678
10708
  }, [onSelect]);
10679
10709
  };
10710
+ const isSection = (field) => {
10711
+ return field.type === "section";
10712
+ };
10680
10713
  const FieldSettingsPopover = memo((props) => {
10681
10714
  const { popoverInputs, hasError } = props;
10682
10715
  return /* @__PURE__ */ jsx(
@@ -10706,6 +10739,8 @@ FieldSettingsPopover.displayName = "FieldSettingsPopover";
10706
10739
  const FieldBuilder = memo((props) => {
10707
10740
  var _a2, _b, _c, _d, _e, _f;
10708
10741
  const { parentPath, index: index2, initial, conditionalSourceFields } = props;
10742
+ const { values, setFieldValue, errors } = useFormikContext();
10743
+ const fieldTypeItems = useFieldTypeItems();
10709
10744
  const RADIX_SM_MIN_WIDTH = 576;
10710
10745
  const [isLargeScreen, setIsLargeScreen] = useState(
10711
10746
  window.matchMedia(`(min-width: ${RADIX_SM_MIN_WIDTH}px)`).matches
@@ -10720,23 +10755,38 @@ const FieldBuilder = memo((props) => {
10720
10755
  mediaQuery.removeEventListener("change", handleMediaQueryChange);
10721
10756
  };
10722
10757
  }, []);
10758
+ const [resolvedImage, setResolvedImage] = useState(void 0);
10723
10759
  const [showImagePreview, setShowImagePreview] = useState(false);
10724
- const { values, setFieldValue, errors } = useFormikContext();
10725
- const fieldTypeItems = useFieldTypeItems();
10726
- const isSection = useCallback((field) => {
10727
- return field.type === "section";
10728
- }, []);
10760
+ useEffect(() => {
10761
+ if (!isSection(initial)) {
10762
+ if (initial.image instanceof Promise) {
10763
+ initial.image.then(setResolvedImage).catch(console.error);
10764
+ } else {
10765
+ setResolvedImage(initial.image);
10766
+ }
10767
+ } else {
10768
+ setResolvedImage(void 0);
10769
+ }
10770
+ }, [initial]);
10771
+ const resolvedImageURL = resolvedImage ? URL.createObjectURL(resolvedImage) : void 0;
10772
+ const handleImageDelete = useCallback(
10773
+ (event) => {
10774
+ event.stopPropagation();
10775
+ void setFieldValue(`${parentPath}.${index2}.image`, null).then();
10776
+ },
10777
+ [index2, parentPath, setFieldValue]
10778
+ );
10729
10779
  useEffect(() => {
10730
10780
  if (isSection(initial) && !initial.conditional) {
10731
10781
  void setFieldValue(`${parentPath}.${index2}.condition`, null).then();
10732
10782
  }
10733
- }, [index2, initial, isSection, parentPath, setFieldValue]);
10783
+ }, [index2, initial, parentPath, setFieldValue]);
10734
10784
  const conditionLabel = useMemo(
10735
10785
  () => {
10736
10786
  var _a3, _b2;
10737
10787
  return isSection(initial) ? (_b2 = findFieldByIdentifier(values.fields, (_a3 = initial.condition) == null ? void 0 : _a3.identifier)) == null ? void 0 : _b2.label : void 0;
10738
10788
  },
10739
- [initial, isSection, values.fields]
10789
+ [initial, values.fields]
10740
10790
  );
10741
10791
  const conditionComparison = isSection(initial) ? Array.isArray((_a2 = initial.condition) == null ? void 0 : _a2.value) ? "contains all of" : "equals" : void 0;
10742
10792
  let conditionValue = void 0;
@@ -10746,17 +10796,6 @@ const FieldBuilder = memo((props) => {
10746
10796
  }
10747
10797
  conditionValue = Array.isArray((_c = initial.condition) == null ? void 0 : _c.value) ? initial.condition.value.map((v) => typeof v === "string" ? v : v.label).join(", ") : (_e = (_d = initial.condition) == null ? void 0 : _d.value) == null ? void 0 : _e.toString();
10748
10798
  }
10749
- let imageURL = void 0;
10750
- if (!isSection(initial) && initial.image) {
10751
- imageURL = URL.createObjectURL(initial.image);
10752
- }
10753
- const handleImageDelete = useCallback(
10754
- (event) => {
10755
- event.stopPropagation();
10756
- void setFieldValue(`${parentPath}.${index2}.image`, null).then();
10757
- },
10758
- [index2, parentPath, setFieldValue]
10759
- );
10760
10799
  const handleInputChangeForInput = useCallback((event) => {
10761
10800
  if (event.target.parentNode instanceof HTMLElement) {
10762
10801
  event.target.parentNode.dataset.replicatedValue = event.target.value;
@@ -10859,14 +10898,14 @@ const FieldBuilder = memo((props) => {
10859
10898
  /* @__PURE__ */ jsx(Badge, { className: styles.typeBadge, children: (_f = fieldTypeItems.flat().find((item) => item.value === type)) == null ? void 0 : _f.content }),
10860
10899
  showPopoverInputs && /* @__PURE__ */ jsx(FieldSettingsPopover, { popoverInputs, hasError: popoverHasErrors })
10861
10900
  ] }),
10862
- !isSection(initial) && initial.image && /* @__PURE__ */ jsxs(Fragment, { children: [
10901
+ resolvedImage && /* @__PURE__ */ jsxs(Fragment, { children: [
10863
10902
  /* @__PURE__ */ jsxs("div", { className: styles.imageContainer, children: [
10864
10903
  /* @__PURE__ */ jsx(
10865
10904
  "img",
10866
10905
  {
10867
10906
  className: styles.previewImage,
10868
- src: imageURL,
10869
- alt: initial.image.name,
10907
+ src: resolvedImageURL,
10908
+ alt: resolvedImage.name,
10870
10909
  onClick: () => {
10871
10910
  setShowImagePreview(true);
10872
10911
  }
@@ -10887,9 +10926,9 @@ const FieldBuilder = memo((props) => {
10887
10926
  showImagePreview && /* @__PURE__ */ jsx(
10888
10927
  FullScreenImagePreview,
10889
10928
  {
10890
- file: initial.image,
10891
- url: imageURL,
10892
- name: initial.image.name,
10929
+ file: resolvedImage,
10930
+ url: resolvedImageURL,
10931
+ name: resolvedImage.name,
10893
10932
  setShowPreview: setShowImagePreview
10894
10933
  }
10895
10934
  )