From b2efe471420e99181c79430bff3afa4edc7082a2 Mon Sep 17 00:00:00 2001 From: Paul Abumov Date: Mon, 19 Feb 2024 14:52:44 -0500 Subject: [PATCH] [Form Builder] Added file review modal in TaskReview --- .../review_app/client/src/consts/review.ts | 60 +++ .../InReviewFileModal/InReviewFileModal.css | 91 ++++ .../InReviewFileModal/InReviewFileModal.tsx | 106 ++++ .../TaskPage/ReviewModal/ReviewModal.tsx | 8 +- .../client/src/pages/TaskPage/TaskPage.tsx | 35 +- .../client/src/types/inReviewFileModal.d.ts | 11 + mephisto/review_app/client/src/urls.ts | 1 + .../review_app/server/api/views/__init__.py | 1 + .../server/api/views/unit_data_static_view.py | 59 +++ mephisto/review_app/server/urls.py | 4 + .../react-form-composer/package-lock.json | 460 +++++++++++++++++- packages/react-form-composer/package.json | 1 + .../src/FormComposer/FormComposer.css | 24 + .../src/FormComposer/FormComposer.js | 19 +- .../src/FormComposer/constants.js | 2 + .../src/FormComposer/fields/FileField.js | 28 +- 16 files changed, 892 insertions(+), 18 deletions(-) create mode 100644 mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.css create mode 100644 mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.tsx create mode 100644 mephisto/review_app/client/src/types/inReviewFileModal.d.ts create mode 100644 mephisto/review_app/server/api/views/unit_data_static_view.py diff --git a/mephisto/review_app/client/src/consts/review.ts b/mephisto/review_app/client/src/consts/review.ts index 85b79e5d6..5160624b8 100644 --- a/mephisto/review_app/client/src/consts/review.ts +++ b/mephisto/review_app/client/src/consts/review.ts @@ -9,3 +9,63 @@ export const ReviewType = { REJECT: "reject", SOFT_REJECT: "softReject", }; + +export const MESSAGES_IFRAME_DATA_KEY = "IFRAME_DATA"; + +export const MESSAGES_IN_REVIEW_FILE_DATA_KEY = "IN_REVIEW_FILE_DATA"; + +export const FILE_EXT_TYPES = { + image: [ + "png", + "jpg", + "jpeg", + "gif", + "webp", + "bmp", + ], + video: [ + "mkv", + "mp4", + "webm", + ], + audio: [ + "mp3", + "ogg", + "wav", + ], +}; + +export const FileType = { + AUDIO: "audio", + IMAGE: "image", + PDF: "pdf", + VIDEO: "video", +}; + +export const FILE_TYPE_BY_EXT = { + "png": FileType.IMAGE, + "jpg": FileType.IMAGE, + "jpeg": FileType.IMAGE, + "gif": FileType.IMAGE, + "webp": FileType.IMAGE, + "bmp": FileType.IMAGE, + "mkv": FileType.VIDEO, + "mp4": FileType.VIDEO, + "webm": FileType.VIDEO, + "mp3": FileType.AUDIO, + "ogg": FileType.AUDIO, + "wav": FileType.AUDIO, + "pdf": FileType.PDF, +}; + +export const AUDIO_TYPES_BY_EXT = { + "mp3": "audio/mpeg", + "ogg": "audio/ogg", + "wav": "audio/wav", +}; + +export const VIDEO_TYPES_BY_EXT = { + "mkv": "video/x-matroska", + "mp4": "video/mp4", + "webm": "video/webm", +}; diff --git a/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.css b/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.css new file mode 100644 index 000000000..dd3c6e06b --- /dev/null +++ b/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.css @@ -0,0 +1,91 @@ +/* + * Copyright (c) Meta Platforms and its affiliates. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +.in-review-file-modal .modal-dialog { + max-width: 98vw; + min-width: 500px; + width: fit-content; +} + +.in-review-file-modal .modal-dialog .modal-header { + background-color: #ecdadf; + display: flex; + justify-content: space-between; + padding: 5px; + border-radius: 0; +} + +.in-review-file-modal .modal-dialog .modal-header .button-close { + height: 38px; + width: 38px; + display: flex; + justify-content: center; + align-items: center; + background-color: transparent; + border: none; + font-size: 38px; + line-height: 1; + cursor: pointer; +} + +.in-review-file-modal .modal-dialog .modal-header .button-download-file { + height: 38px; + width: 38px; + display: flex; + justify-content: center; + align-items: center; + background-color: transparent; + border: none; + font-size: 30px; + line-height: 1; + cursor: pointer; + text-decoration: none; + color: black; +} + +.in-review-file-modal .modal-dialog .modal-header .button-close:hover, +.in-review-file-modal .modal-dialog .modal-header .button-download-file:hover { + opacity: 0.7; + background-color: lightgrey; +} + +.in-review-file-modal .modal-dialog .modal-header .modal-title { + font-size: 26px; +} + +/* Body */ +.in-review-file-modal .modal-dialog .modal-content { + border-radius: initial; + width: fit-content; + min-width: 500px; +} + +.in-review-file-modal .modal-dialog .modal-content .modal-body { + /*width: fit-content;*/ + display: flex; + flex-direction: row; + justify-content: center; +} + +.in-review-file-modal .modal-dialog .modal-content .modal-body img, +.in-review-file-modal .modal-dialog .modal-content .modal-body video { + width: fit-content; + max-width: 100%; +} + +.in-review-file-modal .modal-dialog .modal-content .modal-body .iframe-wrapper { + position: relative; + width: 100%; + padding-top: calc(129% + 2%); +} +.in-review-file-modal .modal-dialog .modal-content .modal-body iframe { + position: absolute; + top: 0; + width: 100%; + height: 100%; + background-color: #f2f2f2; + border: 1px solid #cccccc; +} diff --git a/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.tsx b/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.tsx new file mode 100644 index 000000000..f1069d408 --- /dev/null +++ b/mephisto/review_app/client/src/pages/TaskPage/InReviewFileModal/InReviewFileModal.tsx @@ -0,0 +1,106 @@ +/* + * Copyright (c) Meta Platforms and its affiliates. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import { AUDIO_TYPES_BY_EXT, FILE_TYPE_BY_EXT, FileType, VIDEO_TYPES_BY_EXT } from "consts/review"; +import * as React from "react"; +import { useEffect } from "react"; +import { Modal } from "react-bootstrap"; +import urls from "urls"; +import "./InReviewFileModal.css"; + + +type InReviewFileModalProps = { + data: InReviewFileModalDataType; + setData: React.Dispatch>; + show: boolean; + setShow: React.Dispatch>; +}; + +function InReviewFileModal(props: InReviewFileModalProps) { + const { data, show, setShow } = props; + + const [fileUrl, setFileUrl] = React.useState(null); + const [fileExt, setFileExt] = React.useState(null); + + const fileType = FILE_TYPE_BY_EXT[fileExt]; + + function onModalClose() { + setShow(!show); + } + + function truncateFilename(filename: string, n: number): string { + const ext = data.filename.split(".").pop(); + const _filename = (filename.length > n) + ? (filename.slice(0, (n - 1 - ext.length)) + "…" + "." + ext) + : filename; + return _filename; + } + + useEffect(() => { + setFileUrl(null); + setFileExt(null); + + if (data.filename) { + setFileUrl(urls.server.unitFile(data.unitId, data.filename)); + setFileExt(data.filename.split(".").pop().toLowerCase()); + } + }, [data]); + + return ( + show && ( + + + + + {truncateFilename(data.title, 50)} + + + ⤓ + + + + + {fileType ? (<> + {fileType === FileType.IMAGE && ( + {`image + )} + {fileType === FileType.VIDEO && ( + + )} + {fileType === FileType.AUDIO && ( + + )} + {fileType === FileType.PDF && ( +
+