Skip to content

Commit

Permalink
Add drag and drop support for document form
Browse files Browse the repository at this point in the history
  • Loading branch information
indigane committed Aug 30, 2024
1 parent caff239 commit 9dbb453
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 15 deletions.
102 changes: 102 additions & 0 deletions frontend/src/common/components/FileDropZone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, {useEffect} from "react";

interface FileDropZoneProps {
onDraggingChange?: (isDragging: boolean) => void;
onFileDrop: (files: FileList) => void;
helpText?: string;
}

export default function FileDropZone({
onDraggingChange = () => {},
onFileDrop,
helpText,
}: FileDropZoneProps): React.JSX.Element {
useEffect(() => {
let isDragging = document.documentElement.classList.contains("is-dragging");
let dragEndTimeout;

const startDrag = () => {
if (!isDragging) {
isDragging = true;
document.documentElement.classList.add("is-dragging");
onDraggingChange(true);
// Failsafe in case the dragleave is somehow missed and the user is no longer dragging
window.addEventListener("mousemove", handleMouseMove);
}
};

const endDrag = () => {
if (isDragging) {
isDragging = false;
document.documentElement.classList.remove("is-dragging");
onDraggingChange(false);
document
.querySelector(".file-drop-zone.is-dragging-over-drop-zone")
?.classList.remove("is-dragging-over-drop-zone");
window.removeEventListener("mousemove", handleMouseMove);
}
};

const handleDragEnter = (event) => {
event.preventDefault();
dragEndTimeout = clearTimeout(dragEndTimeout);
startDrag();
if (event.target.classList.contains("file-drop-zone")) {
event.target.classList.add("is-dragging-over-drop-zone");
}
};

const handleDragOver = (event) => {
event.preventDefault();
dragEndTimeout = clearTimeout(dragEndTimeout);
};

const handleDragLeave = (event) => {
event.preventDefault();
dragEndTimeout = setTimeout(endDrag, 200);
if (event.target.classList.contains("file-drop-zone")) {
event.target.classList.remove("is-dragging-over-drop-zone");
}
};

const handleDrop = (event) => {
event.preventDefault();
endDrag();
if (
event.target.classList.contains("file-drop-zone") &&
event.dataTransfer.files &&
event.dataTransfer.files.length > 0
) {
onFileDrop(event.dataTransfer.files);
}
};

const handleMouseMove = (event) => {
// Failsafe in case the dragleave is somehow missed and the user is no longer dragging
if (event.buttons === 0) {
endDrag();
}
};

window.addEventListener("dragenter", handleDragEnter);
window.addEventListener("dragover", handleDragOver);
window.addEventListener("dragleave", handleDragLeave);
window.addEventListener("drop", handleDrop);

return () => {
window.removeEventListener("dragenter", handleDragEnter);
window.removeEventListener("dragover", handleDragOver);
window.removeEventListener("dragleave", handleDragLeave);
window.removeEventListener("drop", handleDrop);
window.removeEventListener("mousemove", handleMouseMove);
};
}, [onDraggingChange]);

return (
<>
<div className="file-drop-zone">
<div className="file-drop-zone-helptext">{helpText ?? "Pudota tiedostot tähän."}</div>
</div>
</>
);
}
55 changes: 41 additions & 14 deletions frontend/src/common/components/GenericDocumentsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useCallback, useRef, useState} from "react";
import {SubmitHandler, useFieldArray, useForm, useFormContext} from "react-hook-form";
import {IApartmentDetails, IHousingCompanyDetails} from "../schemas";
import {FileInput, FormProviderForm, TextInput} from "./forms";
import {ConfirmDialogModal, SaveButton} from "./index";
import {ConfirmDialogModal, FileDropZone, SaveButton} from "./index";

