@oneblink/apps-react 6.8.0 → 6.9.0-beta.2

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.
@@ -1,11 +1,11 @@
1
1
  import * as React from 'react';
2
- declare const _default: React.MemoExoticComponent<({ isUploading, isUploadPaused, uploadError, loadImageUrlError, isLoadingImageUrl, imageUrl, progress, }: {
2
+ declare const _default: React.MemoExoticComponent<({ isUploading, isUploadPaused, uploadError, loadAttachmentUrlError, isLoadingAttachmentUrl, attachmentUrl, progress, }: {
3
3
  isUploading?: boolean | undefined;
4
4
  isUploadPaused?: boolean | undefined;
5
5
  uploadError?: Error | undefined;
6
- loadImageUrlError?: Error | undefined;
7
- isLoadingImageUrl?: boolean | undefined;
8
- imageUrl: string | null | undefined;
6
+ loadAttachmentUrlError?: Error | undefined;
7
+ isLoadingAttachmentUrl?: boolean | undefined;
8
+ attachmentUrl: string | null | undefined;
9
9
  progress: number | undefined;
10
10
  }) => React.JSX.Element>;
11
11
  export default _default;
@@ -2,17 +2,17 @@ import * as React from 'react';
2
2
  import Tooltip from '../Tooltip';
3
3
  import useIsOffline from '../../../hooks/useIsOffline';
4
4
  import MaterialIcon from '../../MaterialIcon';
5
- const AttachmentStatus = ({ isUploading, isUploadPaused, uploadError, loadImageUrlError, isLoadingImageUrl, imageUrl, progress, }) => {
5
+ const AttachmentStatus = ({ isUploading, isUploadPaused, uploadError, loadAttachmentUrlError, isLoadingAttachmentUrl, attachmentUrl, progress, }) => {
6
6
  const isOffline = useIsOffline();
7
7
  const tooltip = React.useMemo(() => {
8
- if (isLoadingImageUrl && !imageUrl) {
8
+ if (isLoadingAttachmentUrl && !attachmentUrl) {
9
9
  return 'Attempting to load file preview. File is synced with submission.';
10
10
  }
11
- if (loadImageUrlError && !imageUrl) {
11
+ if (loadAttachmentUrlError && !attachmentUrl) {
12
12
  return 'File preview not available, however file is synced with submission.';
13
13
  }
14
14
  return 'Synced with submission.';
15
- }, [imageUrl, isLoadingImageUrl, loadImageUrlError]);
15
+ }, [attachmentUrl, isLoadingAttachmentUrl, loadAttachmentUrlError]);
16
16
  if (uploadError) {
17
17
  return (React.createElement(Tooltip, { title: uploadError.message, role: "alert" },
18
18
  React.createElement("span", { className: "attachment__status-wrapper" },
@@ -1 +1 @@
1
- {"version":3,"file":"AttachmentStatus.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/AttachmentStatus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,YAAY,MAAM,6BAA6B,CAAA;AACtD,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAE7C,MAAM,gBAAgB,GAAG,CAAC,EACxB,WAAW,EACX,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,EACR,QAAQ,GAST,EAAE,EAAE;IACH,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACjC,IAAI,iBAAiB,IAAI,CAAC,QAAQ,EAAE;YAClC,OAAO,kEAAkE,CAAA;SAC1E;QACD,IAAI,iBAAiB,IAAI,CAAC,QAAQ,EAAE;YAClC,OAAO,qEAAqE,CAAA;SAC7E;QAED,OAAO,yBAAyB,CAAA;IAClC,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAEpD,IAAI,WAAW,EAAE;QACf,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,EAAC,OAAO;YAC/C,8BAAM,SAAS,EAAC,4BAA4B;gBAC1C,oBAAC,YAAY,IAAC,SAAS,EAAC,iBAAiB,YAAqB,CACzD,CACC,CACX,CAAA;KACF;IAED,IAAI,WAAW,EAAE;QACf,IAAI,cAAc,EAAE;YAClB,OAAO,CACL,8BAAM,SAAS,EAAC,4BAA4B;gBAC1C,oBAAC,YAAY,gBAAqB,CAC7B,CACR,CAAA;SACF;QACD,IAAI,SAAS,EAAE;YACb,OAAO,CACL,oBAAC,OAAO,IACN,KAAK,EAAC,oDAAoD,EAC1D,IAAI,EAAC,OAAO;gBAEZ,6BAAK,SAAS,EAAC,8BAA8B;oBAC3C,oBAAC,YAAY,IAAC,SAAS,EAAC,kBAAkB,eAAwB,CAC9D,CACE,CACX,CAAA;SACF;QACD,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAC,WAAW;YACxB,6BAAK,SAAS,EAAC,8BAA8B,EAAC,IAAI,EAAC,aAAa;gBAC7D,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;oBACtB,CACE,CACX,CAAA;KACF;IAED,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAE,OAAO;QACrB,8BAAM,SAAS,EAAC,4BAA4B;YAC1C,oBAAC,YAAY,IACX,SAAS,EAAC,kBAAkB,EAC5B,IAAI,EAAC,QAAQ,gBACF,mBAAmB,mBAGjB,CACV,CACC,CACX,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport Tooltip from '../Tooltip'\nimport useIsOffline from '../../../hooks/useIsOffline'\nimport MaterialIcon from '../../MaterialIcon'\n\nconst AttachmentStatus = ({\n isUploading,\n isUploadPaused,\n uploadError,\n loadImageUrlError,\n isLoadingImageUrl,\n imageUrl,\n progress,\n}: {\n isUploading?: boolean\n isUploadPaused?: boolean\n uploadError?: Error\n loadImageUrlError?: Error\n isLoadingImageUrl?: boolean\n imageUrl: string | null | undefined\n progress: number | undefined\n}) => {\n const isOffline = useIsOffline()\n\n const tooltip = React.useMemo(() => {\n if (isLoadingImageUrl && !imageUrl) {\n return 'Attempting to load file preview. File is synced with submission.'\n }\n if (loadImageUrlError && !imageUrl) {\n return 'File preview not available, however file is synced with submission.'\n }\n\n return 'Synced with submission.'\n }, [imageUrl, isLoadingImageUrl, loadImageUrlError])\n\n if (uploadError) {\n return (\n <Tooltip title={uploadError.message} role=\"alert\">\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon className=\"has-text-danger\">error</MaterialIcon>\n </span>\n </Tooltip>\n )\n }\n\n if (isUploading) {\n if (isUploadPaused) {\n return (\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon>pause</MaterialIcon>\n </span>\n )\n }\n if (isOffline) {\n return (\n <Tooltip\n title=\"Upload will start when you connect to the internet\"\n role=\"alert\"\n >\n <div className=\"cypress-attachment-uploading\">\n <MaterialIcon className=\"has-text-warning\">wifi_off</MaterialIcon>\n </div>\n </Tooltip>\n )\n }\n return (\n <Tooltip title=\"Uploading\">\n <div className=\"cypress-attachment-uploading\" role=\"progressbar\">\n {Math.round(progress || 0)}%\n </div>\n </Tooltip>\n )\n }\n\n return (\n <Tooltip title={tooltip}>\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon\n className=\"has-text-success\"\n role=\"status\"\n aria-label=\"upload successful\"\n >\n check_circle\n </MaterialIcon>\n </span>\n </Tooltip>\n )\n}\n\nexport default React.memo(AttachmentStatus)\n"]}
1
+ {"version":3,"file":"AttachmentStatus.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/AttachmentStatus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,YAAY,MAAM,6BAA6B,CAAA;AACtD,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAE7C,MAAM,gBAAgB,GAAG,CAAC,EACxB,WAAW,EACX,cAAc,EACd,WAAW,EACX,sBAAsB,EACtB,sBAAsB,EACtB,aAAa,EACb,QAAQ,GAST,EAAE,EAAE;IACH,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACjC,IAAI,sBAAsB,IAAI,CAAC,aAAa,EAAE;YAC5C,OAAO,kEAAkE,CAAA;SAC1E;QACD,IAAI,sBAAsB,IAAI,CAAC,aAAa,EAAE;YAC5C,OAAO,qEAAqE,CAAA;SAC7E;QAED,OAAO,yBAAyB,CAAA;IAClC,CAAC,EAAE,CAAC,aAAa,EAAE,sBAAsB,EAAE,sBAAsB,CAAC,CAAC,CAAA;IAEnE,IAAI,WAAW,EAAE;QACf,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAE,WAAW,CAAC,OAAO,EAAE,IAAI,EAAC,OAAO;YAC/C,8BAAM,SAAS,EAAC,4BAA4B;gBAC1C,oBAAC,YAAY,IAAC,SAAS,EAAC,iBAAiB,YAAqB,CACzD,CACC,CACX,CAAA;KACF;IAED,IAAI,WAAW,EAAE;QACf,IAAI,cAAc,EAAE;YAClB,OAAO,CACL,8BAAM,SAAS,EAAC,4BAA4B;gBAC1C,oBAAC,YAAY,gBAAqB,CAC7B,CACR,CAAA;SACF;QACD,IAAI,SAAS,EAAE;YACb,OAAO,CACL,oBAAC,OAAO,IACN,KAAK,EAAC,oDAAoD,EAC1D,IAAI,EAAC,OAAO;gBAEZ,6BAAK,SAAS,EAAC,8BAA8B;oBAC3C,oBAAC,YAAY,IAAC,SAAS,EAAC,kBAAkB,eAAwB,CAC9D,CACE,CACX,CAAA;SACF;QACD,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAC,WAAW;YACxB,6BAAK,SAAS,EAAC,8BAA8B,EAAC,IAAI,EAAC,aAAa;gBAC7D,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;oBACtB,CACE,CACX,CAAA;KACF;IAED,OAAO,CACL,oBAAC,OAAO,IAAC,KAAK,EAAE,OAAO;QACrB,8BAAM,SAAS,EAAC,4BAA4B;YAC1C,oBAAC,YAAY,IACX,SAAS,EAAC,kBAAkB,EAC5B,IAAI,EAAC,QAAQ,gBACF,mBAAmB,mBAGjB,CACV,CACC,CACX,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport Tooltip from '../Tooltip'\nimport useIsOffline from '../../../hooks/useIsOffline'\nimport MaterialIcon from '../../MaterialIcon'\n\nconst AttachmentStatus = ({\n isUploading,\n isUploadPaused,\n uploadError,\n loadAttachmentUrlError,\n isLoadingAttachmentUrl,\n attachmentUrl,\n progress,\n}: {\n isUploading?: boolean\n isUploadPaused?: boolean\n uploadError?: Error\n loadAttachmentUrlError?: Error\n isLoadingAttachmentUrl?: boolean\n attachmentUrl: string | null | undefined\n progress: number | undefined\n}) => {\n const isOffline = useIsOffline()\n\n const tooltip = React.useMemo(() => {\n if (isLoadingAttachmentUrl && !attachmentUrl) {\n return 'Attempting to load file preview. File is synced with submission.'\n }\n if (loadAttachmentUrlError && !attachmentUrl) {\n return 'File preview not available, however file is synced with submission.'\n }\n\n return 'Synced with submission.'\n }, [attachmentUrl, isLoadingAttachmentUrl, loadAttachmentUrlError])\n\n if (uploadError) {\n return (\n <Tooltip title={uploadError.message} role=\"alert\">\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon className=\"has-text-danger\">error</MaterialIcon>\n </span>\n </Tooltip>\n )\n }\n\n if (isUploading) {\n if (isUploadPaused) {\n return (\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon>pause</MaterialIcon>\n </span>\n )\n }\n if (isOffline) {\n return (\n <Tooltip\n title=\"Upload will start when you connect to the internet\"\n role=\"alert\"\n >\n <div className=\"cypress-attachment-uploading\">\n <MaterialIcon className=\"has-text-warning\">wifi_off</MaterialIcon>\n </div>\n </Tooltip>\n )\n }\n return (\n <Tooltip title=\"Uploading\">\n <div className=\"cypress-attachment-uploading\" role=\"progressbar\">\n {Math.round(progress || 0)}%\n </div>\n </Tooltip>\n )\n }\n\n return (\n <Tooltip title={tooltip}>\n <span className=\"attachment__status-wrapper\">\n <MaterialIcon\n className=\"has-text-success\"\n role=\"status\"\n aria-label=\"upload successful\"\n >\n check_circle\n </MaterialIcon>\n </span>\n </Tooltip>\n )\n}\n\nexport default React.memo(AttachmentStatus)\n"]}
@@ -5,6 +5,7 @@ interface Props {
5
5
  onRemove: () => void;
6
6
  onDownload?: () => void;
7
7
  onRetry?: () => void;
8
+ attachmentUrl: string | null | undefined;
8
9
  }
9
10
  declare const _default: React.NamedExoticComponent<Props>;
10
11
  export default _default;
@@ -3,7 +3,7 @@ import clsx from 'clsx';
3
3
  import useBooleanState from '../../../hooks/useBooleanState';
4
4
  import useClickOutsideElement from '../../../hooks/useClickOutsideElement';
5
5
  import MaterialIcon from '../../MaterialIcon';
6
- const DropdownMenu = ({ element, onRemove, onDownload, onRetry }) => {
6
+ const DropdownMenu = ({ element, onRemove, onDownload, onRetry, attachmentUrl, }) => {
7
7
  const dropDownRef = React.useRef(null);
8
8
  const [isShowingMore, showMore, hideMore] = useBooleanState(false);
9
9
  useClickOutsideElement(dropDownRef, React.useCallback(() => {
@@ -27,6 +27,13 @@ const DropdownMenu = ({ element, onRemove, onDownload, onRetry }) => {
27
27
  hideMore();
28
28
  onDownload();
29
29
  }, role: "menuitem" }, "Download")),
30
+ attachmentUrl && (React.createElement("a", { href: attachmentUrl || '', target: "_blank", rel: "noreferrer", className: "dropdown-item cypress-file-open-button", style: {
31
+ display: 'flex',
32
+ alignItems: 'center',
33
+ gap: 2,
34
+ } },
35
+ "Open ",
36
+ React.createElement(MaterialIcon, { fontSize: "small" }, "open_in_new"))),
30
37
  React.createElement("a", { className: clsx('dropdown-item cypress-file-remove-button', {
31
38
  'ob-files__menu-remove-hidden': element.readOnly,
32
39
  }), onClick: () => {
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/DropdownMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,eAAe,MAAM,gCAAgC,CAAA;AAC5D,OAAO,sBAAsB,MAAM,uCAAuC,CAAA;AAC1E,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAS7C,MAAM,YAAY,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAS,EAAE,EAAE;IACzE,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACtC,MAAM,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IAElE,sBAAsB,CACpB,WAAW,EACX,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACrB,IAAI,aAAa,EAAE;YACjB,QAAQ,EAAE,CAAA;SACX;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAC9B,CAAA;IAED,OAAO,CACL,6BACE,SAAS,EAAE,IAAI,CAAC,kCAAkC,EAAE;YAClD,WAAW,EAAE,aAAa;SAC3B,CAAC,EACF,GAAG,EAAE,WAAW;QAEhB,6BAAK,SAAS,EAAC,kBAAkB;YAC/B,gCACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,uDAAuD,mBACnD,MAAM,mBACN,eAAe,EAC7B,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAE5C,oBAAC,YAAY,IAAC,SAAS,EAAC,qBAAqB,gBAAyB,CAC/D,CACL;QACN,6BAAK,SAAS,EAAC,eAAe,EAAC,IAAI,EAAC,MAAM;YACxC,6BAAK,SAAS,EAAC,kBAAkB;gBAC9B,OAAO,IAAI,CACV,2BACE,SAAS,EAAC,yCAAyC,EACnD,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,OAAO,EAAE,CAAA;oBACX,CAAC,EACD,IAAI,EAAC,UAAU,YAGb,CACL;gBACA,UAAU,IAAI,CACb,2BACE,SAAS,EAAC,4CAA4C,EACtD,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,UAAU,EAAE,CAAA;oBACd,CAAC,EACD,IAAI,EAAC,UAAU,eAGb,CACL;gBACD,2BACE,SAAS,EAAE,IAAI,CAAC,0CAA0C,EAAE;wBAC1D,8BAA8B,EAAE,OAAO,CAAC,QAAQ;qBACjD,CAAC,EACF,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,QAAQ,EAAE,CAAA;oBACZ,CAAC,EACD,IAAI,EAAC,UAAU,aAGb,CACA,CACF,CACF,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAQ,YAAY,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport clsx from 'clsx'\nimport { FormTypes } from '@oneblink/types'\nimport useBooleanState from '../../../hooks/useBooleanState'\nimport useClickOutsideElement from '../../../hooks/useClickOutsideElement'\nimport MaterialIcon from '../../MaterialIcon'\n\ninterface Props {\n element: FormTypes.FilesElement\n onRemove: () => void\n onDownload?: () => void\n onRetry?: () => void\n}\n\nconst DropdownMenu = ({ element, onRemove, onDownload, onRetry }: Props) => {\n const dropDownRef = React.useRef(null)\n const [isShowingMore, showMore, hideMore] = useBooleanState(false)\n\n useClickOutsideElement(\n dropDownRef,\n React.useCallback(() => {\n if (isShowingMore) {\n hideMore()\n }\n }, [hideMore, isShowingMore]),\n )\n\n return (\n <div\n className={clsx('dropdown is-right ob-files__menu', {\n 'is-active': isShowingMore,\n })}\n ref={dropDownRef}\n >\n <div className=\"dropdown-trigger\">\n <button\n type=\"button\"\n className=\"button ob-files__menu-button cypress-file-menu-button\"\n aria-haspopup=\"true\"\n aria-controls=\"dropdown-menu\"\n onClick={isShowingMore ? hideMore : showMore}\n >\n <MaterialIcon className=\"ob-files__menu-icon\">more_vert</MaterialIcon>\n </button>\n </div>\n <div className=\"dropdown-menu\" role=\"menu\">\n <div className=\"dropdown-content\">\n {onRetry && (\n <a\n className=\"dropdown-item cypress-file-retry-button\"\n onClick={() => {\n hideMore()\n onRetry()\n }}\n role=\"menuitem\"\n >\n Retry\n </a>\n )}\n {onDownload && (\n <a\n className=\"dropdown-item cypress-file-download-button\"\n onClick={() => {\n hideMore()\n onDownload()\n }}\n role=\"menuitem\"\n >\n Download\n </a>\n )}\n <a\n className={clsx('dropdown-item cypress-file-remove-button', {\n 'ob-files__menu-remove-hidden': element.readOnly,\n })}\n onClick={() => {\n hideMore()\n onRemove()\n }}\n role=\"menuitem\"\n >\n Remove\n </a>\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo<Props>(DropdownMenu)\n"]}
1
+ {"version":3,"file":"DropdownMenu.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/DropdownMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,OAAO,eAAe,MAAM,gCAAgC,CAAA;AAC5D,OAAO,sBAAsB,MAAM,uCAAuC,CAAA;AAC1E,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAU7C,MAAM,YAAY,GAAG,CAAC,EACpB,OAAO,EACP,QAAQ,EACR,UAAU,EACV,OAAO,EACP,aAAa,GACP,EAAE,EAAE;IACV,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACtC,MAAM,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IAElE,sBAAsB,CACpB,WAAW,EACX,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QACrB,IAAI,aAAa,EAAE;YACjB,QAAQ,EAAE,CAAA;SACX;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAC9B,CAAA;IAED,OAAO,CACL,6BACE,SAAS,EAAE,IAAI,CAAC,kCAAkC,EAAE;YAClD,WAAW,EAAE,aAAa;SAC3B,CAAC,EACF,GAAG,EAAE,WAAW;QAEhB,6BAAK,SAAS,EAAC,kBAAkB;YAC/B,gCACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,uDAAuD,mBACnD,MAAM,mBACN,eAAe,EAC7B,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAE5C,oBAAC,YAAY,IAAC,SAAS,EAAC,qBAAqB,gBAAyB,CAC/D,CACL;QACN,6BAAK,SAAS,EAAC,eAAe,EAAC,IAAI,EAAC,MAAM;YACxC,6BAAK,SAAS,EAAC,kBAAkB;gBAC9B,OAAO,IAAI,CACV,2BACE,SAAS,EAAC,yCAAyC,EACnD,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,OAAO,EAAE,CAAA;oBACX,CAAC,EACD,IAAI,EAAC,UAAU,YAGb,CACL;gBACA,UAAU,IAAI,CACb,2BACE,SAAS,EAAC,4CAA4C,EACtD,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,UAAU,EAAE,CAAA;oBACd,CAAC,EACD,IAAI,EAAC,UAAU,eAGb,CACL;gBACA,aAAa,IAAI,CAChB,2BACE,IAAI,EAAE,aAAa,IAAI,EAAE,EACzB,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,wCAAwC,EAClD,KAAK,EAAE;wBACL,OAAO,EAAE,MAAM;wBACf,UAAU,EAAE,QAAQ;wBACpB,GAAG,EAAE,CAAC;qBACP;;oBAEI,oBAAC,YAAY,IAAC,QAAQ,EAAC,OAAO,kBAA2B,CAC5D,CACL;gBACD,2BACE,SAAS,EAAE,IAAI,CAAC,0CAA0C,EAAE;wBAC1D,8BAA8B,EAAE,OAAO,CAAC,QAAQ;qBACjD,CAAC,EACF,OAAO,EAAE,GAAG,EAAE;wBACZ,QAAQ,EAAE,CAAA;wBACV,QAAQ,EAAE,CAAA;oBACZ,CAAC,EACD,IAAI,EAAC,UAAU,aAGb,CACA,CACF,CACF,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAQ,YAAY,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport clsx from 'clsx'\nimport { FormTypes } from '@oneblink/types'\nimport useBooleanState from '../../../hooks/useBooleanState'\nimport useClickOutsideElement from '../../../hooks/useClickOutsideElement'\nimport MaterialIcon from '../../MaterialIcon'\n\ninterface Props {\n element: FormTypes.FilesElement\n onRemove: () => void\n onDownload?: () => void\n onRetry?: () => void\n attachmentUrl: string | null | undefined\n}\n\nconst DropdownMenu = ({\n element,\n onRemove,\n onDownload,\n onRetry,\n attachmentUrl,\n}: Props) => {\n const dropDownRef = React.useRef(null)\n const [isShowingMore, showMore, hideMore] = useBooleanState(false)\n\n useClickOutsideElement(\n dropDownRef,\n React.useCallback(() => {\n if (isShowingMore) {\n hideMore()\n }\n }, [hideMore, isShowingMore]),\n )\n\n return (\n <div\n className={clsx('dropdown is-right ob-files__menu', {\n 'is-active': isShowingMore,\n })}\n ref={dropDownRef}\n >\n <div className=\"dropdown-trigger\">\n <button\n type=\"button\"\n className=\"button ob-files__menu-button cypress-file-menu-button\"\n aria-haspopup=\"true\"\n aria-controls=\"dropdown-menu\"\n onClick={isShowingMore ? hideMore : showMore}\n >\n <MaterialIcon className=\"ob-files__menu-icon\">more_vert</MaterialIcon>\n </button>\n </div>\n <div className=\"dropdown-menu\" role=\"menu\">\n <div className=\"dropdown-content\">\n {onRetry && (\n <a\n className=\"dropdown-item cypress-file-retry-button\"\n onClick={() => {\n hideMore()\n onRetry()\n }}\n role=\"menuitem\"\n >\n Retry\n </a>\n )}\n {onDownload && (\n <a\n className=\"dropdown-item cypress-file-download-button\"\n onClick={() => {\n hideMore()\n onDownload()\n }}\n role=\"menuitem\"\n >\n Download\n </a>\n )}\n {attachmentUrl && (\n <a\n href={attachmentUrl || ''}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"dropdown-item cypress-file-open-button\"\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 2,\n }}\n >\n Open <MaterialIcon fontSize=\"small\">open_in_new</MaterialIcon>\n </a>\n )}\n <a\n className={clsx('dropdown-item cypress-file-remove-button', {\n 'ob-files__menu-remove-hidden': element.readOnly,\n })}\n onClick={() => {\n hideMore()\n onRemove()\n }}\n role=\"menuitem\"\n >\n Remove\n </a>\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo<Props>(DropdownMenu)\n"]}
@@ -5,16 +5,17 @@ type Props = {
5
5
  isUploading?: boolean;
6
6
  isUploadPaused?: boolean;
7
7
  uploadErrorMessage?: string;
8
- loadImageUrlError?: Error;
9
- isLoadingImageUrl?: boolean;
8
+ loadAttachmentUrlError?: Error;
9
+ isLoadingAttachmentUrl?: boolean;
10
+ isContentTypeImage?: boolean;
10
11
  fileName: string;
11
- imageUrl: string | undefined | null;
12
+ attachmentUrl: string | undefined | null;
12
13
  onRemove: () => void;
13
14
  onDownload?: () => void;
14
15
  onRetry?: () => void;
15
16
  progress: undefined | number;
16
17
  index: number;
17
18
  };
18
- declare function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadImageUrlError, isLoadingImageUrl, imageUrl, fileName, onDownload, onRemove, onRetry, progress, index, }: Props): React.JSX.Element;
19
+ declare function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, progress, index, }: Props): React.JSX.Element;
19
20
  declare const _default: React.MemoExoticComponent<typeof FileCard>;
20
21
  export default _default;
@@ -4,7 +4,7 @@ import AttachmentStatus from './AttachmentStatus';
4
4
  import { checkFileNameIsValid, checkFileNameExtensionIsValid, } from '../../../services/form-validation';
5
5
  import ProgressBar from './ProgressBar';
6
6
  import DropdownMenu from './DropdownMenu';
7
- function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadImageUrlError, isLoadingImageUrl, imageUrl, fileName, onDownload, onRemove, onRetry, progress, index, }) {
7
+ function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, progress, index, }) {
8
8
  const uploadError = React.useMemo(() => {
9
9
  if (!checkFileNameIsValid(element, fileName)) {
10
10
  return new Error(`${fileName.split('.').pop()} files are not allowed`);
@@ -19,11 +19,12 @@ function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, lo
19
19
  return (React.createElement("div", { className: "column is-one-quarter-ob" },
20
20
  React.createElement("div", { className: "ob-files__box" },
21
21
  React.createElement("div", { className: "ob-files__content" },
22
- React.createElement(FileCardContent, { imageUrl: imageUrl, alt: `${element.label}: Attachment ${index + 1}` })),
23
- React.createElement(DropdownMenu, { element: element, onDownload: onDownload, onRetry: onRetry, onRemove: onRemove }),
22
+ React.createElement("a", { href: attachmentUrl || '', target: "_blank", rel: "noreferrer", className: "dropdown-item cypress-file-download-button", style: { pointerEvents: attachmentUrl ? 'auto' : 'none' } },
23
+ React.createElement(FileCardContent, { attachmentUrl: attachmentUrl, alt: `${element.label}: Attachment ${index + 1}`, isContentTypeImage: isContentTypeImage }))),
24
+ React.createElement(DropdownMenu, { element: element, onDownload: onDownload, onRetry: onRetry, onRemove: onRemove, attachmentUrl: attachmentUrl || '' }),
24
25
  React.createElement("div", { className: "ob-files__file-name is-size-6" },
25
26
  React.createElement("span", { className: "ob-files__file-name-inner" }, fileName),
26
- React.createElement(AttachmentStatus, { isUploading: isUploading, isUploadPaused: isUploadPaused, uploadError: uploadError, loadImageUrlError: loadImageUrlError, isLoadingImageUrl: isLoadingImageUrl, imageUrl: imageUrl, progress: progress }),
27
+ React.createElement(AttachmentStatus, { isUploading: isUploading, isUploadPaused: isUploadPaused, uploadError: uploadError, loadAttachmentUrlError: loadAttachmentUrlError, isLoadingAttachmentUrl: isLoadingAttachmentUrl, attachmentUrl: attachmentUrl, progress: progress }),
27
28
  React.createElement(ProgressBar, { progress: progress, isShowing: !!isUploading })))));
28
29
  }
29
30
  export default React.memo(FileCard);
@@ -1 +1 @@
1
- {"version":3,"file":"FileCard.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/FileCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,eAAe,MAAM,mBAAmB,CAAA;AAC/C,OAAO,gBAAgB,MAAM,oBAAoB,CAAA;AACjD,OAAO,EACL,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,WAAW,MAAM,eAAe,CAAA;AACvC,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAkBzC,SAAS,QAAQ,CAAC,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAAK,GACC;IACN,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;YAC5C,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;SACvE;QACD,IAAI,CAAC,6BAA6B,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;YACrD,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,yBAAyB,CAAC,CAAA;SACvD;QACD,IAAI,kBAAkB,EAAE;YACtB,OAAO,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;SACrC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAA;IAE3C,OAAO,CACL,6BAAK,SAAS,EAAC,0BAA0B;QACvC,6BAAK,SAAS,EAAC,eAAe;YAC5B,6BAAK,SAAS,EAAC,mBAAmB;gBAChC,oBAAC,eAAe,IACd,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,gBAAgB,KAAK,GAAG,CAAC,EAAE,GAChD,CACE;YACN,oBAAC,YAAY,IACX,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,GAClB;YAEF,6BAAK,SAAS,EAAC,+BAA+B;gBAC5C,8BAAM,SAAS,EAAC,2BAA2B,IAAE,QAAQ,CAAQ;gBAC7D,oBAAC,gBAAgB,IACf,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,iBAAiB,EAAE,iBAAiB,EACpC,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,GAClB;gBACF,oBAAC,WAAW,IAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,WAAW,GAAI,CACzD,CACF,CACF,CACP,CAAA;AACH,CAAC;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport { FormTypes } from '@oneblink/types'\nimport FileCardContent from './FileCardContent'\nimport AttachmentStatus from './AttachmentStatus'\nimport {\n checkFileNameIsValid,\n checkFileNameExtensionIsValid,\n} from '../../../services/form-validation'\nimport ProgressBar from './ProgressBar'\nimport DropdownMenu from './DropdownMenu'\n\ntype Props = {\n element: FormTypes.FilesElement\n isUploading?: boolean\n isUploadPaused?: boolean\n uploadErrorMessage?: string\n loadImageUrlError?: Error\n isLoadingImageUrl?: boolean\n fileName: string\n imageUrl: string | undefined | null\n onRemove: () => void\n onDownload?: () => void\n onRetry?: () => void\n progress: undefined | number\n index: number\n}\n\nfunction FileCard({\n element,\n isUploading,\n isUploadPaused,\n uploadErrorMessage,\n loadImageUrlError,\n isLoadingImageUrl,\n imageUrl,\n fileName,\n onDownload,\n onRemove,\n onRetry,\n progress,\n index,\n}: Props) {\n const uploadError = React.useMemo(() => {\n if (!checkFileNameIsValid(element, fileName)) {\n return new Error(`${fileName.split('.').pop()} files are not allowed`)\n }\n if (!checkFileNameExtensionIsValid(element, fileName)) {\n return new Error(`${fileName} must have an extension`)\n }\n if (uploadErrorMessage) {\n return new Error(uploadErrorMessage)\n }\n }, [element, fileName, uploadErrorMessage])\n\n return (\n <div className=\"column is-one-quarter-ob\">\n <div className=\"ob-files__box\">\n <div className=\"ob-files__content\">\n <FileCardContent\n imageUrl={imageUrl}\n alt={`${element.label}: Attachment ${index + 1}`}\n />\n </div>\n <DropdownMenu\n element={element}\n onDownload={onDownload}\n onRetry={onRetry}\n onRemove={onRemove}\n />\n\n <div className=\"ob-files__file-name is-size-6\">\n <span className=\"ob-files__file-name-inner\">{fileName}</span>\n <AttachmentStatus\n isUploading={isUploading}\n isUploadPaused={isUploadPaused}\n uploadError={uploadError}\n loadImageUrlError={loadImageUrlError}\n isLoadingImageUrl={isLoadingImageUrl}\n imageUrl={imageUrl}\n progress={progress}\n />\n <ProgressBar progress={progress} isShowing={!!isUploading} />\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo(FileCard)\n"]}
1
+ {"version":3,"file":"FileCard.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/FileCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,eAAe,MAAM,mBAAmB,CAAA;AAC/C,OAAO,gBAAgB,MAAM,oBAAoB,CAAA;AACjD,OAAO,EACL,oBAAoB,EACpB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,WAAW,MAAM,eAAe,CAAA;AACvC,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAmBzC,SAAS,QAAQ,CAAC,EAChB,OAAO,EACP,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAAK,GACC;IACN,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;YAC5C,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;SACvE;QACD,IAAI,CAAC,6BAA6B,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE;YACrD,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,yBAAyB,CAAC,CAAA;SACvD;QACD,IAAI,kBAAkB,EAAE;YACtB,OAAO,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;SACrC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,kBAAkB,CAAC,CAAC,CAAA;IAE3C,OAAO,CACL,6BAAK,SAAS,EAAC,0BAA0B;QACvC,6BAAK,SAAS,EAAC,eAAe;YAC5B,6BAAK,SAAS,EAAC,mBAAmB;gBAChC,2BACE,IAAI,EAAE,aAAa,IAAI,EAAE,EACzB,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,4CAA4C,EACtD,KAAK,EAAE,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE;oBAEzD,oBAAC,eAAe,IACd,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,gBAAgB,KAAK,GAAG,CAAC,EAAE,EAChD,kBAAkB,EAAE,kBAAkB,GACtC,CACA,CACA;YACN,oBAAC,YAAY,IACX,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,IAAI,EAAE,GAClC;YAEF,6BAAK,SAAS,EAAC,+BAA+B;gBAC5C,8BAAM,SAAS,EAAC,2BAA2B,IAAE,QAAQ,CAAQ;gBAC7D,oBAAC,gBAAgB,IACf,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE,WAAW,EACxB,sBAAsB,EAAE,sBAAsB,EAC9C,sBAAsB,EAAE,sBAAsB,EAC9C,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,QAAQ,GAClB;gBACF,oBAAC,WAAW,IAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,WAAW,GAAI,CACzD,CACF,CACF,CACP,CAAA;AACH,CAAC;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport { FormTypes } from '@oneblink/types'\nimport FileCardContent from './FileCardContent'\nimport AttachmentStatus from './AttachmentStatus'\nimport {\n checkFileNameIsValid,\n checkFileNameExtensionIsValid,\n} from '../../../services/form-validation'\nimport ProgressBar from './ProgressBar'\nimport DropdownMenu from './DropdownMenu'\n\ntype Props = {\n element: FormTypes.FilesElement\n isUploading?: boolean\n isUploadPaused?: boolean\n uploadErrorMessage?: string\n loadAttachmentUrlError?: Error\n isLoadingAttachmentUrl?: boolean\n isContentTypeImage?: boolean\n fileName: string\n attachmentUrl: string | undefined | null\n onRemove: () => void\n onDownload?: () => void\n onRetry?: () => void\n progress: undefined | number\n index: number\n}\n\nfunction FileCard({\n element,\n isUploading,\n isUploadPaused,\n uploadErrorMessage,\n loadAttachmentUrlError,\n isLoadingAttachmentUrl,\n isContentTypeImage,\n attachmentUrl,\n fileName,\n onDownload,\n onRemove,\n onRetry,\n progress,\n index,\n}: Props) {\n const uploadError = React.useMemo(() => {\n if (!checkFileNameIsValid(element, fileName)) {\n return new Error(`${fileName.split('.').pop()} files are not allowed`)\n }\n if (!checkFileNameExtensionIsValid(element, fileName)) {\n return new Error(`${fileName} must have an extension`)\n }\n if (uploadErrorMessage) {\n return new Error(uploadErrorMessage)\n }\n }, [element, fileName, uploadErrorMessage])\n\n return (\n <div className=\"column is-one-quarter-ob\">\n <div className=\"ob-files__box\">\n <div className=\"ob-files__content\">\n <a\n href={attachmentUrl || ''}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"dropdown-item cypress-file-download-button\"\n style={{ pointerEvents: attachmentUrl ? 'auto' : 'none' }}\n >\n <FileCardContent\n attachmentUrl={attachmentUrl}\n alt={`${element.label}: Attachment ${index + 1}`}\n isContentTypeImage={isContentTypeImage}\n />\n </a>\n </div>\n <DropdownMenu\n element={element}\n onDownload={onDownload}\n onRetry={onRetry}\n onRemove={onRemove}\n attachmentUrl={attachmentUrl || ''}\n />\n\n <div className=\"ob-files__file-name is-size-6\">\n <span className=\"ob-files__file-name-inner\">{fileName}</span>\n <AttachmentStatus\n isUploading={isUploading}\n isUploadPaused={isUploadPaused}\n uploadError={uploadError}\n loadAttachmentUrlError={loadAttachmentUrlError}\n isLoadingAttachmentUrl={isLoadingAttachmentUrl}\n attachmentUrl={attachmentUrl}\n progress={progress}\n />\n <ProgressBar progress={progress} isShowing={!!isUploading} />\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo(FileCard)\n"]}
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
- declare const _default: React.MemoExoticComponent<({ imageUrl, alt, }: {
3
- imageUrl: string | null | undefined;
2
+ declare const _default: React.MemoExoticComponent<({ attachmentUrl, alt, isContentTypeImage, }: {
3
+ attachmentUrl: string | null | undefined;
4
4
  alt: string;
5
+ isContentTypeImage?: boolean | undefined;
5
6
  }) => React.JSX.Element>;
6
7
  export default _default;
@@ -1,9 +1,9 @@
1
1
  import * as React from 'react';
2
2
  import MaterialIcon from '../../MaterialIcon';
3
- const FileCardContent = ({ imageUrl, alt, }) => {
4
- if (imageUrl) {
3
+ const FileCardContent = ({ attachmentUrl, alt, isContentTypeImage, }) => {
4
+ if (isContentTypeImage && attachmentUrl) {
5
5
  return (React.createElement("div", { className: "ob-files__content-image" },
6
- React.createElement("img", { className: "ob-files__image", src: imageUrl, alt: alt })));
6
+ React.createElement("img", { className: "ob-files__image", src: attachmentUrl, alt: alt })));
7
7
  }
8
8
  return (React.createElement("div", { className: "ob-files__content-file has-text-centered" },
9
9
  React.createElement(MaterialIcon, { className: "icon-large ob-files__attach-icon has-text-grey" }, "attach_file")));
@@ -1 +1 @@
1
- {"version":3,"file":"FileCardContent.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/FileCardContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAE7C,MAAM,eAAe,GAAG,CAAC,EACvB,QAAQ,EACR,GAAG,GAIJ,EAAE,EAAE;IACH,IAAI,QAAQ,EAAE;QACZ,OAAO,CACL,6BAAK,SAAS,EAAC,yBAAyB;YACtC,6BAAK,SAAS,EAAC,iBAAiB,EAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,GAAI,CACxD,CACP,CAAA;KACF;IAED,OAAO,CACL,6BAAK,SAAS,EAAC,0CAA0C;QACvD,oBAAC,YAAY,IAAC,SAAS,EAAC,gDAAgD,kBAEzD,CACX,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport MaterialIcon from '../../MaterialIcon'\n\nconst FileCardContent = ({\n imageUrl,\n alt,\n}: {\n imageUrl: string | undefined | null\n alt: string\n}) => {\n if (imageUrl) {\n return (\n <div className=\"ob-files__content-image\">\n <img className=\"ob-files__image\" src={imageUrl} alt={alt} />\n </div>\n )\n }\n\n return (\n <div className=\"ob-files__content-file has-text-centered\">\n <MaterialIcon className=\"icon-large ob-files__attach-icon has-text-grey\">\n attach_file\n </MaterialIcon>\n </div>\n )\n}\n\nexport default React.memo(FileCardContent)\n"]}
1
+ {"version":3,"file":"FileCardContent.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/FileCardContent.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,YAAY,MAAM,oBAAoB,CAAA;AAE7C,MAAM,eAAe,GAAG,CAAC,EACvB,aAAa,EACb,GAAG,EACH,kBAAkB,GAKnB,EAAE,EAAE;IACH,IAAI,kBAAkB,IAAI,aAAa,EAAE;QACvC,OAAO,CACL,6BAAK,SAAS,EAAC,yBAAyB;YACtC,6BAAK,SAAS,EAAC,iBAAiB,EAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,GAAI,CAC7D,CACP,CAAA;KACF;IAED,OAAO,CACL,6BAAK,SAAS,EAAC,0CAA0C;QACvD,oBAAC,YAAY,IAAC,SAAS,EAAC,gDAAgD,kBAEzD,CACX,CACP,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport MaterialIcon from '../../MaterialIcon'\n\nconst FileCardContent = ({\n attachmentUrl,\n alt,\n isContentTypeImage,\n}: {\n attachmentUrl: string | undefined | null\n alt: string\n isContentTypeImage?: boolean\n}) => {\n if (isContentTypeImage && attachmentUrl) {\n return (\n <div className=\"ob-files__content-image\">\n <img className=\"ob-files__image\" src={attachmentUrl} alt={alt} />\n </div>\n )\n }\n\n return (\n <div className=\"ob-files__content-file has-text-centered\">\n <MaterialIcon className=\"icon-large ob-files__attach-icon has-text-grey\">\n attach_file\n </MaterialIcon>\n </div>\n )\n}\n\nexport default React.memo(FileCardContent)\n"]}
@@ -114,7 +114,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
114
114
  console.error('Could not find "input" element in Camera component template');
115
115
  }
116
116
  }, [element, onChange]);
117
- const { isUploading, uploadErrorMessage, isLoadingImageUrl, imageUrl, loadImageUrlError, canDownload, progress, } = useAttachment(value, element, React.useCallback((id, attachment) => {
117
+ const { isUploading, uploadErrorMessage, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, canDownload, progress, } = useAttachment(value, element, React.useCallback((id, attachment) => {
118
118
  onChange(element, {
119
119
  value: attachment,
120
120
  });
@@ -146,7 +146,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
146
146
  }, [value, id]);
147
147
  const handleSaveAnnotation = React.useCallback((annotationDataUri) => {
148
148
  clearIsAnnotating();
149
- if (typeof imageUrl !== 'string') {
149
+ if (typeof attachmentUrl !== 'string') {
150
150
  return;
151
151
  }
152
152
  setState({
@@ -193,15 +193,15 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
193
193
  annotationImage.src = annotationDataUri;
194
194
  };
195
195
  image.setAttribute('crossorigin', 'anonymous');
196
- image.src = imageUrl;
197
- }, [clearIsAnnotating, element, imageUrl, onChange]);
196
+ image.src = attachmentUrl;
197
+ }, [attachmentUrl, clearIsAnnotating, element, onChange]);
198
198
  const progressTooltipRef = React.useRef(null);
199
199
  return (React.createElement(React.Fragment, null,
200
200
  React.createElement(FormElementLabelContainer, { className: "ob-camera", element: element, id: id, required: element.required },
201
201
  React.createElement("div", { className: "control" },
202
202
  (value || isLoading) && (React.createElement(React.Fragment, null,
203
203
  React.createElement("figure", { className: "ob-figure", ref: progressTooltipRef },
204
- React.createElement(DisplayImage, { isUploading: isUploading, uploadErrorMessage: uploadErrorMessage, isLoadingImageUrl: isLoadingImageUrl, imageUrl: imageUrl, loadImageUrlError: loadImageUrlError, isLoading: isLoading, element: element, onAnnotate: setIsAnnotating, canDownload: canDownload, progress: progress }),
204
+ React.createElement(DisplayImage, { isUploading: isUploading, uploadErrorMessage: uploadErrorMessage, isLoadingAttachmentUrl: isLoadingAttachmentUrl, attachmentUrl: attachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isLoading: isLoading, element: element, onAnnotate: setIsAnnotating, canDownload: canDownload, progress: progress }),
205
205
  React.createElement(ProgressBar, { isShowing: isUploading, progress: progress })))),
206
206
  React.createElement("input", { ref: fileInputRef, className: "ob-input ob-camera__input-hidden cypress-camera-control", type: "file", accept: "image/*", capture: "environment", id: id, name: element.name, required: element.required, disabled: element.readOnly, onChange: fileChange }),
207
207
  React.createElement("div", { className: "buttons ob-buttons" }, value ? (React.createElement(React.Fragment, null,
@@ -213,7 +213,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
213
213
  React.createElement("span", null, "\u00A0Download"))))) : (React.createElement("button", { type: "button", className: "button ob-button ob-button__open is-primary cypress-open-camera", onClick: openCamera, disabled: element.readOnly || isLoading, "aria-describedby": ariaDescribedby, onBlur: setIsDirty }, "Open Camera")))),
214
214
  (isDirty || displayValidationMessage) && !!validationMessage && (React.createElement("div", { role: "alert", className: "has-margin-top-8" },
215
215
  React.createElement("div", { className: "has-text-danger ob-error__text cypress-validation-message" }, validationMessage)))),
216
- isAnnotating && imageUrl && (React.createElement(AnnotationModal, { imageSrc: imageUrl, onClose: clearIsAnnotating, onSave: handleSaveAnnotation })),
216
+ isAnnotating && attachmentUrl && (React.createElement(AnnotationModal, { imageSrc: attachmentUrl, onClose: clearIsAnnotating, onSave: handleSaveAnnotation })),
217
217
  cameraError && (React.createElement(Modal, { isOpen: true, title: "Whoops...", className: "cypress-error-modal", titleClassName: "cypress-error-title", actions: React.createElement("button", { type: "button", className: "button ob-button is-primary cypress-close-error-button", onClick: () => setState({ isLoading: false }), autoFocus: true }, "Okay") },
218
218
  React.createElement("p", null,
219
219
  "An error occurred while attempting to take a photo. Please click",
@@ -224,7 +224,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
224
224
  React.createElement("blockquote", null, cameraError.toString()))))));
225
225
  }
226
226
  export default React.memo(FormElementCamera);
227
- const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUploading, isLoadingImageUrl, imageUrl, loadImageUrlError, isLoading, element, onAnnotate, progress, }) {
227
+ const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUploading, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, isLoading, element, onAnnotate, progress, }) {
228
228
  if (uploadErrorMessage) {
229
229
  return (React.createElement("div", { className: "figure-content", role: "alert" },
230
230
  React.createElement("h3", { className: "title is-3" }, "Upload Failed"),
@@ -236,20 +236,20 @@ const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUp
236
236
  React.createElement("b", null, "Clear"),
237
237
  " buttons below.")));
238
238
  }
