index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import React from "react";
  2. import { Modal, Group, Button, TextInput, Stack, Divider, ModalProps } from "@mantine/core";
  3. import toast from "react-hot-toast";
  4. import { AiOutlineUpload } from "react-icons/ai";
  5. import useJson from "src/store/useJson";
  6. import styled from "styled-components";
  7. const StyledUploadWrapper = styled.label`
  8. display: flex;
  9. flex-direction: column;
  10. justify-content: center;
  11. align-items: center;
  12. background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
  13. border: 2px dashed ${({ theme }) => theme.BACKGROUND_TERTIARY};
  14. border-radius: 5px;
  15. min-height: 200px;
  16. padding: 16px;
  17. cursor: pointer;
  18. input[type="file"] {
  19. display: none;
  20. }
  21. `;
  22. const StyledFileName = styled.span`
  23. padding-top: 14px;
  24. color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
  25. `;
  26. const StyledUploadMessage = styled.h3`
  27. color: ${({ theme }) => theme.INTERACTIVE_ACTIVE};
  28. margin-bottom: 0;
  29. `;
  30. export const ImportModal: React.FC<ModalProps> = ({ opened, onClose }) => {
  31. const setJson = useJson(state => state.setJson);
  32. const [url, setURL] = React.useState("");
  33. const [jsonFile, setJsonFile] = React.useState<File | null>(null);
  34. const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  35. if (e.target.files) setJsonFile(e.target.files?.item(0));
  36. };
  37. const handleFileDrag = (e: React.DragEvent<HTMLLabelElement>) => {
  38. e.preventDefault();
  39. if (e.type === "drop" && e.dataTransfer.files.length) {
  40. if (e.dataTransfer.files[0].type === "application/json") {
  41. setJsonFile(e.dataTransfer.files[0]);
  42. } else {
  43. toast.error("Please upload JSON file!");
  44. }
  45. }
  46. };
  47. const handleImportFile = () => {
  48. if (url) {
  49. setJsonFile(null);
  50. toast.loading("Loading...", { id: "toastFetch" });
  51. return fetch(url)
  52. .then(res => res.json())
  53. .then(json => {
  54. setJson(JSON.stringify(json, null, 2));
  55. onClose();
  56. })
  57. .catch(() => toast.error("Failed to fetch JSON!"))
  58. .finally(() => toast.dismiss("toastFetch"));
  59. }
  60. if (jsonFile) {
  61. const reader = new FileReader();
  62. reader.readAsText(jsonFile, "UTF-8");
  63. reader.onload = function (data) {
  64. setJson(data.target?.result as string);
  65. onClose();
  66. };
  67. }
  68. };
  69. return (
  70. <Modal title="Import JSON" opened={opened} onClose={onClose} centered>
  71. <Stack py="sm">
  72. <TextInput
  73. value={url}
  74. onChange={e => setURL(e.target.value)}
  75. type="url"
  76. placeholder="URL of JSON to fetch"
  77. data-autofocus
  78. />
  79. <StyledUploadWrapper onDrop={handleFileDrag} onDragOver={handleFileDrag}>
  80. <input
  81. key={jsonFile?.name}
  82. onChange={handleFileChange}
  83. type="file"
  84. accept="application/JSON"
  85. />
  86. <AiOutlineUpload size={48} />
  87. <StyledUploadMessage>Click Here to Upload JSON</StyledUploadMessage>
  88. <StyledFileName>{jsonFile?.name ?? "None"}</StyledFileName>
  89. </StyledUploadWrapper>
  90. </Stack>
  91. <Divider py="xs" />
  92. <Group position="right">
  93. <Button onClick={handleImportFile} disabled={!(jsonFile || url)}>
  94. Import
  95. </Button>
  96. </Group>
  97. </Modal>
  98. );
  99. };