import {zodResolver} from "@hookform/resolvers/zod";
import {useNavigate} from "react-router-dom";
Expand Down Expand Up @@ -135,6 +135,7 @@ const DocumentsListItems = ({name, remove}) => {
formObject.setValue(`${name}.${index}.file_object`, filesArray[0], {shouldDirty: true});
}}
required={!document.file_link}
defaultValue={document.file_object ? [document.file_object] : []}
/>
{!document.file_object && document.file_link && (
<a
Expand Down Expand Up @@ -201,17 +202,6 @@ export const DocumentFieldSet = ({fieldsetHeader, name}) => {
);
};

const DocumentFieldSets = ({apartment}) => {
return (
<div className="field-sets">
<DocumentFieldSet
fieldsetHeader={apartment === undefined ? "Taloyhtiön dokumentit" : "Asunnon dokumentit"}
name="documents"
/>
</div>
);
};

type IGenericDocumentsPage = {
housingCompany: IHousingCompanyDetails;
apartment?: IApartmentDetails;
Expand Down Expand Up @@ -265,6 +255,16 @@ const GenericDocumentsPage = ({housingCompany, apartment}: IGenericDocumentsPage
mode: "all",
});

const {
fields: documentFields,
append: appendDocument,
remove: removeDocument,
} = useFieldArray({
name: "documents",
control: formObject.control,
});
formObject.register("documents");

// API Handling
const [saveDocument, {isSaveLoading}] = saveDocumentHook();
const [deleteDocument, {isDeleteLoading}] = deleteDocumentHook();
Expand Down Expand Up @@ -335,8 +335,35 @@ const GenericDocumentsPage = ({housingCompany, apartment}: IGenericDocumentsPage
) : (
""
)}
<DocumentFieldSets apartment={apartment} />

<div className="field-sets">
<Fieldset heading={apartment === undefined ? "Taloyhtiön dokumentit" : "Asunnon dokumentit"}>
<ul className="documents-list">
{documentFields.length ? (
<DocumentsListItems
name="documents"
remove={removeDocument}
/>
) : (
<div>Ei dokumentteja</div>
)}
<li className="row row--buttons">
<DocumentAddEmptyLineButton append={appendDocument} />
</li>
</ul>
</Fieldset>
<FileDropZone
onFileDrop={(files) => {
for (const file of files) {
appendDocument({
...emptyDocument,
key: uuidv4(),
file_object: file,
});
}
}}
helpText="Pudota tiedostot tähän lisätäksesi ne dokumenteiksi."
/>
</div>
<div className="row row--buttons">
<Button
iconLeft={<IconArrowLeft />}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/common/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {default as DetailField} from "./DetailField";
export {default as Divider} from "./Divider";
export {default as DownloadButton} from "./DownloadButton";
export {default as EditButton} from "./EditButton";
export {default as FileDropZone} from "./FileDropZone";
export {default as GenericActionModal} from "./GenericActionModal";
export {default as GenericDocumentsPage} from "./GenericDocumentsPage";
export {default as GenericImprovementsPage} from "./GenericImprovementsPage";
Expand Down
1 change: 1 addition & 0 deletions frontend/src/styles/components/_Documents.sass
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

.view--create-documents
.field-sets
position: relative
background-color: $color-black-5

.document-list-item-file-row
Expand Down
32 changes: 32 additions & 0 deletions frontend/src/styles/components/_FileDropZone.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@use "../imports" as *

.file-drop-zone
display: none
.is-dragging &
display: grid
place-items: center
position: absolute
top: 0
left: 0
right: 0
bottom: 0
width: auto
height: auto
background: rgba($color-white, 0.90)
border: 2px dotted rgba($color-coat-of-arms, 0.90)
&.is-dragging-over-drop-zone
background: rgba($color-bus-light, 0.95)
border-color: rgba($color-coat-of-arms, 1)
transition: all 200ms ease-in-out

.file-drop-zone-helptext
display: grid
place-items: center
top: 0%
bottom: 30%
position: sticky
font-size: 28px
font-weight: 700
height: 250px
pointer-events: none
color: $color-coat-of-arms
1 change: 1 addition & 0 deletions frontend/src/styles/components/index.sass
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@forward "CreatePage"
@forward "DialogModule"
@forward "Documents"
@forward "FileDropZone"
@forward "Forms"
@forward "Functions"
@forward "HousingCompanyList"
Expand Down
2 changes: 1 addition & 1 deletion frontend/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2015",
"lib": [
"dom",
"dom.iterable",
Expand Down

0 comments on commit 9dbb453

Please sign in to comment.