239
- if (loadImageUrlError) {
239
+ if (loadAttachmentUrlError) {
240
240
  return (React.createElement("div", { className: "figure-content", role: "alert" },
241
241
  React.createElement("h3", { className: "title is-3" }, "Preview Failed"),
242
- React.createElement("p", null, loadImageUrlError.message)));
242
+ React.createElement("p", null, loadAttachmentUrlError.message)));
243
243
  }
244
- if (isLoadingImageUrl || isLoading) {
244
+ if (isLoadingAttachmentUrl || isLoading) {
245
245
  return (React.createElement("div", { className: "figure-content has-text-centered cypress-camera-loading-image" },
246
246
  React.createElement(OnLoading, { small: true })));
247
247
  }
248
- if (imageUrl) {
248
+ if (attachmentUrl) {
249
249
  return (React.createElement(React.Fragment, null,
250
250
  React.createElement("span", { className: "ob-figure__status" },
251
- React.createElement(AttachmentStatus, { isLoadingImageUrl: isLoadingImageUrl, loadImageUrlError: loadImageUrlError, isUploading: isUploading, imageUrl: imageUrl, progress: progress })),
252
- React.createElement("img", { src: imageUrl, className: "cypress-camera-image ob-camera__img", crossOrigin: "anonymous", alt: `${element.label}: Attachment` }),
251
+ React.createElement(AttachmentStatus, { isLoadingAttachmentUrl: isLoadingAttachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isUploading: isUploading, attachmentUrl: attachmentUrl, progress: progress })),
252
+ React.createElement("img", { src: attachmentUrl, className: "cypress-camera-image ob-camera__img", crossOrigin: "anonymous", alt: `${element.label}: Attachment` }),
253
253
  React.createElement("button", { type: "button", className: "button is-primary ob-camera__annotate-button cypress-annotate-button", onClick: onAnnotate, disabled: element.readOnly },
254
254
  React.createElement("span", { className: "icon" },
255
255
  React.createElement(MaterialIcon, null, "brush")))));
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementCamera.js","sourceRoot":"","sources":["../../src/form-elements/FormElementCamera.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\n\nimport useBooleanState from '../hooks/useBooleanState'\nimport downloadAttachment, {\n downloadFileLegacy,\n} from '../services/download-file'\nimport OnLoading from '../components/renderer/OnLoading'\nimport { FormTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport drawTimestampOnCanvas from '../services/drawTimestampOnCanvas'\nimport { FormElementBinaryStorageValue } from '../types/attachments'\nimport useAttachment from '../hooks/attachments/useAttachment'\nimport AnnotationModal from '../components/renderer/AnnotationModal'\nimport Modal from '../components/renderer/Modal'\nimport {\n checkIfContentTypeIsImage,\n prepareNewAttachment,\n correctFileOrientation,\n} from '../services/attachments'\nimport AttachmentStatus from '../components/renderer/attachments/AttachmentStatus'\nimport { canvasToBlob, urlToBlobAsync } from '../services/blob-utils'\nimport ImagePreviewUnavailable from '../components/renderer/attachments/ImagePreviewUnavailable'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport ProgressBar from '../components/renderer/attachments/ProgressBar'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport MaterialIcon from '../components/MaterialIcon'\n\ntype Props = {\n id: string\n element: FormTypes.CameraElement\n value: FormElementBinaryStorageValue\n onChange: FormElementValueChangeHandler<FormElementBinaryStorageValue>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\nfunction FormElementCamera({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const [{ cameraError, isLoading }, setState] = React.useState<{\n isLoading: boolean\n cameraError?: Error\n }>({\n isLoading: false,\n })\n const [isAnnotating, setIsAnnotating, clearIsAnnotating] =\n useBooleanState(false)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const clearImage = React.useCallback(() => {\n onChange(element, {\n value: undefined,\n })\n }, [element, onChange])\n\n const fileChange = React.useCallback(\n async (changeEvent: React.ChangeEvent<HTMLInputElement>) => {\n if (!changeEvent.target || !changeEvent.target.files) {\n return\n }\n\n const file = changeEvent.target.files[0]\n if (!file) {\n return\n }\n\n setState({\n isLoading: true,\n })\n\n console.log('File selected event', file)\n try {\n if (!checkIfContentTypeIsImage(file.type)) {\n throw new Error(\n `Invalid file type \"${file.type}\". Please select an image.`,\n )\n }\n const result = await correctFileOrientation(\n file,\n element.includeTimestampWatermark ? drawTimestampOnCanvas : undefined,\n )\n\n if (result instanceof Blob) {\n onChange(element, {\n value: prepareNewAttachment(result, file.name, element),\n })\n } else {\n const blob = await canvasToBlob(result)\n onChange(element, {\n value: prepareNewAttachment(blob, file.name, element),\n })\n }\n\n setIsDirty()\n setState({\n isLoading: false,\n })\n } catch (error) {\n setState({\n isLoading: false,\n cameraError: error as Error,\n })\n }\n },\n [element, onChange, setIsDirty],\n )\n const openCamera = React.useCallback(() => {\n if (window.cordova && navigator.camera && navigator.camera.getPicture) {\n setState({\n isLoading: true,\n })\n navigator.camera.getPicture(\n (base64Data: string) => {\n urlToBlobAsync(`data:image/jpeg;base64,${base64Data}`)\n .then((blob) => {\n onChange(element, {\n value: prepareNewAttachment(blob, 'photo.jpeg', element),\n })\n setState({\n isLoading: false,\n })\n })\n .catch((error) => {\n setState({\n cameraError: error,\n isLoading: false,\n })\n })\n },\n (error: Error) => {\n console.warn(\n 'An error occurred while attempting to take a photo',\n error,\n )\n setState({\n isLoading: false,\n cameraError: error,\n })\n },\n {\n quality: 100,\n destinationType: window.Camera.DestinationType.DATA_URL,\n sourceType: window.Camera.PictureSourceType.CAMERA,\n allowEdit: false,\n encodingType: window.Camera.EncodingType.JPEG,\n mediaType: window.Camera.MediaType.PICTURE,\n correctOrientation: true,\n saveToPhotoAlbum: false,\n cameraDirection: window.Camera.Direction.BACK,\n },\n )\n } else if (fileInputRef.current) {\n // RESET HTML FILE INPUT VALUE SO FILES PREVIOUSLY ADDED AND REMOVED ARE RECOGNIZED\n fileInputRef.current.value = ''\n fileInputRef.current.click()\n } else {\n console.error(\n 'Could not find \"input\" element in Camera component template',\n )\n }\n }, [element, onChange])\n\n const {\n isUploading,\n uploadErrorMessage,\n isLoadingImageUrl,\n imageUrl,\n loadImageUrlError,\n canDownload,\n progress,\n } = useAttachment(\n value,\n element,\n React.useCallback(\n (id, attachment) => {\n onChange(element, {\n value: attachment,\n })\n },\n [element, onChange],\n ),\n )\n\n const handleRetry = React.useMemo(() => {\n if (!value || typeof value !== 'object') return\n\n if (value.type === 'ERROR' && value.data) {\n return () => {\n onChange(element, {\n value: {\n type: 'NEW',\n _id: value._id,\n data: value.data,\n fileName: value.fileName,\n isPrivate: value.isPrivate,\n },\n })\n }\n }\n }, [element, onChange, value])\n\n const handleDownload = React.useCallback(async () => {\n if (typeof value === 'string') {\n await downloadFileLegacy(value, id)\n } else if (value && value.type !== 'ERROR') {\n await downloadAttachment(value)\n }\n }, [value, id])\n\n const handleSaveAnnotation = React.useCallback(\n (annotationDataUri: string) => {\n clearIsAnnotating()\n\n if (typeof imageUrl !== 'string') {\n return\n }\n\n setState({\n isLoading: true,\n })\n\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n return\n }\n\n const image = new Image()\n image.onload = function () {\n canvas.width = image.width\n canvas.height = image.height\n\n ctx.drawImage(image, 0, 0)\n\n const annotationImage = new Image()\n annotationImage.onload = function () {\n ctx.drawImage(annotationImage, 0, 0, canvas.width, canvas.height)\n\n try {\n canvasToBlob(canvas)\n .then((blob) => {\n const attachment = prepareNewAttachment(\n blob,\n 'photo.png',\n element,\n )\n onChange(element, {\n value: attachment,\n })\n setState({\n isLoading: false,\n })\n })\n .catch((error) => {\n setState({\n cameraError: error,\n isLoading: false,\n })\n })\n } catch (error) {\n setState({\n cameraError: error as Error,\n isLoading: false,\n })\n }\n }\n annotationImage.src = annotationDataUri\n }\n image.setAttribute('crossorigin', 'anonymous')\n image.src = imageUrl\n },\n [clearIsAnnotating, element, imageUrl, onChange],\n )\n\n const progressTooltipRef = React.useRef<HTMLDivElement>(null)\n return (\n <>\n <FormElementLabelContainer\n className=\"ob-camera\"\n element={element}\n id={id}\n required={element.required}\n >\n <div className=\"control\">\n {(value || isLoading) && (\n <>\n <figure className=\"ob-figure\" ref={progressTooltipRef}>\n <DisplayImage\n isUploading={isUploading}\n uploadErrorMessage={uploadErrorMessage}\n isLoadingImageUrl={isLoadingImageUrl}\n imageUrl={imageUrl}\n loadImageUrlError={loadImageUrlError}\n isLoading={isLoading}\n element={element}\n onAnnotate={setIsAnnotating}\n canDownload={canDownload}\n progress={progress}\n />\n <ProgressBar isShowing={isUploading} progress={progress} />\n </figure>\n </>\n )}\n\n <input\n ref={fileInputRef}\n className=\"ob-input ob-camera__input-hidden cypress-camera-control\"\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n id={id}\n name={element.name}\n required={element.required}\n disabled={element.readOnly}\n onChange={fileChange}\n />\n <div className=\"buttons ob-buttons\">\n {value ? (\n <>\n {uploadErrorMessage && handleRetry && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__retry is-light cypress-retry-file-button\"\n onClick={handleRetry}\n >\n Retry\n </button>\n )}\n <button\n type=\"button\"\n className=\"button ob-button ob-button__clear is-light cypress-clear-camera\"\n onClick={clearImage}\n disabled={element.readOnly || isLoading}\n >\n Clear\n </button>\n {canDownload && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__download is-primary cypress-download-file-button\"\n onClick={handleDownload}\n >\n <span className=\"icon\">\n <MaterialIcon>cloud_download</MaterialIcon>\n </span>\n <span>&nbsp;Download</span>\n </button>\n )}\n </>\n ) : (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__open is-primary cypress-open-camera\"\n onClick={openCamera}\n disabled={element.readOnly || isLoading}\n aria-describedby={ariaDescribedby}\n onBlur={setIsDirty}\n >\n Open Camera\n </button>\n )}\n </div>\n </div>\n {(isDirty || displayValidationMessage) && !!validationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n\n {isAnnotating && imageUrl && (\n <AnnotationModal\n imageSrc={imageUrl}\n onClose={clearIsAnnotating}\n onSave={handleSaveAnnotation}\n />\n )}\n\n {cameraError && (\n <Modal\n isOpen\n title=\"Whoops...\"\n className=\"cypress-error-modal\"\n titleClassName=\"cypress-error-title\"\n actions={\n <button\n type=\"button\"\n className=\"button ob-button is-primary cypress-close-error-button\"\n onClick={() => setState({ isLoading: false })}\n autoFocus\n >\n Okay\n </button>\n }\n >\n <p>\n An error occurred while attempting to take a photo. Please click{' '}\n <b>Okay</b> below to try again. If the problem persists, please\n contact support.\n </p>\n\n <div className=\"content has-margin-top-6\">\n <blockquote>{cameraError.toString()}</blockquote>\n </div>\n </Modal>\n )}\n </>\n )\n}\n\nexport default React.memo(FormElementCamera)\n\nconst DisplayImage = React.memo(function DisplayImage({\n uploadErrorMessage,\n isUploading,\n isLoadingImageUrl,\n imageUrl,\n loadImageUrlError,\n isLoading,\n element,\n onAnnotate,\n progress,\n}: ReturnType<typeof useAttachment> & {\n element: FormTypes.CameraElement\n isLoading: boolean\n onAnnotate: () => void\n progress: number | undefined\n}) {\n if (uploadErrorMessage) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Upload Failed</h3>\n <p>\n Your photo failed to upload, please use the <b>Retry</b> or{' '}\n <b>Clear</b> buttons below.\n </p>\n </div>\n )\n }\n\n if (loadImageUrlError) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Preview Failed</h3>\n <p>{loadImageUrlError.message}</p>\n </div>\n )\n }\n\n if (isLoadingImageUrl || isLoading) {\n return (\n <div className=\"figure-content has-text-centered cypress-camera-loading-image\">\n <OnLoading small />\n </div>\n )\n }\n\n if (imageUrl) {\n return (\n <>\n <span className=\"ob-figure__status\">\n <AttachmentStatus\n isLoadingImageUrl={isLoadingImageUrl}\n loadImageUrlError={loadImageUrlError}\n isUploading={isUploading}\n imageUrl={imageUrl}\n progress={progress}\n />\n </span>\n <img\n src={imageUrl}\n className=\"cypress-camera-image ob-camera__img\"\n crossOrigin=\"anonymous\"\n alt={`${element.label}: Attachment`}\n />\n <button\n type=\"button\"\n className=\"button is-primary ob-camera__annotate-button cypress-annotate-button\"\n onClick={onAnnotate}\n disabled={element.readOnly}\n >\n <span className=\"icon\">\n <MaterialIcon>brush</MaterialIcon>\n </span>\n </button>\n </>\n )\n }\n\n return (\n <div className=\"figure-content\" role=\"alert\">\n <ImagePreviewUnavailable />\n </div>\n )\n})\n"]}
1
+ {"version":3,"file":"FormElementCamera.js","sourceRoot":"","sources":["../../src/form-elements/FormElementCamera.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\n\nimport useBooleanState from '../hooks/useBooleanState'\nimport downloadAttachment, {\n downloadFileLegacy,\n} from '../services/download-file'\nimport OnLoading from '../components/renderer/OnLoading'\nimport { FormTypes } from '@oneblink/types'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport drawTimestampOnCanvas from '../services/drawTimestampOnCanvas'\nimport { FormElementBinaryStorageValue } from '../types/attachments'\nimport useAttachment from '../hooks/attachments/useAttachment'\nimport AnnotationModal from '../components/renderer/AnnotationModal'\nimport Modal from '../components/renderer/Modal'\nimport {\n checkIfContentTypeIsImage,\n prepareNewAttachment,\n correctFileOrientation,\n} from '../services/attachments'\nimport AttachmentStatus from '../components/renderer/attachments/AttachmentStatus'\nimport { canvasToBlob, urlToBlobAsync } from '../services/blob-utils'\nimport ImagePreviewUnavailable from '../components/renderer/attachments/ImagePreviewUnavailable'\nimport { FormElementValueChangeHandler, IsDirtyProps } from '../types/form'\nimport ProgressBar from '../components/renderer/attachments/ProgressBar'\nimport useElementAriaDescribedby from '../hooks/useElementAriaDescribedby'\nimport MaterialIcon from '../components/MaterialIcon'\n\ntype Props = {\n id: string\n element: FormTypes.CameraElement\n value: FormElementBinaryStorageValue\n onChange: FormElementValueChangeHandler<FormElementBinaryStorageValue>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\nfunction FormElementCamera({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n isDirty,\n setIsDirty,\n}: Props) {\n const ariaDescribedby = useElementAriaDescribedby(id, element)\n const [{ cameraError, isLoading }, setState] = React.useState<{\n isLoading: boolean\n cameraError?: Error\n }>({\n isLoading: false,\n })\n const [isAnnotating, setIsAnnotating, clearIsAnnotating] =\n useBooleanState(false)\n const fileInputRef = React.useRef<HTMLInputElement>(null)\n\n const clearImage = React.useCallback(() => {\n onChange(element, {\n value: undefined,\n })\n }, [element, onChange])\n\n const fileChange = React.useCallback(\n async (changeEvent: React.ChangeEvent<HTMLInputElement>) => {\n if (!changeEvent.target || !changeEvent.target.files) {\n return\n }\n\n const file = changeEvent.target.files[0]\n if (!file) {\n return\n }\n\n setState({\n isLoading: true,\n })\n\n console.log('File selected event', file)\n try {\n if (!checkIfContentTypeIsImage(file.type)) {\n throw new Error(\n `Invalid file type \"${file.type}\". Please select an image.`,\n )\n }\n const result = await correctFileOrientation(\n file,\n element.includeTimestampWatermark ? drawTimestampOnCanvas : undefined,\n )\n\n if (result instanceof Blob) {\n onChange(element, {\n value: prepareNewAttachment(result, file.name, element),\n })\n } else {\n const blob = await canvasToBlob(result)\n onChange(element, {\n value: prepareNewAttachment(blob, file.name, element),\n })\n }\n\n setIsDirty()\n setState({\n isLoading: false,\n })\n } catch (error) {\n setState({\n isLoading: false,\n cameraError: error as Error,\n })\n }\n },\n [element, onChange, setIsDirty],\n )\n const openCamera = React.useCallback(() => {\n if (window.cordova && navigator.camera && navigator.camera.getPicture) {\n setState({\n isLoading: true,\n })\n navigator.camera.getPicture(\n (base64Data: string) => {\n urlToBlobAsync(`data:image/jpeg;base64,${base64Data}`)\n .then((blob) => {\n onChange(element, {\n value: prepareNewAttachment(blob, 'photo.jpeg', element),\n })\n setState({\n isLoading: false,\n })\n })\n .catch((error) => {\n setState({\n cameraError: error,\n isLoading: false,\n })\n })\n },\n (error: Error) => {\n console.warn(\n 'An error occurred while attempting to take a photo',\n error,\n )\n setState({\n isLoading: false,\n cameraError: error,\n })\n },\n {\n quality: 100,\n destinationType: window.Camera.DestinationType.DATA_URL,\n sourceType: window.Camera.PictureSourceType.CAMERA,\n allowEdit: false,\n encodingType: window.Camera.EncodingType.JPEG,\n mediaType: window.Camera.MediaType.PICTURE,\n correctOrientation: true,\n saveToPhotoAlbum: false,\n cameraDirection: window.Camera.Direction.BACK,\n },\n )\n } else if (fileInputRef.current) {\n // RESET HTML FILE INPUT VALUE SO FILES PREVIOUSLY ADDED AND REMOVED ARE RECOGNIZED\n fileInputRef.current.value = ''\n fileInputRef.current.click()\n } else {\n console.error(\n 'Could not find \"input\" element in Camera component template',\n )\n }\n }, [element, onChange])\n\n const {\n isUploading,\n uploadErrorMessage,\n isLoadingAttachmentUrl,\n attachmentUrl,\n loadAttachmentUrlError,\n canDownload,\n progress,\n } = useAttachment(\n value,\n element,\n React.useCallback(\n (id, attachment) => {\n onChange(element, {\n value: attachment,\n })\n },\n [element, onChange],\n ),\n )\n\n const handleRetry = React.useMemo(() => {\n if (!value || typeof value !== 'object') return\n\n if (value.type === 'ERROR' && value.data) {\n return () => {\n onChange(element, {\n value: {\n type: 'NEW',\n _id: value._id,\n data: value.data,\n fileName: value.fileName,\n isPrivate: value.isPrivate,\n },\n })\n }\n }\n }, [element, onChange, value])\n\n const handleDownload = React.useCallback(async () => {\n if (typeof value === 'string') {\n await downloadFileLegacy(value, id)\n } else if (value && value.type !== 'ERROR') {\n await downloadAttachment(value)\n }\n }, [value, id])\n\n const handleSaveAnnotation = React.useCallback(\n (annotationDataUri: string) => {\n clearIsAnnotating()\n\n if (typeof attachmentUrl !== 'string') {\n return\n }\n\n setState({\n isLoading: true,\n })\n\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) {\n return\n }\n\n const image = new Image()\n image.onload = function () {\n canvas.width = image.width\n canvas.height = image.height\n\n ctx.drawImage(image, 0, 0)\n\n const annotationImage = new Image()\n annotationImage.onload = function () {\n ctx.drawImage(annotationImage, 0, 0, canvas.width, canvas.height)\n\n try {\n canvasToBlob(canvas)\n .then((blob) => {\n const attachment = prepareNewAttachment(\n blob,\n 'photo.png',\n element,\n )\n onChange(element, {\n value: attachment,\n })\n setState({\n isLoading: false,\n })\n })\n .catch((error) => {\n setState({\n cameraError: error,\n isLoading: false,\n })\n })\n } catch (error) {\n setState({\n cameraError: error as Error,\n isLoading: false,\n })\n }\n }\n annotationImage.src = annotationDataUri\n }\n image.setAttribute('crossorigin', 'anonymous')\n image.src = attachmentUrl\n },\n [attachmentUrl, clearIsAnnotating, element, onChange],\n )\n\n const progressTooltipRef = React.useRef<HTMLDivElement>(null)\n return (\n <>\n <FormElementLabelContainer\n className=\"ob-camera\"\n element={element}\n id={id}\n required={element.required}\n >\n <div className=\"control\">\n {(value || isLoading) && (\n <>\n <figure className=\"ob-figure\" ref={progressTooltipRef}>\n <DisplayImage\n isUploading={isUploading}\n uploadErrorMessage={uploadErrorMessage}\n isLoadingAttachmentUrl={isLoadingAttachmentUrl}\n attachmentUrl={attachmentUrl}\n loadAttachmentUrlError={loadAttachmentUrlError}\n isLoading={isLoading}\n element={element}\n onAnnotate={setIsAnnotating}\n canDownload={canDownload}\n progress={progress}\n />\n <ProgressBar isShowing={isUploading} progress={progress} />\n </figure>\n </>\n )}\n\n <input\n ref={fileInputRef}\n className=\"ob-input ob-camera__input-hidden cypress-camera-control\"\n type=\"file\"\n accept=\"image/*\"\n capture=\"environment\"\n id={id}\n name={element.name}\n required={element.required}\n disabled={element.readOnly}\n onChange={fileChange}\n />\n <div className=\"buttons ob-buttons\">\n {value ? (\n <>\n {uploadErrorMessage && handleRetry && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__retry is-light cypress-retry-file-button\"\n onClick={handleRetry}\n >\n Retry\n </button>\n )}\n <button\n type=\"button\"\n className=\"button ob-button ob-button__clear is-light cypress-clear-camera\"\n onClick={clearImage}\n disabled={element.readOnly || isLoading}\n >\n Clear\n </button>\n {canDownload && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__download is-primary cypress-download-file-button\"\n onClick={handleDownload}\n >\n <span className=\"icon\">\n <MaterialIcon>cloud_download</MaterialIcon>\n </span>\n <span>&nbsp;Download</span>\n </button>\n )}\n </>\n ) : (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__open is-primary cypress-open-camera\"\n onClick={openCamera}\n disabled={element.readOnly || isLoading}\n aria-describedby={ariaDescribedby}\n onBlur={setIsDirty}\n >\n Open Camera\n </button>\n )}\n </div>\n </div>\n {(isDirty || displayValidationMessage) && !!validationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n\n {isAnnotating && attachmentUrl && (\n <AnnotationModal\n imageSrc={attachmentUrl}\n onClose={clearIsAnnotating}\n onSave={handleSaveAnnotation}\n />\n )}\n\n {cameraError && (\n <Modal\n isOpen\n title=\"Whoops...\"\n className=\"cypress-error-modal\"\n titleClassName=\"cypress-error-title\"\n actions={\n <button\n type=\"button\"\n className=\"button ob-button is-primary cypress-close-error-button\"\n onClick={() => setState({ isLoading: false })}\n autoFocus\n >\n Okay\n </button>\n }\n >\n <p>\n An error occurred while attempting to take a photo. Please click{' '}\n <b>Okay</b> below to try again. If the problem persists, please\n contact support.\n </p>\n\n <div className=\"content has-margin-top-6\">\n <blockquote>{cameraError.toString()}</blockquote>\n </div>\n </Modal>\n )}\n </>\n )\n}\n\nexport default React.memo(FormElementCamera)\n\nconst DisplayImage = React.memo(function DisplayImage({\n uploadErrorMessage,\n isUploading,\n isLoadingAttachmentUrl,\n attachmentUrl,\n loadAttachmentUrlError,\n isLoading,\n element,\n onAnnotate,\n progress,\n}: ReturnType<typeof useAttachment> & {\n element: FormTypes.CameraElement\n isLoading: boolean\n onAnnotate: () => void\n progress: number | undefined\n}) {\n if (uploadErrorMessage) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Upload Failed</h3>\n <p>\n Your photo failed to upload, please use the <b>Retry</b> or{' '}\n <b>Clear</b> buttons below.\n </p>\n </div>\n )\n }\n\n if (loadAttachmentUrlError) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Preview Failed</h3>\n <p>{loadAttachmentUrlError.message}</p>\n </div>\n )\n }\n\n if (isLoadingAttachmentUrl || isLoading) {\n return (\n <div className=\"figure-content has-text-centered cypress-camera-loading-image\">\n <OnLoading small />\n </div>\n )\n }\n\n if (attachmentUrl) {\n return (\n <>\n <span className=\"ob-figure__status\">\n <AttachmentStatus\n isLoadingAttachmentUrl={isLoadingAttachmentUrl}\n loadAttachmentUrlError={loadAttachmentUrlError}\n isUploading={isUploading}\n attachmentUrl={attachmentUrl}\n progress={progress}\n />\n </span>\n <img\n src={attachmentUrl}\n className=\"cypress-camera-image ob-camera__img\"\n crossOrigin=\"anonymous\"\n alt={`${element.label}: Attachment`}\n />\n <button\n type=\"button\"\n className=\"button is-primary ob-camera__annotate-button cypress-annotate-button\"\n onClick={onAnnotate}\n disabled={element.readOnly}\n >\n <span className=\"icon\">\n <MaterialIcon>brush</MaterialIcon>\n </span>\n </button>\n </>\n )\n }\n\n return (\n <div className=\"figure-content\" role=\"alert\">\n <ImagePreviewUnavailable />\n </div>\n )\n})\n"]}
@@ -26,7 +26,7 @@ const FormElementFile = ({ element, onRemove, file, onChange, disableUpload, ind
26
26
  };
27
27
  }
28
28
  }, [file, onChange]);
29
- return (React.createElement(FileCard, { element: element, isUploading: attachmentResult.isUploading, isUploadPaused: disableUpload, uploadErrorMessage: attachmentResult.uploadErrorMessage, loadImageUrlError: attachmentResult.loadImageUrlError, isLoadingImageUrl: attachmentResult.isLoadingImageUrl, imageUrl: attachmentResult.imageUrl, fileName: file.fileName, onDownload: attachmentResult.canDownload ? handleDownload : undefined, onRemove: handleRemove, onRetry: handleRetry, progress: attachmentResult.progress, index: index }));
29
+ return (React.createElement(FileCard, { element: element, isUploading: attachmentResult.isUploading, isUploadPaused: disableUpload, uploadErrorMessage: attachmentResult.uploadErrorMessage, loadAttachmentUrlError: attachmentResult.loadAttachmentUrlError, isLoadingAttachmentUrl: attachmentResult.isLoadingAttachmentUrl, attachmentUrl: attachmentResult.attachmentUrl, isContentTypeImage: attachmentResult.isContentTypeImage, fileName: file.fileName, onDownload: attachmentResult.canDownload ? handleDownload : undefined, onRemove: handleRemove, onRetry: handleRetry, progress: attachmentResult.progress, index: index }));
30
30
  };
31
31
  export default React.memo(FormElementFile);
32
32
  //# sourceMappingURL=FormElementFile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementFile.js","sourceRoot":"","sources":["../../src/form-elements/FormElementFile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,kBAAkB,MAAM,2BAA2B,CAAA;AAE1D,OAAO,aAA2B,MAAM,oCAAoC,CAAA;AAC5E,OAAO,QAAQ,MAAM,6CAA6C,CAAA;AAYlE,MAAM,eAAe,GAAG,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,KAAK,GACC,EAAE,EAAE;IACV,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAE9E,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACd,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;SACzB;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEpB,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE;QAClD,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE;YACtC,OAAO,GAAG,EAAE;gBACV,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;oBACjB,IAAI,EAAE,KAAK;oBACX,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,SAAS,EAAE,IAAI,CAAC,SAAS;iBAC1B,CAAC,CAAA;YACJ,CAAC,CAAA;SACF;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEpB,OAAO,CACL,oBAAC,QAAQ,IACP,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,gBAAgB,CAAC,WAAW,EACzC,cAAc,EAAE,aAAa,EAC7B,kBAAkB,EAAE,gBAAgB,CAAC,kBAAkB,EACvD,iBAAiB,EAAE,gBAAgB,CAAC,iBAAiB,EACrD,iBAAiB,EAAE,gBAAgB,CAAC,iBAAiB,EACrD,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EACnC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,UAAU,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EACrE,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EACnC,KAAK,EAAE,KAAK,GACZ,CACH,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAQ,eAAe,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport downloadAttachment from '../services/download-file'\nimport { FormTypes } from '@oneblink/types'\nimport useAttachment, { OnChange } from '../hooks/attachments/useAttachment'\nimport FileCard from '../components/renderer/attachments/FileCard'\nimport { attachmentsService } from '@oneblink/apps'\n\ntype Props = {\n element: FormTypes.FilesElement\n onRemove: (id: string) => void\n file: attachmentsService.Attachment\n disableUpload: boolean\n onChange: OnChange\n index: number\n}\n\nconst FormElementFile = ({\n element,\n onRemove,\n file,\n onChange,\n disableUpload,\n index,\n}: Props) => {\n const attachmentResult = useAttachment(file, element, onChange, disableUpload)\n\n const handleRemove = React.useCallback(() => {\n if (!file.type) {\n return onRemove(file.id)\n }\n return onRemove(file._id)\n }, [file, onRemove])\n\n const handleDownload = React.useCallback(async () => {\n await downloadAttachment(file)\n }, [file])\n\n const handleRetry = React.useMemo(() => {\n if (file.type === 'ERROR' && file.data) {\n return () => {\n onChange(file._id, {\n type: 'NEW',\n _id: file._id,\n data: file.data,\n fileName: file.fileName,\n isPrivate: file.isPrivate,\n })\n }\n }\n }, [file, onChange])\n\n return (\n <FileCard\n element={element}\n isUploading={attachmentResult.isUploading}\n isUploadPaused={disableUpload}\n uploadErrorMessage={attachmentResult.uploadErrorMessage}\n loadImageUrlError={attachmentResult.loadImageUrlError}\n isLoadingImageUrl={attachmentResult.isLoadingImageUrl}\n imageUrl={attachmentResult.imageUrl}\n fileName={file.fileName}\n onDownload={attachmentResult.canDownload ? handleDownload : undefined}\n onRemove={handleRemove}\n onRetry={handleRetry}\n progress={attachmentResult.progress}\n index={index}\n />\n )\n}\n\nexport default React.memo<Props>(FormElementFile)\n"]}
1
+ {"version":3,"file":"FormElementFile.js","sourceRoot":"","sources":["../../src/form-elements/FormElementFile.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,kBAAkB,MAAM,2BAA2B,CAAA;AAE1D,OAAO,aAA2B,MAAM,oCAAoC,CAAA;AAC5E,OAAO,QAAQ,MAAM,6CAA6C,CAAA;AAYlE,MAAM,eAAe,GAAG,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,KAAK,GACC,EAAE,EAAE;IACV,MAAM,gBAAgB,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAE9E,MAAM,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;QAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACd,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;SACzB;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEpB,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE;QAClD,MAAM,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE;YACtC,OAAO,GAAG,EAAE;gBACV,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE;oBACjB,IAAI,EAAE,KAAK;oBACX,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,SAAS,EAAE,IAAI,CAAC,SAAS;iBAC1B,CAAC,CAAA;YACJ,CAAC,CAAA;SACF;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEpB,OAAO,CACL,oBAAC,QAAQ,IACP,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,gBAAgB,CAAC,WAAW,EACzC,cAAc,EAAE,aAAa,EAC7B,kBAAkB,EAAE,gBAAgB,CAAC,kBAAkB,EACvD,sBAAsB,EAAE,gBAAgB,CAAC,sBAAsB,EAC/D,sBAAsB,EAAE,gBAAgB,CAAC,sBAAsB,EAC/D,aAAa,EAAE,gBAAgB,CAAC,aAAa,EAC7C,kBAAkB,EAAE,gBAAgB,CAAC,kBAAkB,EACvD,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,UAAU,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EACrE,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,EACnC,KAAK,EAAE,KAAK,GACZ,CACH,CAAA;AACH,CAAC,CAAA;AAED,eAAe,KAAK,CAAC,IAAI,CAAQ,eAAe,CAAC,CAAA","sourcesContent":["import * as React from 'react'\nimport downloadAttachment from '../services/download-file'\nimport { FormTypes } from '@oneblink/types'\nimport useAttachment, { OnChange } from '../hooks/attachments/useAttachment'\nimport FileCard from '../components/renderer/attachments/FileCard'\nimport { attachmentsService } from '@oneblink/apps'\n\ntype Props = {\n element: FormTypes.FilesElement\n onRemove: (id: string) => void\n file: attachmentsService.Attachment\n disableUpload: boolean\n onChange: OnChange\n index: number\n}\n\nconst FormElementFile = ({\n element,\n onRemove,\n file,\n onChange,\n disableUpload,\n index,\n}: Props) => {\n const attachmentResult = useAttachment(file, element, onChange, disableUpload)\n\n const handleRemove = React.useCallback(() => {\n if (!file.type) {\n return onRemove(file.id)\n }\n return onRemove(file._id)\n }, [file, onRemove])\n\n const handleDownload = React.useCallback(async () => {\n await downloadAttachment(file)\n }, [file])\n\n const handleRetry = React.useMemo(() => {\n if (file.type === 'ERROR' && file.data) {\n return () => {\n onChange(file._id, {\n type: 'NEW',\n _id: file._id,\n data: file.data,\n fileName: file.fileName,\n isPrivate: file.isPrivate,\n })\n }\n }\n }, [file, onChange])\n\n return (\n <FileCard\n element={element}\n isUploading={attachmentResult.isUploading}\n isUploadPaused={disableUpload}\n uploadErrorMessage={attachmentResult.uploadErrorMessage}\n loadAttachmentUrlError={attachmentResult.loadAttachmentUrlError}\n isLoadingAttachmentUrl={attachmentResult.isLoadingAttachmentUrl}\n attachmentUrl={attachmentResult.attachmentUrl}\n isContentTypeImage={attachmentResult.isContentTypeImage}\n fileName={file.fileName}\n onDownload={attachmentResult.canDownload ? handleDownload : undefined}\n onRemove={handleRemove}\n onRetry={handleRetry}\n progress={attachmentResult.progress}\n index={index}\n />\n )\n}\n\nexport default React.memo<Props>(FormElementFile)\n"]}
@@ -115,7 +115,7 @@ const SignatureDisplay = React.memo(function SignatureDisplay({ element, value,
115
115
  value: undefined,
116
116
  }), disabled: element.readOnly }, "Clear"))));
117
117
  });
118
- const DisplayImage = React.memo(function DisplayImage({ alt, uploadErrorMessage, isUploading, isLoadingImageUrl, imageUrl, loadImageUrlError, progress, }) {
118
+ const DisplayImage = React.memo(function DisplayImage({ alt, uploadErrorMessage, isUploading, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, progress, }) {
119
119
  if (uploadErrorMessage) {
120
120
  return (React.createElement("div", { className: "figure-content", role: "alert" },
121
121
  React.createElement("h3", { className: "title is-3" }, "Upload Failed"),
@@ -127,20 +127,20 @@ const DisplayImage = React.memo(function DisplayImage({ alt, uploadErrorMessage,
127
127
  React.createElement("b", null, "Clear"),
128
128
  " buttons below.")));
129
129
  }
130
- if (loadImageUrlError) {
130
+ if (loadAttachmentUrlError) {
131
131
  return (React.createElement("div", { className: "figure-content", role: "alert" },
132
132
  React.createElement("h3", { className: "title is-3" }, "Preview Failed"),
133
- React.createElement("p", null, loadImageUrlError.message)));
133
+ React.createElement("p", null, loadAttachmentUrlError.message)));
134
134
  }
135
- if (isLoadingImageUrl) {
135
+ if (isLoadingAttachmentUrl) {
136
136
  return (React.createElement("div", { className: "figure-content" },
137
137
  React.createElement(OnLoading, { small: true, className: "cypress-signature-loading-image" })));
138
138
  }
139
- if (imageUrl) {
139
+ if (attachmentUrl) {
140
140
  return (React.createElement("div", { className: "figure-content" },
141
141
  React.createElement("span", { className: "ob-figure__status" },
142
- React.createElement(AttachmentStatus, { isLoadingImageUrl: isLoadingImageUrl, loadImageUrlError: loadImageUrlError, isUploading: isUploading, imageUrl: imageUrl, progress: progress })),
143
- React.createElement("img", { src: imageUrl, className: "cypress-signature-image ob-signature__img", alt: alt }),
142
+ React.createElement(AttachmentStatus, { isLoadingAttachmentUrl: isLoadingAttachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isUploading: isUploading, attachmentUrl: attachmentUrl, progress: progress })),
143
+ React.createElement("img", { src: attachmentUrl, className: "cypress-signature-image ob-signature__img", alt: alt }),
144
144
  React.createElement(ProgressBar, { progress: progress, isShowing: isUploading })));
145
145
  }
146
146
  return (React.createElement("div", { className: "figure-content", role: "alert" },
@@ -1 +1 @@
1
- {"version":3,"file":"FormElementSignature.js","sourceRoot":"","sources":["../../src/form-elements/FormElementSignature.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport SignatureCanvas from 'react-signature-canvas'\nimport useResizeObserver, { ObservedSize } from 'use-resize-observer'\nimport { FormTypes } from '@oneblink/types'\n\nimport scrollingService from '../services/scrolling-service'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport OnLoading from '../components/renderer/OnLoading'\nimport useAttachment from '../hooks/attachments/useAttachment'\nimport { FormElementBinaryStorageValue } from '../types/attachments'\nimport { prepareNewAttachment } from '../services/attachments'\nimport AttachmentStatus from '../components/renderer/attachments/AttachmentStatus'\nimport { canvasToBlob } from '../services/blob-utils'\nimport ImagePreviewUnavailable from '../components/renderer/attachments/ImagePreviewUnavailable'\nimport { FormElementValueChangeHandler } from '../types/form'\nimport useIsPageVisible from '../hooks/useIsPageVisible'\nimport ProgressBar from '../components/renderer/attachments/ProgressBar'\nimport { IsDirtyProps } from '../types/form'\n\ntype Props = {\n id: string\n element: FormTypes.DrawElement\n value: FormElementBinaryStorageValue\n onChange: FormElementValueChangeHandler<FormElementBinaryStorageValue>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\nfunction FormElementSignature({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n setIsDirty,\n isDirty,\n}: Props) {\n const isPageVisible = useIsPageVisible()\n\n const handleChange = React.useCallback<\n FormElementValueChangeHandler<FormElementBinaryStorageValue>\n >(\n (formElement, newValue) => {\n setIsDirty()\n onChange(formElement, newValue)\n },\n [onChange, setIsDirty],\n )\n\n return (\n <div className=\"cypress-signature-element\">\n <FormElementLabelContainer\n className=\"ob-signature\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"control\">\n {value ? (\n <SignatureDisplay\n element={element}\n value={value}\n onChange={handleChange}\n />\n ) : isPageVisible ? (\n <SignatureDrawing element={element} onChange={handleChange} />\n ) : null}\n </div>\n\n {(isDirty || displayValidationMessage) && !!validationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementSignature)\n\nconst SignatureDrawing = React.memo(function SignatureDrawing({\n element,\n onChange,\n}: {\n element: Props['element']\n onChange: Props['onChange']\n}) {\n const canvasRef = React.useRef<SignatureCanvas>(null)\n\n const [isEmpty, setIsEmpty] = React.useState(true)\n const [canvasDimensions, setCanvasDimensions] = React.useState<ObservedSize>({\n width: undefined,\n height: undefined,\n })\n\n const handleClear = React.useCallback(() => {\n if (canvasRef.current) {\n console.log('Clearing signature...')\n canvasRef.current.clear()\n }\n setIsEmpty(true)\n }, [])\n\n const handleDone = React.useCallback(async () => {\n if (!canvasRef.current) return\n const trimmedCanvas = canvasRef.current.getTrimmedCanvas()\n\n // Convert base64 data uri to blob and send it on its way\n const blob = await canvasToBlob(trimmedCanvas)\n onChange(element, {\n value: prepareNewAttachment(blob, 'signature.png', element),\n })\n }, [element, onChange])\n\n // HANDLING CANVAS CHANGE\n const handleEndDraw = React.useCallback(() => {\n if (window.cordova) {\n scrollingService.enableScrolling()\n }\n if (isEmpty) {\n setIsEmpty(false)\n }\n }, [isEmpty])\n\n const { ref } = useResizeObserver<HTMLDivElement>({\n onResize: setCanvasDimensions,\n })\n\n // REACTIVE DISABLING OF CANVAS\n React.useEffect(() => {\n if (!canvasRef.current) return\n if (element.readOnly) {\n canvasRef.current.off()\n } else {\n canvasRef.current.on()\n }\n }, [canvasRef, element.readOnly])\n\n return (\n <>\n <div ref={ref}>\n <SignatureCanvas\n ref={canvasRef}\n canvasProps={{\n ...canvasDimensions,\n className:\n 'input ob-signature__control cypress-signature-control signature-pad',\n // @ts-expect-error ???\n disabled: element.readOnly,\n }}\n onEnd={handleEndDraw}\n onBegin={\n window.cordova ? scrollingService.disableScrolling : undefined\n }\n />\n </div>\n\n <div className=\"buttons ob-buttons\">\n <button\n type=\"button\"\n className=\"button ob-button is-light ob-button__clear cypress-clear-signature\"\n onClick={handleClear}\n disabled={element.readOnly || isEmpty}\n >\n Clear\n </button>\n <button\n type=\"button\"\n className=\"button ob-button ob-button__done is-primary cypress-done-signature-button\"\n onClick={handleDone}\n disabled={element.readOnly || isEmpty}\n >\n Save Signature\n </button>\n </div>\n </>\n )\n})\n\nconst SignatureDisplay = React.memo(function SignatureDisplay({\n element,\n value,\n onChange,\n}: {\n element: Props['element']\n value: Props['value']\n onChange: Props['onChange']\n}) {\n const result = useAttachment(\n value,\n element,\n React.useCallback(\n (id, attachment) => {\n onChange(element, {\n value: attachment,\n })\n },\n [element, onChange],\n ),\n )\n\n const handleRetry = React.useMemo(() => {\n if (!value || typeof value !== 'object') return\n\n if (value.type === 'ERROR' && value.data) {\n return () => {\n onChange(element, {\n value: {\n type: 'NEW',\n _id: value._id,\n data: value.data,\n fileName: value.fileName,\n isPrivate: value.isPrivate,\n },\n })\n }\n }\n }, [element, onChange, value])\n\n return (\n <>\n <figure className=\"ob-figure\">\n <DisplayImage {...result} alt={`${element.label}: Signature`} />\n </figure>\n\n <div className=\"buttons ob-buttons\">\n {result.uploadErrorMessage && handleRetry && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__retry is-light cypress-retry-file-button\"\n onClick={handleRetry}\n >\n Retry\n </button>\n )}\n <button\n type=\"button\"\n className=\"button ob-button is-light ob-button__clear cypress-clear-signature\"\n onClick={() =>\n onChange(element, {\n value: undefined,\n })\n }\n disabled={element.readOnly}\n >\n Clear\n </button>\n </div>\n </>\n )\n})\n\nconst DisplayImage = React.memo(function DisplayImage({\n alt,\n uploadErrorMessage,\n isUploading,\n isLoadingImageUrl,\n imageUrl,\n loadImageUrlError,\n progress,\n}: ReturnType<typeof useAttachment> & {\n alt: string\n}) {\n if (uploadErrorMessage) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Upload Failed</h3>\n <p>\n Your signature failed to upload, please use the <b>Retry</b> or{' '}\n <b>Clear</b> buttons below.\n </p>\n </div>\n )\n }\n\n if (loadImageUrlError) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Preview Failed</h3>\n <p>{loadImageUrlError.message}</p>\n </div>\n )\n }\n\n if (isLoadingImageUrl) {\n return (\n <div className=\"figure-content\">\n <OnLoading small className=\"cypress-signature-loading-image\" />\n </div>\n )\n }\n\n if (imageUrl) {\n return (\n <div className=\"figure-content\">\n <span className=\"ob-figure__status\">\n <AttachmentStatus\n isLoadingImageUrl={isLoadingImageUrl}\n loadImageUrlError={loadImageUrlError}\n isUploading={isUploading}\n imageUrl={imageUrl}\n progress={progress}\n />\n </span>\n <img\n src={imageUrl}\n className=\"cypress-signature-image ob-signature__img\"\n alt={alt}\n />\n <ProgressBar progress={progress} isShowing={isUploading} />\n </div>\n )\n }\n\n return (\n <div className=\"figure-content\" role=\"alert\">\n <ImagePreviewUnavailable />\n </div>\n )\n})\n"]}
1
+ {"version":3,"file":"FormElementSignature.js","sourceRoot":"","sources":["../../src/form-elements/FormElementSignature.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport SignatureCanvas from 'react-signature-canvas'\nimport useResizeObserver, { ObservedSize } from 'use-resize-observer'\nimport { FormTypes } from '@oneblink/types'\n\nimport scrollingService from '../services/scrolling-service'\nimport FormElementLabelContainer from '../components/renderer/FormElementLabelContainer'\nimport OnLoading from '../components/renderer/OnLoading'\nimport useAttachment from '../hooks/attachments/useAttachment'\nimport { FormElementBinaryStorageValue } from '../types/attachments'\nimport { prepareNewAttachment } from '../services/attachments'\nimport AttachmentStatus from '../components/renderer/attachments/AttachmentStatus'\nimport { canvasToBlob } from '../services/blob-utils'\nimport ImagePreviewUnavailable from '../components/renderer/attachments/ImagePreviewUnavailable'\nimport { FormElementValueChangeHandler } from '../types/form'\nimport useIsPageVisible from '../hooks/useIsPageVisible'\nimport ProgressBar from '../components/renderer/attachments/ProgressBar'\nimport { IsDirtyProps } from '../types/form'\n\ntype Props = {\n id: string\n element: FormTypes.DrawElement\n value: FormElementBinaryStorageValue\n onChange: FormElementValueChangeHandler<FormElementBinaryStorageValue>\n displayValidationMessage: boolean\n validationMessage: string | undefined\n} & IsDirtyProps\n\nfunction FormElementSignature({\n id,\n element,\n value,\n onChange,\n validationMessage,\n displayValidationMessage,\n setIsDirty,\n isDirty,\n}: Props) {\n const isPageVisible = useIsPageVisible()\n\n const handleChange = React.useCallback<\n FormElementValueChangeHandler<FormElementBinaryStorageValue>\n >(\n (formElement, newValue) => {\n setIsDirty()\n onChange(formElement, newValue)\n },\n [onChange, setIsDirty],\n )\n\n return (\n <div className=\"cypress-signature-element\">\n <FormElementLabelContainer\n className=\"ob-signature\"\n id={id}\n element={element}\n required={element.required}\n >\n <div className=\"control\">\n {value ? (\n <SignatureDisplay\n element={element}\n value={value}\n onChange={handleChange}\n />\n ) : isPageVisible ? (\n <SignatureDrawing element={element} onChange={handleChange} />\n ) : null}\n </div>\n\n {(isDirty || displayValidationMessage) && !!validationMessage && (\n <div role=\"alert\" className=\"has-margin-top-8\">\n <div className=\"has-text-danger ob-error__text cypress-validation-message\">\n {validationMessage}\n </div>\n </div>\n )}\n </FormElementLabelContainer>\n </div>\n )\n}\n\nexport default React.memo(FormElementSignature)\n\nconst SignatureDrawing = React.memo(function SignatureDrawing({\n element,\n onChange,\n}: {\n element: Props['element']\n onChange: Props['onChange']\n}) {\n const canvasRef = React.useRef<SignatureCanvas>(null)\n\n const [isEmpty, setIsEmpty] = React.useState(true)\n const [canvasDimensions, setCanvasDimensions] = React.useState<ObservedSize>({\n width: undefined,\n height: undefined,\n })\n\n const handleClear = React.useCallback(() => {\n if (canvasRef.current) {\n console.log('Clearing signature...')\n canvasRef.current.clear()\n }\n setIsEmpty(true)\n }, [])\n\n const handleDone = React.useCallback(async () => {\n if (!canvasRef.current) return\n const trimmedCanvas = canvasRef.current.getTrimmedCanvas()\n\n // Convert base64 data uri to blob and send it on its way\n const blob = await canvasToBlob(trimmedCanvas)\n onChange(element, {\n value: prepareNewAttachment(blob, 'signature.png', element),\n })\n }, [element, onChange])\n\n // HANDLING CANVAS CHANGE\n const handleEndDraw = React.useCallback(() => {\n if (window.cordova) {\n scrollingService.enableScrolling()\n }\n if (isEmpty) {\n setIsEmpty(false)\n }\n }, [isEmpty])\n\n const { ref } = useResizeObserver<HTMLDivElement>({\n onResize: setCanvasDimensions,\n })\n\n // REACTIVE DISABLING OF CANVAS\n React.useEffect(() => {\n if (!canvasRef.current) return\n if (element.readOnly) {\n canvasRef.current.off()\n } else {\n canvasRef.current.on()\n }\n }, [canvasRef, element.readOnly])\n\n return (\n <>\n <div ref={ref}>\n <SignatureCanvas\n ref={canvasRef}\n canvasProps={{\n ...canvasDimensions,\n className:\n 'input ob-signature__control cypress-signature-control signature-pad',\n // @ts-expect-error ???\n disabled: element.readOnly,\n }}\n onEnd={handleEndDraw}\n onBegin={\n window.cordova ? scrollingService.disableScrolling : undefined\n }\n />\n </div>\n\n <div className=\"buttons ob-buttons\">\n <button\n type=\"button\"\n className=\"button ob-button is-light ob-button__clear cypress-clear-signature\"\n onClick={handleClear}\n disabled={element.readOnly || isEmpty}\n >\n Clear\n </button>\n <button\n type=\"button\"\n className=\"button ob-button ob-button__done is-primary cypress-done-signature-button\"\n onClick={handleDone}\n disabled={element.readOnly || isEmpty}\n >\n Save Signature\n </button>\n </div>\n </>\n )\n})\n\nconst SignatureDisplay = React.memo(function SignatureDisplay({\n element,\n value,\n onChange,\n}: {\n element: Props['element']\n value: Props['value']\n onChange: Props['onChange']\n}) {\n const result = useAttachment(\n value,\n element,\n React.useCallback(\n (id, attachment) => {\n onChange(element, {\n value: attachment,\n })\n },\n [element, onChange],\n ),\n )\n\n const handleRetry = React.useMemo(() => {\n if (!value || typeof value !== 'object') return\n\n if (value.type === 'ERROR' && value.data) {\n return () => {\n onChange(element, {\n value: {\n type: 'NEW',\n _id: value._id,\n data: value.data,\n fileName: value.fileName,\n isPrivate: value.isPrivate,\n },\n })\n }\n }\n }, [element, onChange, value])\n\n return (\n <>\n <figure className=\"ob-figure\">\n <DisplayImage {...result} alt={`${element.label}: Signature`} />\n </figure>\n\n <div className=\"buttons ob-buttons\">\n {result.uploadErrorMessage && handleRetry && (\n <button\n type=\"button\"\n className=\"button ob-button ob-button__retry is-light cypress-retry-file-button\"\n onClick={handleRetry}\n >\n Retry\n </button>\n )}\n <button\n type=\"button\"\n className=\"button ob-button is-light ob-button__clear cypress-clear-signature\"\n onClick={() =>\n onChange(element, {\n value: undefined,\n })\n }\n disabled={element.readOnly}\n >\n Clear\n </button>\n </div>\n </>\n )\n})\n\nconst DisplayImage = React.memo(function DisplayImage({\n alt,\n uploadErrorMessage,\n isUploading,\n isLoadingAttachmentUrl,\n attachmentUrl,\n loadAttachmentUrlError,\n progress,\n}: ReturnType<typeof useAttachment> & {\n alt: string\n}) {\n if (uploadErrorMessage) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Upload Failed</h3>\n <p>\n Your signature failed to upload, please use the <b>Retry</b> or{' '}\n <b>Clear</b> buttons below.\n </p>\n </div>\n )\n }\n\n if (loadAttachmentUrlError) {\n return (\n <div className=\"figure-content\" role=\"alert\">\n <h3 className=\"title is-3\">Preview Failed</h3>\n <p>{loadAttachmentUrlError.message}</p>\n </div>\n )\n }\n\n if (isLoadingAttachmentUrl) {\n return (\n <div className=\"figure-content\">\n <OnLoading small className=\"cypress-signature-loading-image\" />\n </div>\n )\n }\n\n if (attachmentUrl) {\n return (\n <div className=\"figure-content\">\n <span className=\"ob-figure__status\">\n <AttachmentStatus\n isLoadingAttachmentUrl={isLoadingAttachmentUrl}\n loadAttachmentUrlError={loadAttachmentUrlError}\n isUploading={isUploading}\n attachmentUrl={attachmentUrl}\n progress={progress}\n />\n </span>\n <img\n src={attachmentUrl}\n className=\"cypress-signature-image ob-signature__img\"\n alt={alt}\n />\n <ProgressBar progress={progress} isShowing={isUploading} />\n </div>\n )\n }\n\n return (\n <div className=\"figure-content\" role=\"alert\">\n <ImagePreviewUnavailable />\n </div>\n )\n})\n"]}
@@ -5,9 +5,10 @@ export type OnChange = (id: string, attachment: attachmentsService.Attachment) =
5
5
  export default function useAttachment(value: FormElementBinaryStorageValue, element: FormTypes.FormElementBinaryStorage, onChange: OnChange, disableUpload?: boolean): {
6
6
  canDownload: boolean;
7
7
  progress: number | undefined;
8
- imageUrl?: string | null | undefined;
9
- loadImageUrlError?: Error | undefined;
8
+ attachmentUrl?: string | null | undefined;
9
+ loadAttachmentUrlError?: Error | undefined;
10
+ isContentTypeImage?: boolean | undefined;
10
11
  isUploading: boolean;
11
12
  uploadErrorMessage: string | undefined;
12
- isLoadingImageUrl: boolean;
13
+ isLoadingAttachmentUrl: boolean;
13
14
  };
@@ -14,7 +14,7 @@ export default function useAttachment(value, element, onChange, disableUpload) {
14
14
  const { isLoggedIn, isUsingFormsKey } = useAuth();
15
15
  const { storeAttachmentBlobLocally, getAttachmentBlobLocally } = useAttachmentBlobs();
16
16
  const isAuthenticated = isLoggedIn || isUsingFormsKey;
17
- const [imageUrlState, setImageUrlState] = React.useState({});
17
+ const [attachmentUrlState, setAttachmentUrlState] = React.useState({});
18
18
  const [progressState, setProgressState] = React.useState();
19
19
  const onProgress = React.useCallback(({ progress }) => {
20
20
  setProgressState(progress);
@@ -89,8 +89,8 @@ export default function useAttachment(value, element, onChange, disableUpload) {
89
89
  }
90
90
  // If the value is string we will assume a base64 data uri
91
91
  if (typeof value === 'string') {
92
- setImageUrlState({
93
- imageUrl: value,
92
+ setAttachmentUrlState({
93
+ attachmentUrl: value,
94
94
  });
95
95
  return;
96
96
  }
@@ -98,60 +98,47 @@ export default function useAttachment(value, element, onChange, disableUpload) {
98
98
  if (!value.data) {
99
99
  return;
100
100
  }
101
- if (!checkIfContentTypeIsImage(value.data.type)) {
102
- // Not an image which we will represent as null
103
- setImageUrlState({
104
- imageUrl: null,
105
- });
106
- return;
107
- }
108
- const imageUrl = URL.createObjectURL(value.data);
109
- console.log('Created object url from blob for image', imageUrl);
110
- setImageUrlState({
111
- imageUrl,
112
- });
113
- return;
114
- }
115
- if (!checkIfContentTypeIsImage(value.contentType)) {
116
- // Not an image which we will represent as null
117
- setImageUrlState({
118
- imageUrl: null,
101
+ const attachmentUrl = URL.createObjectURL(value.data);
102
+ setAttachmentUrlState({
103
+ attachmentUrl,
104
+ isContentTypeImage: checkIfContentTypeIsImage(value.data.type),
119
105
  });
120
106
  return;
121
107
  }
122
- // Check for locally stored Blob. Blob should be stored locally for private uploaded images only
108
+ // Check for locally stored Blob
123
109
  const locallyStoredAttachment = getAttachmentBlobLocally(value.id);
124
110
  if (locallyStoredAttachment) {
125
- const imageUrl = URL.createObjectURL(locallyStoredAttachment.blob);
126
- console.log('Created object url from locally stored Blob for private image attachment', imageUrl);
127
- setImageUrlState({
128
- imageUrl,
111
+ const attachmentUrl = URL.createObjectURL(locallyStoredAttachment.blob);
112
+ console.log('Created object url from locally stored Blob', attachmentUrl);
113
+ setAttachmentUrlState({
114
+ attachmentUrl,
115
+ isContentTypeImage: checkIfContentTypeIsImage(value.contentType),
129
116
  });
130
117
  return;
131
118
  }
132
- // If user is not logged in or is offline, we can't download private images.
119
+ // If user is not logged in or is offline, we can't download private attachments.
133
120
  // If the blob was not stored locally (above) for some reason, the user is SOL
134
121
  if (!isAuthenticated || isOffline) {
135
- setImageUrlState({
136
- imageUrl: null,
122
+ setAttachmentUrlState({
123
+ attachmentUrl: null,
137
124
  });
138
125
  return;
139
126
  }
140
127
  let ignore = false;
141
128
  const abortController = new AbortController();
142
- const privateImageUrl = value.url;
129
+ const privateAttachmentUrl = value.url;
143
130
  const effect = async () => {
144
131
  try {
145
- const blob = await urlToBlobAsync(privateImageUrl, abortController.signal);
132
+ const blob = await urlToBlobAsync(privateAttachmentUrl, abortController.signal);
146
133
  if (ignore) {
147
134
  return;
148
135
  }
149
- // Store private image attachment in Context
136
+ // Store private attachment in Context
150
137
  storeAttachmentBlobLocally({ attachmentId: value.id, blob });
151
- const imageUrl = URL.createObjectURL(blob);
152
- console.log('Created object url from private attachment for image', imageUrl);
153
- setImageUrlState({
154
- imageUrl,
138
+ const attachmentUrl = URL.createObjectURL(blob);
139
+ console.log('Created object url from private attachment for image', attachmentUrl);
140
+ setAttachmentUrlState({
141
+ attachmentUrl: attachmentUrl,
155
142
  });
156
143
  }
157
144
  catch (error) {
@@ -159,8 +146,8 @@ export default function useAttachment(value, element, onChange, disableUpload) {
159
146
  return;
160
147
  }
161
148
  console.warn('Error loading file:', error);
162
- setImageUrlState({
163
- loadImageUrlError: error,
149
+ setAttachmentUrlState({
150
+ loadAttachmentUrlError: error,
164
151
  });
165
152
  }
166
153
  };
@@ -178,13 +165,13 @@ export default function useAttachment(value, element, onChange, disableUpload) {
178
165
  ]);
179
166
  React.useEffect(() => {
180
167
  return () => {
181
- const imageUrl = imageUrlState.imageUrl;
182
- if (imageUrl && imageUrl.startsWith('blob:')) {
183
- console.log('revoking image url:', imageUrl);
184
- URL.revokeObjectURL(imageUrl);
168
+ const attachmentUrl = attachmentUrlState.attachmentUrl;
169
+ if (attachmentUrl && attachmentUrl.startsWith('blob:')) {
170
+ console.log('revoking attachment url:', attachmentUrl);
171
+ URL.revokeObjectURL(attachmentUrl);
185
172
  }
186
173
  };
187
- }, [imageUrlState.imageUrl]);
174
+ }, [attachmentUrlState.attachmentUrl]);
188
175
  const isUploading = React.useMemo(() => {
189
176
  return !!(value &&
190
177
  typeof value !== 'string' &&
@@ -221,8 +208,8 @@ export default function useAttachment(value, element, onChange, disableUpload) {
221
208
  return {
222
209
  isUploading,
223
210
  uploadErrorMessage,
224
- isLoadingImageUrl: imageUrlState.imageUrl === undefined,
225
- ...imageUrlState,
211
+ isLoadingAttachmentUrl: attachmentUrlState.attachmentUrl === undefined,
212
+ ...attachmentUrlState,
226
213
  canDownload,
227
214
  progress: progressState,
228
215
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useAttachment.js","sourceRoot":"","sources":["../../../src/hooks/attachments/useAttachment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,iBAAiB,MAAM,sBAAsB,CAAA;AACpD,OAAO,YAAY,MAAM,iBAAiB,CAAA;AAE1C,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,OAAO,MAAM,qBAAqB,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,kBAAkB,MAAM,4CAA4C,CAAA;AAC3E,OAAO,4BAA4B,MAAM,0BAA0B,CAAA;AAOnE,MAAM,CAAC,OAAO,UAAU,aAAa,CACnC,KAAoC,EACpC,OAA2C,EAC3C,QAAkB,EAClB,aAAuB;IAEvB,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,KAAK,QAAQ,CAAA;IAClD,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAA;IAChC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,kBAAkB,GAAG,4BAA4B,EAAE,CAAA;IACzD,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,GAAG,OAAO,EAAE,CAAA;IACjD,MAAM,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,GAC5D,kBAAkB,EAAE,CAAA;IAEtB,MAAM,eAAe,GAAG,UAAU,IAAI,eAAe,CAAA;IAErD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAGrD,EAAE,CAAC,CAAA;IACN,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAsB,CAAA;IAE9E,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAwB,EAAE,EAAE;QAC1E,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAC5B,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,iBAAiB;IACjB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,MAAM,MAAM,GAAG,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,EAAE,CAAA;QAEvB,IACE,SAAS;YACT,aAAa;YACb,CAAC,MAAM;YACP,CAAC,KAAK;YACN,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,CAAC,IAAI,KAAK,KAAK;YACpB,CAAC,KAAK,CAAC,IAAI,EACX;YACA,OAAM;SACP;QAED,MAAM,aAAa,GAAG,KAAyC,CAAA;QAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAA;QAEvB,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAE7C,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,IAAI;gBACF,OAAO,CAAC,GAAG,CACT,oCAAoC,EACpC,aAAa,CAAC,QAAQ,CACvB,CAAA;gBACD,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC;oBACE,MAAM;oBACN,QAAQ,EAAE,aAAa,CAAC,QAAQ;oBAChC,WAAW,EAAE,IAAI,CAAC,IAAI;oBACtB,IAAI;oBACJ,SAAS;oBACT,UAAU;iBACX,EACD,eAAe,CAAC,MAAM,CACvB,CAAA;gBACD,IAAI,MAAM,EAAE;oBACV,OAAM;iBACP;gBAED,0BAA0B,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;gBAEnE,OAAO,CAAC,GAAG,CAAC,mCAAmC,EAAE,MAAM,CAAC,CAAA;gBAExD,oBAAoB;gBACpB,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;aACpC;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,MAAM,EAAE;oBACV,OAAM;iBACP;gBAED,OAAO,CAAC,IAAI,CACV,gCAAgC,EAChC,aAAa,CAAC,QAAQ,EACtB,KAAK,CACN,CAAA;gBACD,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE;oBAC1B,GAAG,aAAa;oBAChB,IAAI,EAAE,OAAO;oBACb,YAAY,EAAG,KAAe,CAAC,OAAO;iBACvC,CAAC,CAAA;aACH;QACH,CAAC,CAAA;QAED,MAAM,EAAE,CAAA;QAER,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,IAAI,CAAA;YACb,eAAe,CAAC,KAAK,EAAE,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE;QACD,aAAa;QACb,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,EAAE;QACR,SAAS;QACT,SAAS;QACT,QAAQ;QACR,UAAU;QACV,kBAAkB;QAClB,0BAA0B;QAC1B,KAAK;KACN,CAAC,CAAA;IAEF,mBAAmB;IACnB,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,CAAC,KAAK,EAAE;YACV,OAAM;SACP;QAED,0DAA0D;QAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,gBAAgB,CAAC;gBACf,QAAQ,EAAE,KAAK;aAChB,CAAC,CAAA;YACF,OAAM;SACP;QAED,IAAI,KAAK,CAAC,IAAI,EAAE;YACd,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;gBACf,OAAM;aACP;YAED,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAC/C,+CAA+C;gBAC/C,gBAAgB,CAAC;oBACf,QAAQ,EAAE,IAAI;iBACf,CAAC,CAAA;gBACF,OAAM;aACP;YAED,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAChD,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE,QAAQ,CAAC,CAAA;YAC/D,gBAAgB,CAAC;gBACf,QAAQ;aACT,CAAC,CAAA;YACF,OAAM;SACP;QAED,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;YACjD,+CAA+C;YAC/C,gBAAgB,CAAC;gBACf,QAAQ,EAAE,IAAI;aACf,CAAC,CAAA;YACF,OAAM;SACP;QAED,gGAAgG;QAChG,MAAM,uBAAuB,GAAG,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAClE,IAAI,uBAAuB,EAAE;YAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAA;YAClE,OAAO,CAAC,GAAG,CACT,0EAA0E,EAC1E,QAAQ,CACT,CAAA;YACD,gBAAgB,CAAC;gBACf,QAAQ;aACT,CAAC,CAAA;YACF,OAAM;SACP;QAED,4EAA4E;QAC5E,8EAA8E;QAC9E,IAAI,CAAC,eAAe,IAAI,SAAS,EAAE;YACjC,gBAAgB,CAAC;gBACf,QAAQ,EAAE,IAAI;aACf,CAAC,CAAA;YACF,OAAM;SACP;QAED,IAAI,MAAM,GAAG,KAAK,CAAA;QAClB,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;QAC7C,MAAM,eAAe,GAAG,KAAK,CAAC,GAAG,CAAA;QAEjC,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,IAAI;gBACF,MAAM,IAAI,GAAG,MAAM,cAAc,CAC/B,eAAe,EACf,eAAe,CAAC,MAAM,CACvB,CAAA;gBACD,IAAI,MAAM,EAAE;oBACV,OAAM;iBACP;gBACD,4CAA4C;gBAC5C,0BAA0B,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC5D,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAA;gBAC1C,OAAO,CAAC,GAAG,CACT,sDAAsD,EACtD,QAAQ,CACT,CAAA;gBACD,gBAAgB,CAAC;oBACf,QAAQ;iBACT,CAAC,CAAA;aACH;YAAC,OAAO,KAAK,EAAE;gBACd,IAAI,MAAM,EAAE;oBACV,OAAM;iBACP;gBACD,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAA;gBAC1C,gBAAgB,CAAC;oBACf,iBAAiB,EAAE,KAAc;iBAClC,CAAC,CAAA;aACH;QACH,CAAC,CAAA;QACD,MAAM,EAAE,CAAA;QAER,OAAO,GAAG,EAAE;YACV,MAAM,GAAG,IAAI,CAAA;YACb,eAAe,CAAC,KAAK,EAAE,CAAA;QACzB,CAAC,CAAA;IACH,CAAC,EAAE;QACD,wBAAwB;QACxB,eAAe;QACf,SAAS;QACT,0BAA0B;QAC1B,KAAK;KACN,CAAC,CAAA;IAEF,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,GAAG,EAAE;YACV,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAA;YACvC,IAAI,QAAQ,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;gBAC5C,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAA;gBAC5C,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAA;aAC9B;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;IAE5B,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,OAAO,CAAC,CAAC,CACP,KAAK;YACL,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,IAAI,KAAK,KAAK,CACrB,CAAA;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QAC5C,IACE,KAAK;YACL,OAAO,KAAK,KAAK,QAAQ;YACzB,KAAK,CAAC,IAAI;YACV,KAAK,CAAC,IAAI,KAAK,OAAO,EACtB;YACA,OAAO,KAAK,CAAC,YAAY,CAAA;SAC1B;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAEX,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,KAAK,EAAE;YACV,OAAO,KAAK,CAAA;SACb;QAED,mCAAmC;QACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;YAC7B,OAAO,IAAI,CAAA;SACZ;QAED,kDAAkD;QAClD,IAAI,KAAK,CAAC,IAAI,EAAE;YACd,mDAAmD;YACnD,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAA;SACpB;QAED,sEAAsE;QACtE,IAAI,eAAe,EAAE;YACnB,OAAO,IAAI,CAAA;SACZ;QAED,OAAO,KAAK,CAAA;IACd,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,CAAA;IAE5B,OAAO;QACL,WAAW;QACX,kBAAkB;QAClB,iBAAiB,EAAE,aAAa,CAAC,QAAQ,KAAK,SAAS;QACvD,GAAG,aAAa;QAChB,WAAW;QACX,QAAQ,EAAE,aAAa;KACxB,CAAA;AACH,CAAC","sourcesContent":["import * as React from 'react'\nimport { attachmentsService } from '@oneblink/apps'\nimport { FormTypes } from '@oneblink/types'\nimport useFormDefinition from '../useFormDefinition'\nimport useIsOffline from '../useIsOffline'\nimport { FormElementBinaryStorageValue } from '../../types/attachments'\nimport { checkIfContentTypeIsImage } from '../../services/attachments'\nimport useAuth from '../../hooks/useAuth'\nimport { urlToBlobAsync } from '../../services/blob-utils'\nimport useAttachmentBlobs from '../../hooks/attachments/useAttachmentBlobs'\nimport useOnUploadAttachmentContext from '../useOnUploadAttachment'\n\nexport type OnChange = (\n id: string,\n attachment: attachmentsService.Attachment,\n) => void\n\nexport default function useAttachment(\n value: FormElementBinaryStorageValue,\n element: FormTypes.FormElementBinaryStorage,\n onChange: OnChange,\n disableUpload?: boolean,\n) {\n const isPrivate = element.storageType !== 'public'\n const form = useFormDefinition()\n const isOffline = useIsOffline()\n const onUploadAttachment = useOnUploadAttachmentContext()\n const { isLoggedIn, isUsingFormsKey } = useAuth()\n const { storeAttachmentBlobLocally, getAttachmentBlobLocally } =\n useAttachmentBlobs()\n\n const isAuthenticated = isLoggedIn || isUsingFormsKey\n\n const [imageUrlState, setImageUrlState] = React.useState<{\n imageUrl?: string | null\n loadImageUrlError?: Error\n }>({})\n const [progressState, setProgressState] = React.useState<number | undefined>()\n\n const onProgress = React.useCallback(({ progress }: { progress: number }) => {\n setProgressState(progress)\n }, [])\n\n // TRIGGER UPLOAD\n React.useEffect(() => {\n const formId = form?.id\n\n if (\n isOffline ||\n disableUpload ||\n !formId ||\n !value ||\n typeof value !== 'object' ||\n value.type !== 'NEW' ||\n !value.data\n ) {\n return\n }\n\n const newAttachment = value as attachmentsService.AttachmentNew\n const data = value.data\n\n let ignore = false\n const abortController = new AbortController()\n\n const effect = async () => {\n try {\n console.log(\n 'Attempting to upload attachment...',\n newAttachment.fileName,\n )\n const upload = await onUploadAttachment(\n {\n formId,\n fileName: newAttachment.fileName,\n contentType: data.type,\n data,\n isPrivate,\n onProgress,\n },\n abortController.signal,\n )\n if (ignore) {\n return\n }\n\n storeAttachmentBlobLocally({ attachmentId: upload.id, blob: data })\n\n console.log('Successfully Uploaded attachment!', upload)\n\n // UPDATE ATTACHMENT\n onChange(newAttachment._id, upload)\n } catch (error) {\n if (ignore) {\n return\n }\n\n console.warn(\n 'Failed to upload attachment...',\n newAttachment.fileName,\n error,\n )\n onChange(newAttachment._id, {\n ...newAttachment,\n type: 'ERROR',\n errorMessage: (error as Error).message,\n })\n }\n }\n\n effect()\n\n return () => {\n ignore = true\n abortController.abort()\n }\n }, [\n disableUpload,\n form?.id,\n isOffline,\n isPrivate,\n onChange,\n onProgress,\n onUploadAttachment,\n storeAttachmentBlobLocally,\n value,\n ])\n\n // TRIGGER DOWNLOAD\n React.useEffect(() => {\n if (!value) {\n return\n }\n\n // If the value is string we will assume a base64 data uri\n if (typeof value === 'string') {\n setImageUrlState({\n imageUrl: value,\n })\n return\n }\n\n if (value.type) {\n if (!value.data) {\n return\n }\n\n if (!checkIfContentTypeIsImage(value.data.type)) {\n // Not an image which we will represent as null\n setImageUrlState({\n imageUrl: null,\n })\n return\n }\n\n const imageUrl = URL.createObjectURL(value.data)\n console.log('Created object url from blob for image', imageUrl)\n setImageUrlState({\n imageUrl,\n })\n return\n }\n\n if (!checkIfContentTypeIsImage(value.contentType)) {\n // Not an image which we will represent as null\n setImageUrlState({\n imageUrl: null,\n })\n return\n }\n\n // Check for locally stored Blob. Blob should be stored locally for private uploaded images only\n const locallyStoredAttachment = getAttachmentBlobLocally(value.id)\n if (locallyStoredAttachment) {\n const imageUrl = URL.createObjectURL(locallyStoredAttachment.blob)\n console.log(\n 'Created object url from locally stored Blob for private image attachment',\n imageUrl,\n )\n setImageUrlState({\n imageUrl,\n })\n return\n }\n\n // If user is not logged in or is offline, we can't download private images.\n // If the blob was not stored locally (above) for some reason, the user is SOL\n if (!isAuthenticated || isOffline) {\n setImageUrlState({\n imageUrl: null,\n })\n return\n }\n\n let ignore = false\n const abortController = new AbortController()\n const privateImageUrl = value.url\n\n const effect = async () => {\n try {\n const blob = await urlToBlobAsync(\n privateImageUrl,\n abortController.signal,\n )\n if (ignore) {\n return\n }\n // Store private image attachment in Context\n storeAttachmentBlobLocally({ attachmentId: value.id, blob })\n const imageUrl = URL.createObjectURL(blob)\n console.log(\n 'Created object url from private attachment for image',\n imageUrl,\n )\n setImageUrlState({\n imageUrl,\n })\n } catch (error) {\n if (ignore) {\n return\n }\n console.warn('Error loading file:', error)\n setImageUrlState({\n loadImageUrlError: error as Error,\n })\n }\n }\n effect()\n\n return () => {\n ignore = true\n abortController.abort()\n }\n }, [\n getAttachmentBlobLocally,\n isAuthenticated,\n isOffline,\n storeAttachmentBlobLocally,\n value,\n ])\n\n React.useEffect(() => {\n return () => {\n const imageUrl = imageUrlState.imageUrl\n if (imageUrl && imageUrl.startsWith('blob:')) {\n console.log('revoking image url:', imageUrl)\n URL.revokeObjectURL(imageUrl)\n }\n }\n }, [imageUrlState.imageUrl])\n\n const isUploading = React.useMemo(() => {\n return !!(\n value &&\n typeof value !== 'string' &&\n value.type &&\n value.type === 'NEW'\n )\n }, [value])\n\n const uploadErrorMessage = React.useMemo(() => {\n if (\n value &&\n typeof value !== 'string' &&\n value.type &&\n value.type === 'ERROR'\n ) {\n return value.errorMessage\n }\n }, [value])\n\n const canDownload = React.useMemo(() => {\n if (!value) {\n return false\n }\n\n // legacy attachment as base64 data\n if (typeof value === 'string') {\n return true\n }\n\n // attachments still uploading or failed to upload\n if (value.type) {\n // can only be downloaded if we still have the data\n return !!value.data\n }\n\n // private attachments can only be downloaded if user is authenticated\n if (isAuthenticated) {\n return true\n }\n\n return false\n }, [isAuthenticated, value])\n\n return {\n isUploading,\n uploadErrorMessage,\n isLoadingImageUrl: imageUrlState.imageUrl === undefined,\n ...imageUrlState,\n canDownload,\n progress: progressState,\n }\n}\n"]}
1
+ {"version":3,"file":"useAttachment.js","sourceRoot":"","sources":["../../../src/hooks/attachments/useAttachment.ts"],"names":[],"mappings":"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","sourcesContent":["import * as React from 'react'\nimport { attachmentsService } from '@oneblink/apps'\nimport { FormTypes } from '@oneblink/types'\nimport useFormDefinition from '../useFormDefinition'\nimport useIsOffline from '../useIsOffline'\nimport { FormElementBinaryStorageValue } from '../../types/attachments'\nimport { checkIfContentTypeIsImage } from '../../services/attachments'\nimport useAuth from '../../hooks/useAuth'\nimport { urlToBlobAsync } from '../../services/blob-utils'\nimport useAttachmentBlobs from '../../hooks/attachments/useAttachmentBlobs'\nimport useOnUploadAttachmentContext from '../useOnUploadAttachment'\n\nexport type OnChange = (\n id: string,\n attachment: attachmentsService.Attachment,\n) => void\n\nexport default function useAttachment(\n value: FormElementBinaryStorageValue,\n element: FormTypes.FormElementBinaryStorage,\n onChange: OnChange,\n disableUpload?: boolean,\n) {\n const isPrivate = element.storageType !== 'public'\n const form = useFormDefinition()\n const isOffline = useIsOffline()\n const onUploadAttachment = useOnUploadAttachmentContext()\n const { isLoggedIn, isUsingFormsKey } = useAuth()\n const { storeAttachmentBlobLocally, getAttachmentBlobLocally } =\n useAttachmentBlobs()\n\n const isAuthenticated = isLoggedIn || isUsingFormsKey\n\n const [attachmentUrlState, setAttachmentUrlState] = React.useState<{\n attachmentUrl?: string | null\n loadAttachmentUrlError?: Error\n isContentTypeImage?: boolean\n }>({})\n const [progressState, setProgressState] = React.useState<number | undefined>()\n\n const onProgress = React.useCallback(({ progress }: { progress: number }) => {\n setProgressState(progress)\n }, [])\n\n // TRIGGER UPLOAD\n React.useEffect(() => {\n const formId = form?.id\n\n if (\n isOffline ||\n disableUpload ||\n !formId ||\n !value ||\n typeof value !== 'object' ||\n value.type !== 'NEW' ||\n !value.data\n ) {\n return\n }\n\n const newAttachment = value as attachmentsService.AttachmentNew\n const data = value.data\n\n let ignore = false\n const abortController = new AbortController()\n\n const effect = async () => {\n try {\n console.log(\n 'Attempting to upload attachment...',\n newAttachment.fileName,\n )\n const upload = await onUploadAttachment(\n {\n formId,\n fileName: newAttachment.fileName,\n contentType: data.type,\n data,\n isPrivate,\n onProgress,\n },\n abortController.signal,\n )\n if (ignore) {\n return\n }\n\n storeAttachmentBlobLocally({ attachmentId: upload.id, blob: data })\n\n console.log('Successfully Uploaded attachment!', upload)\n\n // UPDATE ATTACHMENT\n onChange(newAttachment._id, upload)\n } catch (error) {\n if (ignore) {\n return\n }\n\n console.warn(\n 'Failed to upload attachment...',\n newAttachment.fileName,\n error,\n )\n onChange(newAttachment._id, {\n ...newAttachment,\n type: 'ERROR',\n errorMessage: (error as Error).message,\n })\n }\n }\n\n effect()\n\n return () => {\n ignore = true\n abortController.abort()\n }\n }, [\n disableUpload,\n form?.id,\n isOffline,\n isPrivate,\n onChange,\n onProgress,\n onUploadAttachment,\n storeAttachmentBlobLocally,\n value,\n ])\n\n // TRIGGER DOWNLOAD\n React.useEffect(() => {\n if (!value) {\n return\n }\n\n // If the value is string we will assume a base64 data uri\n if (typeof value === 'string') {\n setAttachmentUrlState({\n attachmentUrl: value,\n })\n return\n }\n\n if (value.type) {\n if (!value.data) {\n return\n }\n\n const attachmentUrl = URL.createObjectURL(value.data)\n setAttachmentUrlState({\n attachmentUrl,\n isContentTypeImage: checkIfContentTypeIsImage(value.data.type),\n })\n return\n }\n\n // Check for locally stored Blob\n const locallyStoredAttachment = getAttachmentBlobLocally(value.id)\n if (locallyStoredAttachment) {\n const attachmentUrl = URL.createObjectURL(locallyStoredAttachment.blob)\n console.log('Created object url from locally stored Blob', attachmentUrl)\n setAttachmentUrlState({\n attachmentUrl,\n isContentTypeImage: checkIfContentTypeIsImage(value.contentType),\n })\n return\n }\n\n // If user is not logged in or is offline, we can't download private attachments.\n // If the blob was not stored locally (above) for some reason, the user is SOL\n if (!isAuthenticated || isOffline) {\n setAttachmentUrlState({\n attachmentUrl: null,\n })\n return\n }\n\n let ignore = false\n const abortController = new AbortController()\n const privateAttachmentUrl = value.url\n\n const effect = async () => {\n try {\n const blob = await urlToBlobAsync(\n privateAttachmentUrl,\n abortController.signal,\n )\n if (ignore) {\n return\n }\n // Store private attachment in Context\n storeAttachmentBlobLocally({ attachmentId: value.id, blob })\n const attachmentUrl = URL.createObjectURL(blob)\n console.log(\n 'Created object url from private attachment for image',\n attachmentUrl,\n )\n setAttachmentUrlState({\n attachmentUrl: attachmentUrl,\n })\n } catch (error) {\n if (ignore) {\n return\n }\n console.warn('Error loading file:', error)\n setAttachmentUrlState({\n loadAttachmentUrlError: error as Error,\n })\n }\n }\n effect()\n\n return () => {\n ignore = true\n abortController.abort()\n }\n }, [\n getAttachmentBlobLocally,\n isAuthenticated,\n isOffline,\n storeAttachmentBlobLocally,\n value,\n ])\n\n React.useEffect(() => {\n return () => {\n const attachmentUrl = attachmentUrlState.attachmentUrl\n if (attachmentUrl && attachmentUrl.startsWith('blob:')) {\n console.log('revoking attachment url:', attachmentUrl)\n URL.revokeObjectURL(attachmentUrl)\n }\n }\n }, [attachmentUrlState.attachmentUrl])\n\n const isUploading = React.useMemo(() => {\n return !!(\n value &&\n typeof value !== 'string' &&\n value.type &&\n value.type === 'NEW'\n )\n }, [value])\n\n const uploadErrorMessage = React.useMemo(() => {\n if (\n value &&\n typeof value !== 'string' &&\n value.type &&\n value.type === 'ERROR'\n ) {\n return value.errorMessage\n }\n }, [value])\n\n const canDownload = React.useMemo(() => {\n if (!value) {\n return false\n }\n\n // legacy attachment as base64 data\n if (typeof value === 'string') {\n return true\n }\n\n // attachments still uploading or failed to upload\n if (value.type) {\n // can only be downloaded if we still have the data\n return !!value.data\n }\n\n // private attachments can only be downloaded if user is authenticated\n if (isAuthenticated) {\n return true\n }\n\n return false\n }, [isAuthenticated, value])\n\n return {\n isUploading,\n uploadErrorMessage,\n isLoadingAttachmentUrl: attachmentUrlState.attachmentUrl === undefined,\n ...attachmentUrlState,\n canDownload,\n progress: progressState,\n }\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oneblink/apps-react",
3
3
  "description": "Helper functions for OneBlink apps in ReactJS.",
4
- "version": "6.8.0",
4
+ "version": "6.9.0-beta.2",
5
5
  "author": "OneBlink <developers@oneblink.io> (https://oneblink.io)",
6
6
  "bugs": {
7
7
  "url": "https://github.com/oneblink/apps-react/issues"