diff --git a/src/components/views/dialogs/ExportDialog.tsx b/src/components/views/dialogs/ExportDialog.tsx index 8cefffaa9f..c4eb031aa5 100644 --- a/src/components/views/dialogs/ExportDialog.tsx +++ b/src/components/views/dialogs/ExportDialog.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useRef, useState } from "react"; import { Room } from "matrix-js-sdk/src"; import { _t } from "../../../languageHandler"; import { IDialogProps } from "./IDialogProps"; @@ -13,6 +13,7 @@ import exportConversationalHistory, { textForFormat, textForType, } from "../../../utils/exportUtils/exportUtils"; +import { IFieldState, IValidationResult } from "../elements/Validation"; interface IProps extends IDialogProps { room: Room; @@ -22,10 +23,26 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { const [exportFormat, setExportFormat] = useState("HTML"); const [exportType, setExportType] = useState("TIMELINE"); const [includeAttachments, setAttachments] = useState(false); - const [numberOfMessages, setNumberOfMessages] = useState(); + const [numberOfMessages, setNumberOfMessages] = useState(100); const [sizeLimit, setSizeLimit] = useState(8); + const [sizeLimitRef, messageCountRef] = [useRef(), useRef()]; const onExportClick = async () => { + const isValidSize = await sizeLimitRef.current.validate({ + focused: false, + }); + if (!isValidSize) { + sizeLimitRef.current.validate({ focused: true }); + return; + } + if (exportType === exportTypes.LAST_N_MESSAGES) { + const isValidNumberOfMessages = + await messageCountRef.current.validate({ focused: false }); + if (!isValidNumberOfMessages) { + messageCountRef.current.validate({ focused: true }); + return; + } + } await exportConversationalHistory( room, exportFormats[exportFormat], @@ -38,6 +55,69 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { ); }; + const onValidateSize = async ({ + value, + }: Pick): Promise => { + const parsedSize = parseFloat(value); + const min = 1; + const max = 4000; + + if (isNaN(parsedSize)) { + return { valid: false, feedback: _t("Size must be a number") }; + } + + if (!(min <= parsedSize && parsedSize <= max)) { + return { + valid: false, + feedback: _t( + "Size can only be between %(min)s MB and %(max)s MB", + { min, max }, + ), + }; + } + + return { + valid: true, + feedback: _t("Enter size between %(min)s MB and %(max)s MB", { + min, + max, + }), + }; + }; + + const onValidateNumberOfMessages = async ({ + value, + }: Pick): Promise => { + const parsedSize = parseFloat(value); + const min = 1; + const max = 10 ** 8; + + if (isNaN(parsedSize)) { + return { + valid: false, + feedback: _t("Number of messages must be a number"), + }; + } + + if (!(min <= parsedSize && parsedSize <= max)) { + return { + valid: false, + feedback: _t( + "Number of messages can only be between %(min)s and %(max)s", + { min, max }, + ), + }; + } + + return { + valid: true, + feedback: _t("Enter a number between %(min)s and %(max)s", { + min, + max, + }), + }; + }; + const onCancel = () => { onFinished(false); }; @@ -54,23 +134,24 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { ); }); - let MessageCount = null; if (exportType === exportTypes.LAST_N_MESSAGES) { MessageCount = ( { setNumberOfMessages(parseInt(e.target.value)); }} - type="number" /> ); } - const sizePostFix = ({_t("MB")}); + const sizePostFix = {_t("MB")}; return ( = ({ room, onFinished }) => { > {exportTypeOptions} - { MessageCount } + {MessageCount} {_t("Size Limit")} @@ -116,9 +197,12 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { setSizeLimit(e.target.value)} + onChange={(e) => setSizeLimit(parseInt(e.target.value))} />