index.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import React from "react";
  2. import styled from "styled-components";
  3. import toast from "react-hot-toast";
  4. import { useConfig } from "src/hocs/config";
  5. import { ConfigActionType } from "src/reducer/reducer";
  6. import { Modal } from "src/components/Modal";
  7. import { Button } from "src/components/Button";
  8. import { AiOutlineUpload } from "react-icons/ai";
  9. const StyledInput = styled.input`
  10. background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
  11. color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
  12. outline: none;
  13. border: none;
  14. border-radius: 5px;
  15. padding: 6px 8px;
  16. width: 100%;
  17. margin-bottom: 10px;
  18. `;
  19. const StyledModalContent = styled(Modal.Content)`
  20. display: flex;
  21. justify-content: center;
  22. align-items: center;
  23. flex-direction: column;
  24. `;
  25. const StyledUploadWrapper = styled.label`
  26. display: flex;
  27. flex-direction: column;
  28. justify-content: center;
  29. align-items: center;
  30. background: ${({ theme }) => theme.BACKGROUND_SECONDARY};
  31. border: 2px dashed ${({ theme }) => theme.BACKGROUND_TERTIARY};
  32. border-radius: 5px;
  33. width: 100%;
  34. padding: 16px;
  35. cursor: pointer;
  36. input[type="file"] {
  37. display: none;
  38. }
  39. `;
  40. const StyledFileName = styled.span`
  41. color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
  42. `;
  43. const StyledUploadMessage = styled.h3`
  44. color: ${({ theme }) => theme.INTERACTIVE_ACTIVE};
  45. margin-bottom: 0;
  46. `;
  47. export const ImportModal = ({ visible, setVisible }) => {
  48. const { dispatch } = useConfig();
  49. const [url, setURL] = React.useState("");
  50. const [jsonFile, setJsonFile] = React.useState<File | null>(null);
  51. const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  52. if (e.target.files) setJsonFile(e.target.files?.item(0));
  53. };
  54. const handleImportFile = () => {
  55. if (url) {
  56. setJsonFile(null);
  57. const toastId = toast.loading("Loading...");
  58. return fetch(url)
  59. .then((res) => res.json())
  60. .then((json) => {
  61. dispatch({
  62. type: ConfigActionType.SET_JSON,
  63. payload: JSON.stringify(json),
  64. });
  65. toast.dismiss(toastId);
  66. setVisible(false);
  67. })
  68. .catch(() => toast.error("Failed to fetch JSON!"));
  69. }
  70. if (jsonFile) {
  71. const reader = new FileReader();
  72. reader.readAsText(jsonFile, "UTF-8");
  73. reader.onload = function (data) {
  74. dispatch({
  75. type: ConfigActionType.SET_JSON,
  76. payload: data.target?.result as string,
  77. });
  78. setVisible(false);
  79. };
  80. }
  81. };
  82. React.useEffect(() => {
  83. return () => {
  84. setJsonFile(null);
  85. setURL("");
  86. };
  87. }, [visible]);
  88. return (
  89. <Modal visible={visible} setVisible={setVisible}>
  90. <Modal.Header>Select An Import Method</Modal.Header>
  91. <StyledModalContent>
  92. <StyledInput
  93. value={url}
  94. onChange={(e) => setURL(e.target.value)}
  95. type="url"
  96. placeholder="URL of JSON to fetch"
  97. />
  98. <StyledUploadWrapper>
  99. <input
  100. key={jsonFile?.name}
  101. onChange={handleFileChange}
  102. type="file"
  103. accept="application/JSON"
  104. />
  105. <AiOutlineUpload size={48} />
  106. <StyledUploadMessage>Click Here to Upload JSON</StyledUploadMessage>
  107. <StyledFileName>{jsonFile?.name ?? "None"}</StyledFileName>
  108. </StyledUploadWrapper>
  109. </StyledModalContent>
  110. <Modal.Controls setVisible={setVisible}>
  111. <Button
  112. status="SECONDARY"
  113. onClick={handleImportFile}
  114. disabled={!(jsonFile || url)}
  115. >
  116. Import
  117. </Button>
  118. </Modal.Controls>
  119. </Modal>
  120. );
  121. };