@oneblink/apps-react 8.9.2-beta.4 → 8.10.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ImageCropper/CropModal.d.ts +9 -0
- package/dist/components/ImageCropper/CropModal.js +28 -0
- package/dist/components/ImageCropper/CropModal.js.map +1 -0
- package/dist/components/ImageCropper/index.d.ts +20 -0
- package/dist/components/ImageCropper/index.js +111 -0
- package/dist/components/ImageCropper/index.js.map +1 -0
- package/dist/components/ImageCropper/resource-components.d.ts +10 -0
- package/dist/components/ImageCropper/resource-components.js +30 -0
- package/dist/components/ImageCropper/resource-components.js.map +1 -0
- package/dist/components/downloadable-files/resource-components.js +2 -5
- package/dist/components/downloadable-files/resource-components.js.map +1 -1
- package/dist/components/renderer/AnnotationModal.d.ts +4 -0
- package/dist/components/renderer/AnnotationModal.js +26 -2
- package/dist/components/renderer/AnnotationModal.js.map +1 -1
- package/dist/components/renderer/LookupNotification.js +1 -1
- package/dist/components/renderer/LookupNotification.js.map +1 -1
- package/dist/components/renderer/attachments/DropdownMenu.d.ts +2 -0
- package/dist/components/renderer/attachments/DropdownMenu.js +14 -2
- package/dist/components/renderer/attachments/DropdownMenu.js.map +1 -1
- package/dist/components/renderer/attachments/FileCard.d.ts +3 -1
- package/dist/components/renderer/attachments/FileCard.js +2 -2
- package/dist/components/renderer/attachments/FileCard.js.map +1 -1
- package/dist/form-elements/FormElementCamera.js +66 -49
- package/dist/form-elements/FormElementCamera.js.map +1 -1
- package/dist/form-elements/FormElementFile.js +80 -2
- package/dist/form-elements/FormElementFile.js.map +1 -1
- package/dist/hooks/attachments/useAttachment.d.ts +1 -0
- package/dist/hooks/attachments/useAttachment.js +3 -0
- package/dist/hooks/attachments/useAttachment.js.map +1 -1
- package/dist/hooks/attachments/useAttachments.js +3 -3
- package/dist/hooks/attachments/useAttachments.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/styles/camera.scss +31 -1
- package/dist/styles/downloadable-files.scss +4 -4
- package/dist/styles/utils.scss +4 -0
- package/dist/styles.css +39 -5
- package/package.json +2 -1
@@ -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, attachmentUrl, }) => {
|
6
|
+
const DropdownMenu = ({ element, onRemove, onDownload, onRetry, attachmentUrl, onAnnotate, onCrop, }) => {
|
7
7
|
const dropDownRef = React.useRef(null);
|
8
8
|
const [isShowingMore, showMore, hideMore] = useBooleanState(false);
|
9
9
|
useClickOutsideElement(dropDownRef, React.useCallback(() => {
|
@@ -41,7 +41,19 @@ const DropdownMenu = ({ element, onRemove, onDownload, onRetry, attachmentUrl, }
|
|
41
41
|
}), onClick: () => {
|
42
42
|
hideMore();
|
43
43
|
onRemove();
|
44
|
-
}, role: "menuitem" }, "Remove"))
|
44
|
+
}, role: "menuitem" }, "Remove")),
|
45
|
+
onAnnotate && (React.createElement("a", { className: clsx('dropdown-item cypress-file-annotate-button', {
|
46
|
+
'ob-files__menu-annotate-hidden': element.readOnly,
|
47
|
+
}), onClick: () => {
|
48
|
+
hideMore();
|
49
|
+
onAnnotate();
|
50
|
+
}, role: "menuitem" }, "Annotate")),
|
51
|
+
onCrop && (React.createElement("a", { className: clsx('dropdown-item cypress-file-crop-button', {
|
52
|
+
'ob-files__menu-crop-hidden': element.readOnly,
|
53
|
+
}), onClick: () => {
|
54
|
+
hideMore();
|
55
|
+
onCrop();
|
56
|
+
}, role: "menuitem" }, "Crop"))))));
|
45
57
|
};
|
46
58
|
export default React.memo(DropdownMenu);
|
47
59
|
//# sourceMappingURL=DropdownMenu.js.map
|
@@ -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;
|
1
|
+
{"version":3,"file":"DropdownMenu.js","sourceRoot":"","sources":["../../../../src/components/renderer/attachments/DropdownMenu.tsx"],"names":[],"mappings":"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","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 /** If set to `undefined`, the remove button will be hidden */\n onRemove: (() => void) | undefined\n onDownload?: () => void\n onRetry?: () => void\n attachmentUrl: string | null | undefined\n onAnnotate?: () => void\n onCrop?: () => void\n}\n\nconst DropdownMenu = ({\n element,\n onRemove,\n onDownload,\n onRetry,\n attachmentUrl,\n onAnnotate,\n onCrop,\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 onClick={() => {\n hideMore()\n }}\n >\n <span>Open</span>\n <MaterialIcon className=\"icon-small\">open_in_new</MaterialIcon>\n </a>\n )}\n {onRemove && (\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 )}\n {onAnnotate && (\n <a\n className={clsx('dropdown-item cypress-file-annotate-button', {\n 'ob-files__menu-annotate-hidden': element.readOnly,\n })}\n onClick={() => {\n hideMore()\n onAnnotate()\n }}\n role=\"menuitem\"\n >\n Annotate\n </a>\n )}\n {onCrop && (\n <a\n className={clsx('dropdown-item cypress-file-crop-button', {\n 'ob-files__menu-crop-hidden': element.readOnly,\n })}\n onClick={() => {\n hideMore()\n onCrop()\n }}\n role=\"menuitem\"\n >\n Crop\n </a>\n )}\n </div>\n </div>\n </div>\n )\n}\n\nexport default React.memo<Props>(DropdownMenu)\n"]}
|
@@ -14,9 +14,11 @@ type Props = {
|
|
14
14
|
onRemove: (() => void) | undefined;
|
15
15
|
onDownload?: () => void;
|
16
16
|
onRetry?: () => void;
|
17
|
+
onAnnotate?: () => void;
|
18
|
+
onCrop?: () => void;
|
17
19
|
progress: undefined | number;
|
18
20
|
index: number;
|
19
21
|
};
|
20
|
-
declare function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, progress, index, }: Props): React.JSX.Element;
|
22
|
+
declare function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, onAnnotate, onCrop, progress, index, }: Props): React.JSX.Element;
|
21
23
|
declare const _default: React.MemoExoticComponent<typeof FileCard>;
|
22
24
|
export default _default;
|
@@ -4,7 +4,7 @@ import AttachmentStatus from './AttachmentStatus';
|
|
4
4
|
import { checkFileNameIsValid, checkFileNameExtensionIsValid, } from '../../../services/form-validation/validators';
|
5
5
|
import ProgressBar from './ProgressBar';
|
6
6
|
import DropdownMenu from './DropdownMenu';
|
7
|
-
function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, progress, index, }) {
|
7
|
+
function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, loadAttachmentUrlError, isLoadingAttachmentUrl, isContentTypeImage, attachmentUrl, fileName, onDownload, onRemove, onRetry, onAnnotate, onCrop, 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`);
|
@@ -21,7 +21,7 @@ function FileCard({ element, isUploading, isUploadPaused, uploadErrorMessage, lo
|
|
21
21
|
React.createElement("div", { className: "ob-files__content" },
|
22
22
|
React.createElement("a", { href: attachmentUrl || '', target: "_blank", rel: "noreferrer", className: "cypress-file-download-button", style: { pointerEvents: attachmentUrl ? 'auto' : 'none' } },
|
23
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
|
+
React.createElement(DropdownMenu, { element: element, onDownload: onDownload, onRetry: onRetry, onRemove: onRemove, attachmentUrl: attachmentUrl || '', onAnnotate: onAnnotate, onCrop: onCrop }),
|
25
25
|
React.createElement("div", { className: "ob-files__file-name is-size-6" },
|
26
26
|
React.createElement("span", { className: "ob-files__file-name-inner" }, fileName),
|
27
27
|
React.createElement(AttachmentStatus, { isUploading: isUploading, isUploadPaused: isUploadPaused, uploadError: uploadError, loadAttachmentUrlError: loadAttachmentUrlError, isLoadingAttachmentUrl: isLoadingAttachmentUrl, attachmentUrl: attachmentUrl, progress: progress }),
|
@@ -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,8CAA8C,CAAA;AACrD,OAAO,WAAW,MAAM,eAAe,CAAA;AACvC,OAAO,YAAY,MAAM,gBAAgB,CAAA;
|
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,8CAA8C,CAAA;AACrD,OAAO,WAAW,MAAM,eAAe,CAAA;AACvC,OAAO,YAAY,MAAM,gBAAgB,CAAA;AAsBzC,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,UAAU,EACV,MAAM,EACN,QAAQ,EACR,KAAK,GACC;IACN,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC7C,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAA;QACxE,CAAC;QACD,IAAI,CAAC,6BAA6B,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;YACtD,OAAO,IAAI,KAAK,CAAC,GAAG,QAAQ,yBAAyB,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,kBAAkB,EAAE,CAAC;YACvB,OAAO,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;QACtC,CAAC;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,8BAA8B,EACxC,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,EAClC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,GACd;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/validators'\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 /** If set to `undefined`, the remove button will be hidden */\n onRemove: (() => void) | undefined\n onDownload?: () => void\n onRetry?: () => void\n onAnnotate?: () => void\n onCrop?: () => 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 onAnnotate,\n onCrop,\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=\"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 onAnnotate={onAnnotate}\n onCrop={onCrop}\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"]}
|
@@ -5,7 +5,7 @@ import OnLoading from '../components/renderer/OnLoading';
|
|
5
5
|
import FormElementLabelContainer from '../components/renderer/FormElementLabelContainer';
|
6
6
|
import drawTimestampOnCanvas from '../services/drawTimestampOnCanvas';
|
7
7
|
import useAttachment from '../hooks/attachments/useAttachment';
|
8
|
-
import AnnotationModal from '../components/renderer/AnnotationModal';
|
8
|
+
import AnnotationModal, { superimposeAnnotationOnImage, } from '../components/renderer/AnnotationModal';
|
9
9
|
import Modal from '../components/renderer/Modal';
|
10
10
|
import { checkIfContentTypeIsImage, prepareNewAttachment, correctFileOrientation, } from '../services/attachments';
|
11
11
|
import AttachmentStatus from '../components/renderer/attachments/AttachmentStatus';
|
@@ -15,12 +15,15 @@ import ProgressBar from '../components/renderer/attachments/ProgressBar';
|
|
15
15
|
import useElementAriaDescribedby from '../hooks/useElementAriaDescribedby';
|
16
16
|
import MaterialIcon from '../components/MaterialIcon';
|
17
17
|
import FormElementValidationMessage from '../components/renderer/FormElementValidationMessage';
|
18
|
+
import CropModal from '../components/ImageCropper/CropModal';
|
19
|
+
import { generateCroppedImageBlob } from '../components/ImageCropper';
|
18
20
|
function FormElementCamera({ id, element, value, onChange, validationMessage, displayValidationMessage, isDirty, setIsDirty, }) {
|
19
21
|
const ariaDescribedby = useElementAriaDescribedby(id, element);
|
20
22
|
const [{ cameraError, isLoading }, setState] = React.useState({
|
21
23
|
isLoading: false,
|
22
24
|
});
|
23
25
|
const [isAnnotating, setIsAnnotating, clearIsAnnotating] = useBooleanState(false);
|
26
|
+
const [isCropping, setIsCropping, clearIsCropping] = useBooleanState(false);
|
24
27
|
const fileInputRef = React.useRef(null);
|
25
28
|
const clearImage = React.useCallback(() => {
|
26
29
|
onChange(element, {
|
@@ -118,7 +121,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
|
|
118
121
|
console.error('Could not find "input" element in Camera component template');
|
119
122
|
}
|
120
123
|
}, [element, onChange]);
|
121
|
-
const { isUploading, uploadErrorMessage, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, canDownload, progress, } = useAttachment(value, element, React.useCallback((id, attachment) => {
|
124
|
+
const { isUploading, uploadErrorMessage, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, canDownload, progress, contentType, } = useAttachment(value, element, React.useCallback((id, attachment) => {
|
122
125
|
onChange(element, {
|
123
126
|
value: attachment,
|
124
127
|
});
|
@@ -148,7 +151,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
|
|
148
151
|
await downloadAttachment(value);
|
149
152
|
}
|
150
153
|
}, [value, id]);
|
151
|
-
const handleSaveAnnotation = React.useCallback((annotationDataUri) => {
|
154
|
+
const handleSaveAnnotation = React.useCallback(async (annotationDataUri) => {
|
152
155
|
clearIsAnnotating();
|
153
156
|
if (typeof attachmentUrl !== 'string') {
|
154
157
|
return;
|
@@ -156,56 +159,65 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
|
|
156
159
|
setState({
|
157
160
|
isLoading: true,
|
158
161
|
});
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
162
|
+
try {
|
163
|
+
const blob = await superimposeAnnotationOnImage({
|
164
|
+
annotationDataUri,
|
165
|
+
attachmentUrl,
|
166
|
+
});
|
167
|
+
setState({
|
168
|
+
isLoading: false,
|
169
|
+
});
|
170
|
+
if (blob) {
|
171
|
+
const attachment = prepareNewAttachment(blob, 'photo.png', element);
|
172
|
+
onChange(element, {
|
173
|
+
value: attachment,
|
174
|
+
});
|
175
|
+
}
|
176
|
+
}
|
177
|
+
catch (err) {
|
178
|
+
setState({
|
179
|
+
cameraError: err,
|
180
|
+
isLoading: false,
|
181
|
+
});
|
163
182
|
}
|
164
|
-
const image = new Image();
|
165
|
-
image.onload = function () {
|
166
|
-
canvas.width = image.width;
|
167
|
-
canvas.height = image.height;
|
168
|
-
ctx.drawImage(image, 0, 0);
|
169
|
-
const annotationImage = new Image();
|
170
|
-
annotationImage.onload = function () {
|
171
|
-
ctx.drawImage(annotationImage, 0, 0, canvas.width, canvas.height);
|
172
|
-
try {
|
173
|
-
canvasToBlob(canvas)
|
174
|
-
.then((blob) => {
|
175
|
-
const attachment = prepareNewAttachment(blob, 'photo.png', element);
|
176
|
-
onChange(element, {
|
177
|
-
value: attachment,
|
178
|
-
});
|
179
|
-
setState({
|
180
|
-
isLoading: false,
|
181
|
-
});
|
182
|
-
})
|
183
|
-
.catch((error) => {
|
184
|
-
setState({
|
185
|
-
cameraError: error,
|
186
|
-
isLoading: false,
|
187
|
-
});
|
188
|
-
});
|
189
|
-
}
|
190
|
-
catch (error) {
|
191
|
-
setState({
|
192
|
-
cameraError: error,
|
193
|
-
isLoading: false,
|
194
|
-
});
|
195
|
-
}
|
196
|
-
};
|
197
|
-
annotationImage.src = annotationDataUri;
|
198
|
-
};
|
199
|
-
image.setAttribute('crossorigin', 'anonymous');
|
200
|
-
image.src = attachmentUrl;
|
201
183
|
}, [attachmentUrl, clearIsAnnotating, element, onChange]);
|
184
|
+
const handleSaveCrop = React.useCallback(async (croppedAreaPixels) => {
|
185
|
+
clearIsCropping();
|
186
|
+
if (!attachmentUrl)
|
187
|
+
return;
|
188
|
+
setState({
|
189
|
+
isLoading: true,
|
190
|
+
});
|
191
|
+
try {
|
192
|
+
const croppedImage = await generateCroppedImageBlob({
|
193
|
+
croppedAreaPixels,
|
194
|
+
imgSrc: attachmentUrl,
|
195
|
+
fileType: contentType,
|
196
|
+
});
|
197
|
+
if (!croppedImage)
|
198
|
+
throw new Error('Cropped image is null');
|
199
|
+
const attachment = prepareNewAttachment(croppedImage, 'photo.png', element);
|
200
|
+
onChange(element, {
|
201
|
+
value: attachment,
|
202
|
+
});
|
203
|
+
setState({
|
204
|
+
isLoading: false,
|
205
|
+
});
|
206
|
+
}
|
207
|
+
catch (error) {
|
208
|
+
setState({
|
209
|
+
cameraError: error,
|
210
|
+
isLoading: false,
|
211
|
+
});
|
212
|
+
}
|
213
|
+
}, [attachmentUrl, clearIsCropping, contentType, element, onChange]);
|
202
214
|
const progressTooltipRef = React.useRef(null);
|
203
215
|
return (React.createElement(React.Fragment, null,
|
204
216
|
React.createElement(FormElementLabelContainer, { className: "ob-camera", element: element, id: id, required: element.required },
|
205
217
|
React.createElement("div", { className: "control" },
|
206
218
|
(value || isLoading) && (React.createElement(React.Fragment, null,
|
207
219
|
React.createElement("figure", { className: "ob-figure", ref: progressTooltipRef },
|
208
|
-
React.createElement(DisplayImage, { isUploading: isUploading, uploadErrorMessage: uploadErrorMessage, isLoadingAttachmentUrl: isLoadingAttachmentUrl, attachmentUrl: attachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isLoading: isLoading, element: element, onAnnotate: setIsAnnotating, canDownload: canDownload, progress: progress }),
|
220
|
+
React.createElement(DisplayImage, { isUploading: isUploading, uploadErrorMessage: uploadErrorMessage, isLoadingAttachmentUrl: isLoadingAttachmentUrl, attachmentUrl: attachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isLoading: isLoading, element: element, onAnnotate: setIsAnnotating, onCrop: setIsCropping, canDownload: canDownload, progress: progress }),
|
209
221
|
React.createElement(ProgressBar, { isShowing: isUploading, progress: progress })))),
|
210
222
|
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, "aria-required": element.required }),
|
211
223
|
React.createElement("div", { className: "buttons ob-buttons" }, value ? (React.createElement(React.Fragment, null,
|
@@ -217,6 +229,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
|
|
217
229
|
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")))),
|
218
230
|
(isDirty || displayValidationMessage) && !!validationMessage && (React.createElement(FormElementValidationMessage, { message: validationMessage }))),
|
219
231
|
isAnnotating && attachmentUrl && (React.createElement(AnnotationModal, { imageSrc: attachmentUrl, onClose: clearIsAnnotating, onSave: handleSaveAnnotation })),
|
232
|
+
isCropping && attachmentUrl && (React.createElement(CropModal, { imageSrc: attachmentUrl, onClose: clearIsCropping, onSave: handleSaveCrop })),
|
220
233
|
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") },
|
221
234
|
React.createElement("p", null,
|
222
235
|
"An error occurred while attempting to take a photo. Please click",
|
@@ -227,7 +240,7 @@ function FormElementCamera({ id, element, value, onChange, validationMessage, di
|
|
227
240
|
React.createElement("blockquote", null, cameraError.toString()))))));
|
228
241
|
}
|
229
242
|
export default React.memo(FormElementCamera);
|
230
|
-
const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUploading, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, isLoading, element, onAnnotate, progress, }) {
|
243
|
+
const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUploading, isLoadingAttachmentUrl, attachmentUrl, loadAttachmentUrlError, isLoading, element, onAnnotate, onCrop, progress, }) {
|
231
244
|
if (uploadErrorMessage) {
|
232
245
|
return (React.createElement("div", { className: "figure-content", role: "alert" },
|
233
246
|
React.createElement("h3", { className: "title is-3" }, "Upload Failed"),
|
@@ -253,9 +266,13 @@ const DisplayImage = React.memo(function DisplayImage({ uploadErrorMessage, isUp
|
|
253
266
|
React.createElement("span", { className: "ob-figure__status" },
|
254
267
|
React.createElement(AttachmentStatus, { isLoadingAttachmentUrl: isLoadingAttachmentUrl, loadAttachmentUrlError: loadAttachmentUrlError, isUploading: isUploading, attachmentUrl: attachmentUrl, progress: progress })),
|
255
268
|
React.createElement("img", { src: attachmentUrl, className: "cypress-camera-image ob-camera__img", crossOrigin: "anonymous", alt: `${element.label}: Attachment` }),
|
256
|
-
React.createElement("
|
257
|
-
React.createElement("
|
258
|
-
React.createElement(
|
269
|
+
React.createElement("div", { className: "ob-image-file__actions" },
|
270
|
+
React.createElement("button", { type: "button", className: "button is-primary ob-camera__crop-button cypress-crop-button", onClick: onCrop, disabled: element.readOnly },
|
271
|
+
React.createElement("span", { className: "icon" },
|
272
|
+
React.createElement(MaterialIcon, null, "crop"))),
|
273
|
+
React.createElement("button", { type: "button", className: "button is-primary ob-camera__annotate-button cypress-annotate-button", onClick: onAnnotate, disabled: element.readOnly },
|
274
|
+
React.createElement("span", { className: "icon" },
|
275
|
+
React.createElement(MaterialIcon, null, "brush"))))));
|
259
276
|
}
|
260
277
|
return (React.createElement("div", { className: "figure-content", role: "alert" },
|
261
278
|
React.createElement(ImagePreviewUnavailable, null)));
|
@@ -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'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\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 (!file.size) {\n throw new Error('You cannot upload an empty file.')\n }\n\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 aria-required={element.required}\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> 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 <FormElementValidationMessage message={validationMessage} />\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"]}
|
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, {\n superimposeAnnotationOnImage,\n} 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'\nimport FormElementValidationMessage from '../components/renderer/FormElementValidationMessage'\nimport CropModal from '../components/ImageCropper/CropModal'\nimport { Area } from 'react-easy-crop'\nimport { generateCroppedImageBlob } from '../components/ImageCropper'\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 [isCropping, setIsCropping, clearIsCropping] = useBooleanState(false)\n\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 (!file.size) {\n throw new Error('You cannot upload an empty file.')\n }\n\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 contentType,\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 async (annotationDataUri: string) => {\n clearIsAnnotating()\n\n if (typeof attachmentUrl !== 'string') {\n return\n }\n\n setState({\n isLoading: true,\n })\n try {\n const blob = await superimposeAnnotationOnImage({\n annotationDataUri,\n attachmentUrl,\n })\n setState({\n isLoading: false,\n })\n if (blob) {\n const attachment = prepareNewAttachment(blob, 'photo.png', element)\n onChange(element, {\n value: attachment,\n })\n }\n } catch (err) {\n setState({\n cameraError: err as Error,\n isLoading: false,\n })\n }\n },\n [attachmentUrl, clearIsAnnotating, element, onChange],\n )\n\n const handleSaveCrop = React.useCallback(\n async (croppedAreaPixels: Area) => {\n clearIsCropping()\n if (!attachmentUrl) return\n\n setState({\n isLoading: true,\n })\n\n try {\n const croppedImage = await generateCroppedImageBlob({\n croppedAreaPixels,\n imgSrc: attachmentUrl,\n fileType: contentType,\n })\n\n if (!croppedImage) throw new Error('Cropped image is null')\n const attachment = prepareNewAttachment(\n croppedImage,\n 'photo.png',\n element,\n )\n onChange(element, {\n value: attachment,\n })\n setState({\n isLoading: false,\n })\n } catch (error) {\n setState({\n cameraError: error as Error,\n isLoading: false,\n })\n }\n },\n [attachmentUrl, clearIsCropping, contentType, 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 onCrop={setIsCropping}\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 aria-required={element.required}\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> 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 <FormElementValidationMessage message={validationMessage} />\n )}\n </FormElementLabelContainer>\n\n {isAnnotating && attachmentUrl && (\n <AnnotationModal\n imageSrc={attachmentUrl}\n onClose={clearIsAnnotating}\n onSave={handleSaveAnnotation}\n />\n )}\n\n {isCropping && attachmentUrl && (\n <CropModal\n imageSrc={attachmentUrl}\n onClose={clearIsCropping}\n onSave={handleSaveCrop}\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 onCrop,\n progress,\n}: Omit<ReturnType<typeof useAttachment>, 'contentType'> & {\n element: FormTypes.CameraElement\n isLoading: boolean\n onAnnotate: () => void\n onCrop: () => 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 <div className=\"ob-image-file__actions\">\n <button\n type=\"button\"\n className=\"button is-primary ob-camera__crop-button cypress-crop-button\"\n onClick={onCrop}\n disabled={element.readOnly}\n >\n <span className=\"icon\">\n <MaterialIcon>crop</MaterialIcon>\n </span>\n </button>\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 </div>\n </>\n )\n }\n\n return (\n <div className=\"figure-content\" role=\"alert\">\n <ImagePreviewUnavailable />\n </div>\n )\n})\n"]}
|
@@ -2,8 +2,20 @@ import * as React from 'react';
|
|
2
2
|
import downloadAttachment from '../services/download-file';
|
3
3
|
import useAttachment from '../hooks/attachments/useAttachment';
|
4
4
|
import FileCard from '../components/renderer/attachments/FileCard';
|
5
|
+
import useBooleanState from '../hooks/useBooleanState';
|
6
|
+
import CropModal from '../components/ImageCropper/CropModal';
|
7
|
+
import AnnotationModal, { superimposeAnnotationOnImage, } from '../components/renderer/AnnotationModal';
|
8
|
+
import { generateCroppedImageBlob } from '../components/ImageCropper';
|
9
|
+
import { prepareNewAttachment } from '../services/attachments';
|
10
|
+
import Modal from '../components/renderer/Modal';
|
5
11
|
const FormElementFile = ({ element, onRemove, file, onChange, disableUpload, index, }) => {
|
6
|
-
const
|
12
|
+
const [isAnnotating, setIsAnnotating, clearIsAnnotating] = useBooleanState(false);
|
13
|
+
const [isCropping, setIsCropping, clearIsCropping] = useBooleanState(false);
|
14
|
+
const [state, setState] = React.useState({
|
15
|
+
isLoading: false,
|
16
|
+
error: undefined,
|
17
|
+
});
|
18
|
+
const { attachmentUrl, contentType, isUploading, uploadErrorMessage, isLoadingAttachmentUrl, loadAttachmentUrlError, isContentTypeImage, canDownload, progress, } = useAttachment(file, element, onChange, disableUpload);
|
7
19
|
const handleRemove = React.useMemo(() => {
|
8
20
|
if (!onRemove) {
|
9
21
|
return;
|
@@ -18,6 +30,61 @@ const FormElementFile = ({ element, onRemove, file, onChange, disableUpload, ind
|
|
18
30
|
const handleDownload = React.useCallback(async () => {
|
19
31
|
await downloadAttachment(file);
|
20
32
|
}, [file]);
|
33
|
+
const handleAnnotate = React.useCallback(async (annotationDataUri) => {
|
34
|
+
if (!attachmentUrl || file.type)
|
35
|
+
return;
|
36
|
+
clearIsAnnotating();
|
37
|
+
setState({
|
38
|
+
isLoading: true,
|
39
|
+
});
|
40
|
+
try {
|
41
|
+
const blob = await superimposeAnnotationOnImage({
|
42
|
+
annotationDataUri,
|
43
|
+
attachmentUrl,
|
44
|
+
});
|
45
|
+
setState({
|
46
|
+
isLoading: false,
|
47
|
+
});
|
48
|
+
if (!blob)
|
49
|
+
return;
|
50
|
+
const attachment = prepareNewAttachment(blob, file.fileName, element);
|
51
|
+
onChange(file.id, attachment);
|
52
|
+
}
|
53
|
+
catch (error) {
|
54
|
+
setState({
|
55
|
+
error: error,
|
56
|
+
isLoading: false,
|
57
|
+
});
|
58
|
+
}
|
59
|
+
}, [attachmentUrl, clearIsAnnotating, element, file, onChange]);
|
60
|
+
const handleSaveCrop = React.useCallback(async (croppedAreaPixels) => {
|
61
|
+
if (!attachmentUrl || file.type)
|
62
|
+
return;
|
63
|
+
clearIsCropping();
|
64
|
+
setState({
|
65
|
+
isLoading: true,
|
66
|
+
});
|
67
|
+
try {
|
68
|
+
const croppedImage = await generateCroppedImageBlob({
|
69
|
+
croppedAreaPixels,
|
70
|
+
imgSrc: attachmentUrl,
|
71
|
+
fileType: contentType,
|
72
|
+
});
|
73
|
+
setState({
|
74
|
+
isLoading: false,
|
75
|
+
});
|
76
|
+
if (!croppedImage)
|
77
|
+
return;
|
78
|
+
const attachment = prepareNewAttachment(croppedImage, file.fileName, element);
|
79
|
+
onChange(file.id, attachment);
|
80
|
+
}
|
81
|
+
catch (error) {
|
82
|
+
setState({
|
83
|
+
error: error,
|
84
|
+
isLoading: false,
|
85
|
+
});
|
86
|
+
}
|
87
|
+
}, [attachmentUrl, clearIsCropping, contentType, element, file, onChange]);
|
21
88
|
const handleRetry = React.useMemo(() => {
|
22
89
|
if (file.type === 'ERROR' && file.data) {
|
23
90
|
return () => {
|
@@ -31,7 +98,18 @@ const FormElementFile = ({ element, onRemove, file, onChange, disableUpload, ind
|
|
31
98
|
};
|
32
99
|
}
|
33
100
|
}, [file, onChange]);
|
34
|
-
return (React.createElement(
|
101
|
+
return (React.createElement(React.Fragment, null,
|
102
|
+
React.createElement(FileCard, { element: element, isUploading: isUploading, isUploadPaused: disableUpload, uploadErrorMessage: uploadErrorMessage, loadAttachmentUrlError: loadAttachmentUrlError, isLoadingAttachmentUrl: isLoadingAttachmentUrl || state.isLoading, attachmentUrl: attachmentUrl, isContentTypeImage: isContentTypeImage, fileName: file.fileName, onDownload: canDownload ? handleDownload : undefined, onRemove: handleRemove, onRetry: handleRetry, progress: progress, index: index, onAnnotate: setIsAnnotating, onCrop: setIsCropping }),
|
103
|
+
isCropping && attachmentUrl && (React.createElement(CropModal, { imageSrc: attachmentUrl, onClose: clearIsCropping, onSave: handleSaveCrop })),
|
104
|
+
isAnnotating && attachmentUrl && (React.createElement(AnnotationModal, { imageSrc: attachmentUrl, onClose: clearIsAnnotating, onSave: handleAnnotate })),
|
105
|
+
state.error && (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") },
|
106
|
+
React.createElement("p", null,
|
107
|
+
"An error occurred while attempting to edit an image. Please click",
|
108
|
+
' ',
|
109
|
+
React.createElement("b", null, "Okay"),
|
110
|
+
" below to try again. If the problem persists, please contact support."),
|
111
|
+
React.createElement("div", { className: "content has-margin-top-6" },
|
112
|
+
React.createElement("blockquote", null, state.error.toString()))))));
|
35
113
|
};
|
36
114
|
export default React.memo(FormElementFile);
|
37
115
|
//# 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;AAalE,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,OAAO,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAM;QACR,CAAC;QACD,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC1B,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC,CAAA;IACH,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,CAAC;YACvC,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;QACH,CAAC;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 /** If set to `undefined`, the remove button will be hidden */\n onRemove: ((id: string) => void) | undefined\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.useMemo(() => {\n if (!onRemove) {\n return\n }\n return () => {\n if (!file.type) {\n return onRemove(file.id)\n }\n return onRemove(file._id)\n }\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"]}
|
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;AAElE,OAAO,eAAe,MAAM,0BAA0B,CAAA;AACtD,OAAO,SAAS,MAAM,sCAAsC,CAAA;AAC5D,OAAO,eAAe,EAAE,EACtB,4BAA4B,GAC7B,MAAM,wCAAwC,CAAA;AAE/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,KAAK,MAAM,8BAA8B,CAAA;AAYhD,MAAM,eAAe,GAAG,CAAC,EACvB,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,KAAK,GACC,EAAE,EAAE;IACV,MAAM,CAAC,YAAY,EAAE,eAAe,EAAE,iBAAiB,CAAC,GACtD,eAAe,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,CAAC,UAAU,EAAE,aAAa,EAAE,eAAe,CAAC,GAAG,eAAe,CAAC,KAAK,CAAC,CAAA;IAC3E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,CAGrC;QACD,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAA;IACF,MAAM,EACJ,aAAa,EACb,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,WAAW,EACX,QAAQ,GACT,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAA;IAEzD,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAM;QACR,CAAC;QACD,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC1B,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC3B,CAAC,CAAA;IACH,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,cAAc,GAAG,KAAK,CAAC,WAAW,CACtC,KAAK,EAAE,iBAAyB,EAAE,EAAE;QAClC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI;YAAE,OAAM;QACvC,iBAAiB,EAAE,CAAA;QAEnB,QAAQ,CAAC;YACP,SAAS,EAAE,IAAI;SAChB,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,4BAA4B,CAAC;gBAC9C,iBAAiB;gBACjB,aAAa;aACd,CAAC,CAAA;YACF,QAAQ,CAAC;gBACP,SAAS,EAAE,KAAK;aACjB,CAAC,CAAA;YACF,IAAI,CAAC,IAAI;gBAAE,OAAM;YACjB,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YACrE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC;gBACP,KAAK,EAAE,KAAc;gBACrB,SAAS,EAAE,KAAK;aACjB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,EACD,CAAC,aAAa,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAC5D,CAAA;IACD,MAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CACtC,KAAK,EAAE,iBAAuB,EAAE,EAAE;QAChC,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,IAAI;YAAE,OAAM;QACvC,eAAe,EAAE,CAAA;QAEjB,QAAQ,CAAC;YACP,SAAS,EAAE,IAAI;SAChB,CAAC,CAAA;QAEF,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,wBAAwB,CAAC;gBAClD,iBAAiB;gBACjB,MAAM,EAAE,aAAa;gBACrB,QAAQ,EAAE,WAAW;aACtB,CAAC,CAAA;YACF,QAAQ,CAAC;gBACP,SAAS,EAAE,KAAK;aACjB,CAAC,CAAA;YACF,IAAI,CAAC,YAAY;gBAAE,OAAM;YACzB,MAAM,UAAU,GAAG,oBAAoB,CACrC,YAAY,EACZ,IAAI,CAAC,QAAQ,EACb,OAAO,CACR,CAAA;YACD,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC;gBACP,KAAK,EAAE,KAAc;gBACrB,SAAS,EAAE,KAAK;aACjB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,EACD,CAAC,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CACvE,CAAA;IACD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACvC,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;QACH,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEpB,OAAO,CACL;QACE,oBAAC,QAAQ,IACP,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,aAAa,EAC7B,kBAAkB,EAAE,kBAAkB,EACtC,sBAAsB,EAAE,sBAAsB,EAC9C,sBAAsB,EAAE,sBAAsB,IAAI,KAAK,CAAC,SAAS,EACjE,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EACvB,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,EACpD,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,aAAa,GACrB;QACD,UAAU,IAAI,aAAa,IAAI,CAC9B,oBAAC,SAAS,IACR,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,cAAc,GACtB,CACH;QACA,YAAY,IAAI,aAAa,IAAI,CAChC,oBAAC,eAAe,IACd,QAAQ,EAAE,aAAa,EACvB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,EAAE,cAAc,GACtB,CACH;QACA,KAAK,CAAC,KAAK,IAAI,CACd,oBAAC,KAAK,IACJ,MAAM,QACN,KAAK,EAAC,WAAW,EACjB,SAAS,EAAC,qBAAqB,EAC/B,cAAc,EAAC,qBAAqB,EACpC,OAAO,EACL,gCACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,wDAAwD,EAClE,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAC7C,SAAS,iBAGF;YAGX;;gBACoE,GAAG;gBACrE,sCAAW;wFAET;YAEJ,6BAAK,SAAS,EAAC,0BAA0B;gBACvC,wCAAa,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAc,CAC7C,CACA,CACT,CACA,CACJ,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'\nimport useBooleanState from '../hooks/useBooleanState'\nimport CropModal from '../components/ImageCropper/CropModal'\nimport AnnotationModal, {\n superimposeAnnotationOnImage,\n} from '../components/renderer/AnnotationModal'\nimport { Area } from 'react-easy-crop'\nimport { generateCroppedImageBlob } from '../components/ImageCropper'\nimport { prepareNewAttachment } from '../services/attachments'\nimport Modal from '../components/renderer/Modal'\n\ntype Props = {\n element: FormTypes.FilesElement\n /** If set to `undefined`, the remove button will be hidden */\n onRemove: ((id: string) => void) | undefined\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 [isAnnotating, setIsAnnotating, clearIsAnnotating] =\n useBooleanState(false)\n const [isCropping, setIsCropping, clearIsCropping] = useBooleanState(false)\n const [state, setState] = React.useState<{\n isLoading: boolean\n error?: Error\n }>({\n isLoading: false,\n error: undefined,\n })\n const {\n attachmentUrl,\n contentType,\n isUploading,\n uploadErrorMessage,\n isLoadingAttachmentUrl,\n loadAttachmentUrlError,\n isContentTypeImage,\n canDownload,\n progress,\n } = useAttachment(file, element, onChange, disableUpload)\n\n const handleRemove = React.useMemo(() => {\n if (!onRemove) {\n return\n }\n return () => {\n if (!file.type) {\n return onRemove(file.id)\n }\n return onRemove(file._id)\n }\n }, [file, onRemove])\n\n const handleDownload = React.useCallback(async () => {\n await downloadAttachment(file)\n }, [file])\n\n const handleAnnotate = React.useCallback(\n async (annotationDataUri: string) => {\n if (!attachmentUrl || file.type) return\n clearIsAnnotating()\n\n setState({\n isLoading: true,\n })\n\n try {\n const blob = await superimposeAnnotationOnImage({\n annotationDataUri,\n attachmentUrl,\n })\n setState({\n isLoading: false,\n })\n if (!blob) return\n const attachment = prepareNewAttachment(blob, file.fileName, element)\n onChange(file.id, attachment)\n } catch (error) {\n setState({\n error: error as Error,\n isLoading: false,\n })\n }\n },\n [attachmentUrl, clearIsAnnotating, element, file, onChange],\n )\n const handleSaveCrop = React.useCallback(\n async (croppedAreaPixels: Area) => {\n if (!attachmentUrl || file.type) return\n clearIsCropping()\n\n setState({\n isLoading: true,\n })\n\n try {\n const croppedImage = await generateCroppedImageBlob({\n croppedAreaPixels,\n imgSrc: attachmentUrl,\n fileType: contentType,\n })\n setState({\n isLoading: false,\n })\n if (!croppedImage) return\n const attachment = prepareNewAttachment(\n croppedImage,\n file.fileName,\n element,\n )\n onChange(file.id, attachment)\n } catch (error) {\n setState({\n error: error as Error,\n isLoading: false,\n })\n }\n },\n [attachmentUrl, clearIsCropping, contentType, element, file, onChange],\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 <>\n <FileCard\n element={element}\n isUploading={isUploading}\n isUploadPaused={disableUpload}\n uploadErrorMessage={uploadErrorMessage}\n loadAttachmentUrlError={loadAttachmentUrlError}\n isLoadingAttachmentUrl={isLoadingAttachmentUrl || state.isLoading}\n attachmentUrl={attachmentUrl}\n isContentTypeImage={isContentTypeImage}\n fileName={file.fileName}\n onDownload={canDownload ? handleDownload : undefined}\n onRemove={handleRemove}\n onRetry={handleRetry}\n progress={progress}\n index={index}\n onAnnotate={setIsAnnotating}\n onCrop={setIsCropping}\n />\n {isCropping && attachmentUrl && (\n <CropModal\n imageSrc={attachmentUrl}\n onClose={clearIsCropping}\n onSave={handleSaveCrop}\n />\n )}\n {isAnnotating && attachmentUrl && (\n <AnnotationModal\n imageSrc={attachmentUrl}\n onClose={clearIsAnnotating}\n onSave={handleAnnotate}\n />\n )}\n {state.error && (\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 edit an image. 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>{state.error.toString()}</blockquote>\n </div>\n </Modal>\n )}\n </>\n )\n}\n\nexport default React.memo<Props>(FormElementFile)\n"]}
|
@@ -5,6 +5,7 @@ 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
|
+
contentType: string | undefined;
|
8
9
|
attachmentUrl?: string | null;
|
9
10
|
loadAttachmentUrlError?: Error;
|
10
11
|
isContentTypeImage?: boolean;
|