diff --git a/builder/src/components/DragDropFileInput.tsx b/builder/src/components/DragDropFileInput.tsx index 3456e316f..3f446cf82 100644 --- a/builder/src/components/DragDropFileInput.tsx +++ b/builder/src/components/DragDropFileInput.tsx @@ -1,13 +1,19 @@ -import React, { CSSProperties, useEffect, useRef, useState } from "react"; +import React, { + CSSProperties, + MutableRefObject, + useEffect, + useState, +} from "react"; interface DragDropFileInputProps { title: string; onChange?: (files: FileList) => void; readonly?: boolean; + fileInputRef: MutableRefObject; } export const DragDropFileInput: React.FC = (props) => { - const fileInputRef = useRef(null); + const fileInput = props.fileInputRef.current; const [fileDropStyle, setFileDropStyle] = useState({}); const [lastTarget, setLastTarget] = useState(null); const [isDragging, setIsDragging] = useState(false); @@ -39,8 +45,7 @@ export const DragDropFileInput: React.FC = (props) => { }; const fileChange = () => { if (!props.readonly) { - const inp = fileInputRef.current; - const files = inp?.files; + const files = fileInput?.files; if (props.onChange && files) { props.onChange(files); } @@ -49,9 +54,8 @@ export const DragDropFileInput: React.FC = (props) => { }; const onDrop = (e: React.DragEvent) => { if (!props.readonly) { - const inp = fileInputRef.current; - if (inp) { - inp.files = e.dataTransfer.files; + if (fileInput) { + fileInput.files = e.dataTransfer.files; } if (props.onChange) { props.onChange(e.dataTransfer.files); @@ -92,7 +96,7 @@ export const DragDropFileInput: React.FC = (props) => { type="file" name="newfile" style={{ display: "none" }} - ref={fileInputRef} + ref={props.fileInputRef} onChange={fileChange} disabled={props.readonly} /> diff --git a/builder/src/upload.tsx b/builder/src/upload.tsx index eea5b6f92..916cb7754 100644 --- a/builder/src/upload.tsx +++ b/builder/src/upload.tsx @@ -1,5 +1,5 @@ import * as Sentry from "@sentry/browser"; -import React, { useEffect, useState } from "react"; +import React, { useRef, useEffect, useState } from "react"; import { Community, ExperimentalApi, @@ -19,6 +19,7 @@ import { FormSelectField } from "./components/FormSelectField"; import { CommunityCategorySelector } from "./components/CommunitySelector"; import { FormRow } from "./components/FormRow"; import { SubmitPackage } from "./api/packageSubmit"; +import { validateZip } from "./uploadZipValidation"; function getUploadProgressBarcolor(uploadStatus: FileUploadStatus | undefined) { if (uploadStatus == FileUploadStatus.CANCELED) { @@ -42,17 +43,16 @@ function getSubmissionProgressBarcolor( return "bg-warning"; } -class FormErrors { - fileError: string | null = null; +export class FormErrors { teamError: string | null = null; communitiesError: string | null = null; categoriesError: string | null = null; nsfwError: string | null = null; generalErrors: string[] = []; + fileErrors: string[] = []; get hasErrors(): boolean { return !( - this.fileError == null && this.teamError == null && this.communitiesError == null && this.categoriesError == null && @@ -81,6 +81,7 @@ const SubmissionForm: React.FC = observer((props) => { const [formErrors, setFormErrors] = useState(new FormErrors()); const [file, setFile] = useState(null); const [fileUpload, setFileUpload] = useState(null); + const fileInputRef = useRef(null); const [ submissionStatus, setSubmissionStatus, @@ -115,6 +116,12 @@ const SubmissionForm: React.FC = observer((props) => { if (fileUpload) { await fileUpload.cancelUpload(); } + + const input = fileInputRef.current; + if (input) { + input.value = ""; + } + setFileUpload(null); setSubmissionStatus(null); setFormErrors(new FormErrors()); @@ -130,13 +137,32 @@ const SubmissionForm: React.FC = observer((props) => { const onFileChange = (files: FileList) => { const file = files.item(0); setFile(file); + + if (file) { + validateZip(file).then((result) => { + if (result.errors.fileErrors.length > 0) { + setFormErrors(result.errors); + + if (result.blockUpload) { + result.errors.generalErrors.push( + "An error with your selected file is preventing submission." + ); + setSubmissionStatus(SubmissionStatus.ERROR); + } + } + }); + } }; const onSubmit = async (data: any) => { // TODO: Convert to react-hook-form validation + + let fileErrors = formErrors.fileErrors; setFormErrors(new FormErrors()); const errors = new FormErrors(); + errors.fileErrors = fileErrors; + const uploadTeam = data.team ? data.team.value : null; const uploadCommunities = data.communities ? data.communities.map((com: any) => com.value) @@ -245,6 +271,8 @@ const SubmissionForm: React.FC = observer((props) => { (fileUpload?.uploadErrors ?? []).length > 0 || formErrors.generalErrors.length > 0; + const hasFileErrors = formErrors.fileErrors.length > 0; + const hasEtagError = fileUpload && fileUpload.uploadErrors.some( @@ -296,9 +324,18 @@ const SubmissionForm: React.FC = observer((props) => { title={file ? file.name : "Choose or drag file here"} onChange={onFileChange} readonly={!!file} + fileInputRef={fileInputRef} /> - + {hasFileErrors && ( +
+
    + {formErrors.fileErrors.map((e, idx) => ( +
  • {e}
  • + ))} +
+
+ )} {currentCommunity != null && teams != null && communities != null ? ( @@ -371,7 +408,11 @@ const SubmissionForm: React.FC = observer((props) => {