index.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import React from "react";
  2. import toast from "react-hot-toast";
  3. import { AiOutlineUpload } from "react-icons/ai";
  4. import { Button } from "src/components/Button";
  5. import { Input } from "src/components/Input";
  6. import { Modal, ModalProps } from "src/components/Modal";
  7. import useJson from "src/store/useJson";
  8. import styled from "styled-components";
  9. const StyledModalContent = styled(Modal.Content)`
  10. display: flex;
  11. justify-content: center;
  12. align-items: center;
  13. flex-direction: column;
  14. `;
  15. const StyledUploadWrapper = styled.label`
  16. display: flex;
  17. flex-direction: column;
  18. justify-content: center;
  19. align-items: center;
  20. background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
  21. border: 2px dashed ${({ theme }) => theme.BACKGROUND_TERTIARY};
  22. border-radius: 5px;
  23. width: 100%;
  24. min-height: 200px;
  25. padding: 16px;
  26. cursor: pointer;
  27. input[type="file"] {
  28. display: none;
  29. }
  30. `;
  31. const StyledFileName = styled.span`
  32. padding-top: 14px;
  33. color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
  34. `;
  35. const StyledUploadMessage = styled.h3`
  36. color: ${({ theme }) => theme.INTERACTIVE_ACTIVE};
  37. margin-bottom: 0;
  38. `;
  39. export const ImportModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
  40. const setJson = useJson(state => state.setJson);
  41. const [url, setURL] = React.useState("");
  42. const [jsonFile, setJsonFile] = React.useState<File | null>(null);
  43. const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  44. if (e.target.files) setJsonFile(e.target.files?.item(0));
  45. };
  46. const handleImportFile = () => {
  47. if (url) {
  48. setJsonFile(null);
  49. toast.loading("Loading...", { id: "toastFetch" });
  50. return fetch(url)
  51. .then(res => res.json())
  52. .then(json => {
  53. setJson(JSON.stringify(json, null, 2));
  54. setVisible(false);
  55. })
  56. .catch(() => toast.error("Failed to fetch JSON!"))
  57. .finally(() => toast.dismiss("toastFetch"));
  58. }
  59. if (jsonFile) {
  60. const reader = new FileReader();
  61. reader.readAsText(jsonFile, "UTF-8");
  62. reader.onload = function (data) {
  63. setJson(data.target?.result as string);
  64. setVisible(false);
  65. };
  66. }
  67. };
  68. return (
  69. <Modal visible={visible} setVisible={setVisible}>
  70. <Modal.Header>Import JSON</Modal.Header>
  71. <StyledModalContent>
  72. <Input
  73. value={url}
  74. onChange={e => setURL(e.target.value)}
  75. type="url"
  76. placeholder="URL of JSON to fetch"
  77. autoFocus
  78. />
  79. <StyledUploadWrapper>
  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. </StyledModalContent>
  91. <Modal.Controls setVisible={setVisible}>
  92. <Button status="SECONDARY" onClick={handleImportFile} disabled={!(jsonFile || url)}>
  93. Import
  94. </Button>
  95. </Modal.Controls>
  96. </Modal>
  97. );
  98. };