Explorar o código

Add Fetch JSON from URL

Added a button in sidebar to show a modal which has inputs to type in the url of json to fetch.
Hyunseung Lee %!s(int64=3) %!d(string=hai) anos
pai
achega
4bf74a4476
Modificáronse 2 ficheiros con 116 adicións e 0 borrados
  1. 103 0
      src/components/Modal/index.tsx
  2. 13 0
      src/components/Sidebar/index.tsx

+ 103 - 0
src/components/Modal/index.tsx

@@ -0,0 +1,103 @@
+import React from "react";
+import styled, { DefaultTheme } from "styled-components";
+import toast from "react-hot-toast";
+
+import { useConfig } from "src/hocs/config";
+import { ConfigActionType } from "src/reducer/reducer";
+
+enum ButtonType {
+  PRIMARY = "PRIMARY",
+  SECONDARY = "BLURPLE",
+  DANGER = "DANGER",
+  SUCCESS = "SEAGREEN",
+  WARNING = "ORANGE",
+}
+
+function getButtonStatus(status: keyof typeof ButtonType, theme: DefaultTheme) {
+  return theme[ButtonType[status]];
+}
+
+const StyledModalWrapper = styled.div`
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 5;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+`;
+
+const StyledInput = styled.input`
+  background: ${({ theme }) => theme.BACKGROUND_TERTIARY};
+  color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
+  outline: none;
+  border: none;
+  border-radius: 5px;
+  padding: 10px;
+  margin: 10px 0;
+  display: block;
+  width: 100%;
+`;
+
+const StyledButton = styled.button<{ status: keyof typeof ButtonType }>`
+  background: ${({ status, theme }) => getButtonStatus(status, theme)};
+  color: #ffffff;
+  padding: 8px 16px;
+  min-width: 60px;
+  margin-right: 10px;
+
+  @media only screen and (max-width: 768px) {
+    font-size: 18px;
+  }
+`;
+
+export const Modal = ({ visible, setVisible }) => {
+  const { json, settings, dispatch } = useConfig();
+  const inputRef = React.useRef<HTMLInputElement | null>(null);
+
+  const fetchJSON = () => {
+    fetch(inputRef.current!.value)
+      .then((res) => res.json())
+      .then((json) => {
+        dispatch({
+          type: ConfigActionType.SET_JSON,
+          payload: JSON.stringify(json),
+        });
+
+        setVisible(false);
+      })
+      .catch((err) => toast.error(err.message));
+  };
+
+  const cancel = () => {
+    setVisible(false);
+  };
+
+  return (
+    visible && (
+      <StyledModalWrapper>
+        <div>
+          <h2>Import JSON from URL</h2>
+
+          <div>
+            <StyledInput
+              ref={inputRef}
+              type="url"
+              placeholder="URL of JSON to fetch"
+            />
+
+            <StyledButton status="PRIMARY" onClick={fetchJSON}>
+              Import
+            </StyledButton>
+            <StyledButton status="DANGER" onClick={cancel}>
+              Cancel
+            </StyledButton>
+          </div>
+        </div>
+      </StyledModalWrapper>
+    )
+  );
+};

+ 13 - 0
src/components/Sidebar/index.tsx

@@ -14,9 +14,11 @@ import {
   AiOutlineTwitter,
   AiOutlineSave,
   AiOutlineFileAdd,
+  AiOutlineLink,
 } from "react-icons/ai";
 
 import { Tooltip } from "src/components/Tooltip";
+import { Modal } from "src/components/Modal/index";
 import { ConfigActionType } from "src/reducer/reducer";
 import { useConfig } from "src/hocs/config";
 import { useRouter } from "next/router";
@@ -109,11 +111,16 @@ export const Sidebar: React.FC = () => {
   const { json, settings, dispatch } = useConfig();
   const router = useRouter();
   const [jsonFile, setJsonFile] = React.useState<File | null>(null);
+  const [visible, setVisible] = React.useState(false);
 
   const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
     if (e.target.files) setJsonFile(e.target.files?.item(0));
   };
 
+  const handleImportJSONFromURL = () => {
+    setVisible(true);
+  };
+
   const handleClear = () => {
     dispatch({ type: ConfigActionType.SET_JSON, payload: "{}" });
     localStorage.removeItem("json");
@@ -147,6 +154,7 @@ export const Sidebar: React.FC = () => {
   return (
     <StyledSidebar>
       <StyledTopWrapper>
+        <Modal visible={visible} setVisible={setVisible} />
         <Link passHref href="/">
           <StyledElement onClick={() => router.push("/")}>
             <StyledLogo>
@@ -168,6 +176,11 @@ export const Sidebar: React.FC = () => {
             </StyledImportFile>
           </StyledElement>
         </Tooltip>
+        <Tooltip title="Fetch JSON from URL">
+          <StyledElement onClick={handleImportJSONFromURL}>
+            <AiOutlineLink />
+          </StyledElement>
+        </Tooltip>
         <Tooltip title="Rotate Layout">
           <StyledElement
             onClick={() => dispatch({ type: ConfigActionType.TOGGLE_LAYOUT })}