| import React from "react"; | |
| import { Modal, Group, Button, TextInput, Stack, Divider, ModalProps } from "@mantine/core"; | |
| import styled from "styled-components"; | |
| import toast from "react-hot-toast"; | |
| import { AiOutlineUpload } from "react-icons/ai"; | |
| import useFile from "src/store/useFile"; | |
| const StyledUploadWrapper = styled.label` | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| background: ${({ theme }) => theme.GRID_BG_COLOR}; | |
| border: 2px dashed ${({ theme }) => theme.BACKGROUND_TERTIARY}; | |
| border-radius: 5px; | |
| min-height: 200px; | |
| padding: 16px; | |
| cursor: pointer; | |
| input[type="file"] { | |
| display: none; | |
| } | |
| `; | |
| const StyledFileName = styled.span` | |
| padding-top: 14px; | |
| color: ${({ theme }) => theme.INTERACTIVE_NORMAL}; | |
| `; | |
| const StyledUploadMessage = styled.h3` | |
| color: ${({ theme }) => theme.INTERACTIVE_ACTIVE}; | |
| margin-bottom: 0; | |
| `; | |
| export const ImportModal: React.FC<ModalProps> = ({ opened, onClose }) => { | |
| const setContents = useFile(state => state.setContents); | |
| const [url, setURL] = React.useState(""); | |
| const [jsonFile, setJsonFile] = React.useState<File | null>(null); | |
| const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
| if (e.target.files) setJsonFile(e.target.files?.item(0)); | |
| }; | |
| const handleFileDrag = (e: React.DragEvent<HTMLLabelElement>) => { | |
| e.preventDefault(); | |
| if (e.type === "drop" && e.dataTransfer.files.length) { | |
| if (e.dataTransfer.files[0].type === "application/json") { | |
| setJsonFile(e.dataTransfer.files[0]); | |
| } else { | |
| toast.error("Please upload JSON file!"); | |
| } | |
| } | |
| }; | |
| const handleImportFile = () => { | |
| if (url) { | |
| setJsonFile(null); | |
| toast.loading("Loading...", { id: "toastFetch" }); | |
| return fetch(url) | |
| .then(res => res.json()) | |
| .then(json => { | |
| setContents({ contents: JSON.stringify(json, null, 2) }); | |
| onClose(); | |
| }) | |
| .catch(() => toast.error("Failed to fetch JSON!")) | |
| .finally(() => toast.dismiss("toastFetch")); | |
| } | |
| if (jsonFile) { | |
| const reader = new FileReader(); | |
| reader.readAsText(jsonFile, "UTF-8"); | |
| reader.onload = function (data) { | |
| if (typeof data.target?.result === "string") setContents({ contents: data.target?.result }); | |
| onClose(); | |
| }; | |
| } | |
| }; | |
| return ( | |
| <Modal title="Import JSON" opened={opened} onClose={onClose} centered> | |
| <Stack py="sm"> | |
| <TextInput | |
| value={url} | |
| onChange={e => setURL(e.target.value)} | |
| type="url" | |
| placeholder="URL of JSON to fetch" | |
| data-autofocus | |
| /> | |
| <StyledUploadWrapper onDrop={handleFileDrag} onDragOver={handleFileDrag}> | |
| <input | |
| key={jsonFile?.name} | |
| onChange={handleFileChange} | |
| type="file" | |
| accept="application/JSON" | |
| /> | |
| <AiOutlineUpload size={48} /> | |
| <StyledUploadMessage>Click Here to Upload JSON</StyledUploadMessage> | |
| <StyledFileName>{jsonFile?.name ?? "None"}</StyledFileName> | |
| </StyledUploadWrapper> | |
| </Stack> | |
| <Divider my="xs" /> | |
| <Group justify="right"> | |
| <Button onClick={handleImportFile} disabled={!(jsonFile || url)}> | |
| Import | |
| </Button> | |
| </Group> | |
| </Modal> | |
| ); | |
| }; | |