瀏覽代碼

styling improvements

AykutSarac 2 年之前
父節點
當前提交
4ed3411f86

+ 1 - 1
next.config.js

@@ -9,7 +9,7 @@ const withPWA = require("next-pwa")({
  * @type {import('next').NextConfig}
  */
 const nextConfig = {
-  reactStrictMode: true,
+  reactStrictMode: false,
 };
 
 module.exports = withPWA(nextConfig);

二進制
public/assets/icon.png


+ 2 - 2
src/components/Sidebar/index.tsx

@@ -150,7 +150,7 @@ export const Sidebar: React.FC = () => {
   const graphCollapsed = useGraph(state => state.graphCollapsed);
   const direction = useGraph(state => state.direction);
   const foldNodes = useConfig(state => state.foldNodes);
-  const hideEditor = useConfig(state => state.hideEditor);
+  const fullscreen = useConfig(state => state.fullscreen);
 
   const handleSave = () => {
     const a = document.createElement("a");
@@ -189,7 +189,7 @@ export const Sidebar: React.FC = () => {
         </Link>
 
         <Tooltip className="mobile" title="Edit JSON">
-          <StyledElement onClick={() => setConfig("hideEditor", !hideEditor)}>
+          <StyledElement onClick={() => setConfig("fullscreen", !fullscreen)}>
             <AiOutlineEdit />
           </StyledElement>
         </Tooltip>

+ 1 - 2
src/components/SupportButton/index.tsx

@@ -29,6 +29,7 @@ const StyledSupportButton = styled.a`
     0 4px 8px rgba(0, 0, 0, 0.07), 0 8px 16px rgba(0, 0, 0, 0.07),
     0 16px 32px rgba(0, 0, 0, 0.07), 0 32px 64px rgba(0, 0, 0, 0.07);
   opacity: 0.7;
+  box-sizing: content-box !important;
 
   &:hover {
     width: 180px;
@@ -43,8 +44,6 @@ const StyledSupportButton = styled.a`
 `;
 
 export const SupportButton = () => {
-  if (location.pathname.includes("widget")) return null;
-
   return (
     <StyledSupportButton
       href="https://github.com/sponsors/AykutSarac"

+ 4 - 4
src/constants/globalStyle.ts

@@ -22,7 +22,6 @@ const GlobalStyle = createGlobalStyle`
     font-family: 'Mona Sans';
     font-weight: 400;
     font-size: 16px;
-    scroll-behavior: smooth;
     height: 100%;
 
     background-color: #000000;
@@ -32,14 +31,15 @@ const GlobalStyle = createGlobalStyle`
 
     @media only screen and (min-width: 768px) {
       background-color: #000000;
-      opacity: 1;
-      background-image: radial-gradient(#414141 0.5px, #000000 0.5px);
-      background-size: 15px 15px;
+      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25' viewBox='0 0 800 800'%3E%3Cg fill-opacity='0.22'%3E%3Ccircle fill='%23000000' cx='400' cy='400' r='600'/%3E%3Ccircle fill='%23110718' cx='400' cy='400' r='500'/%3E%3Ccircle fill='%23220e30' cx='400' cy='400' r='400'/%3E%3Ccircle fill='%23331447' cx='400' cy='400' r='300'/%3E%3Ccircle fill='%23441b5f' cx='400' cy='400' r='200'/%3E%3Ccircle fill='%23552277' cx='400' cy='400' r='100'/%3E%3C/g%3E%3C/svg%3E");
+      background-attachment: fixed;
+      background-size: cover;
     }
   }
 
   * {
     -webkit-tap-highlight-color: transparent;
+    scroll-behavior: smooth;
   }
 
   .hide {

+ 41 - 32
src/containers/Editor/BottomBar.tsx

@@ -1,6 +1,5 @@
 import React from "react";
 import { useRouter } from "next/router";
-import { useQuery } from "@tanstack/react-query";
 import toast from "react-hot-toast";
 import {
   AiOutlineCloudSync,
@@ -10,11 +9,12 @@ import {
   AiOutlineUnlock,
 } from "react-icons/ai";
 import { VscAccount } from "react-icons/vsc";
-import { altogic } from "src/api/altogic";
-import { getJson, saveJson, updateJson } from "src/services/db/json";
+import { useJson } from "src/hooks/useFetchedJson";
+import { saveJson, updateJson } from "src/services/db/json";
 import useConfig from "src/store/useConfig";
 import useGraph from "src/store/useGraph";
 import useModal from "src/store/useModal";
+import useStored from "src/store/useStored";
 import useUser from "src/store/useUser";
 import styled from "styled-components";
 
@@ -61,29 +61,30 @@ const StyledBottomBarItem = styled.button`
   }
 `;
 
-export const BottomBar = () => {
-  const { isReady, replace, query } = useRouter();
+const StyledImg = styled.img<{ light: boolean }>`
+  filter: ${({ light }) => light && "invert(100%)"};
+`;
 
-  const { data } = useQuery(
-    ["dbJson", query.json],
-    () => getJson(query.json as string),
-    {
-      enabled: isReady && !!query.json,
-    }
-  );
+export const BottomBar = () => {
+  const { replace, query } = useRouter();
+  const { data } = useJson();
 
   const user = useUser(state => state.user);
   const setVisible = useModal(state => state.setVisible);
   const getJsonState = useGraph(state => state.getJson);
   const hasChanges = useConfig(state => state.hasChanges);
   const setConfig = useConfig(state => state.setConfig);
+  const lightmode = useStored(state => state.lightmode);
   const [isPrivate, setIsPrivate] = React.useState(true);
 
   React.useEffect(() => {
-    if (data) setIsPrivate(data.data.private);
+    console.log(data);
+
+    setIsPrivate(data?.data.private ?? true);
   }, [data]);
 
   const handleSaveJson = React.useCallback(() => {
+    if (!user) return setVisible("login")(true);
     if (hasChanges) {
       toast.promise(
         saveJson({ id: query.json, data: getJsonState() }).then(res => {
@@ -97,17 +98,16 @@ export const BottomBar = () => {
         }
       );
     }
-  }, [getJsonState, hasChanges, query.json, replace, setConfig]);
+  }, [getJsonState, hasChanges, query.json, replace, setConfig, setVisible, user]);
 
   const handleLoginClick = () => {
     if (user) return setVisible("account")(true);
-    altogic.auth.signInWithProvider("google");
+    else setVisible("login")(true);
   };
 
   const setPrivate = () => {
     if (!query.json) return handleSaveJson();
     updateJson(query.json as string, { private: !isPrivate });
-    setIsPrivate(!isPrivate);
   };
 
   return (
@@ -121,26 +121,35 @@ export const BottomBar = () => {
           {hasChanges ? <AiOutlineCloudUpload /> : <AiOutlineCloudSync />}
           {hasChanges ? "Unsaved Changes" : "Saved"}
         </StyledBottomBarItem>
-        <StyledBottomBarItem onClick={setPrivate}>
-          {isPrivate ? <AiOutlineLock /> : <AiOutlineUnlock />}
-          {isPrivate ? "Private" : "Public"}
-        </StyledBottomBarItem>
         {query.json && (
-          <StyledBottomBarItem onClick={() => setVisible("share")(true)}>
-            <AiOutlineLink />
-            Share
-          </StyledBottomBarItem>
+          <>
+            <StyledBottomBarItem onClick={setPrivate}>
+              {isPrivate ? <AiOutlineLock /> : <AiOutlineUnlock />}
+              {isPrivate ? "Private" : "Public"}
+            </StyledBottomBarItem>
+            <StyledBottomBarItem onClick={() => setVisible("share")(true)}>
+              <AiOutlineLink />
+              Share
+            </StyledBottomBarItem>
+          </>
         )}
       </StyledLeft>
       <StyledRight>
-        <StyledBottomBarItem>
-          Powered by
-          <img
-            height="20"
-            src="https://regexlearn.com/altogic.svg"
-            alt="powered by buildable"
-          />
-        </StyledBottomBarItem>
+        <a
+          href="https://www.altogic.com/?utm_source=jsoncrack&utm_medium=referral&utm_campaign=sponsorship"
+          rel="sponsored noreferrer"
+          target="_blank"
+        >
+          <StyledBottomBarItem>
+            Powered by
+            <StyledImg
+              height="20"
+              src="https://regexlearn.com/altogic.svg"
+              alt="powered by buildable"
+              light={lightmode}
+            />
+          </StyledBottomBarItem>
+        </a>
       </StyledRight>
     </StyledBottomBar>
   );

+ 5 - 5
src/containers/Editor/Panes.tsx

@@ -17,25 +17,25 @@ const LiveEditor = dynamic(() => import("src/containers/Editor/LiveEditor"), {
 });
 
 const Panes: React.FC = () => {
-  const hideEditor = useConfig(state => state.hideEditor);
+  const fullscreen = useConfig(state => state.fullscreen);
   const setConfig = useConfig(state => state.setConfig);
   const isMobile = window.innerWidth <= 768;
 
   React.useEffect(() => {
-    if (isMobile) setConfig("hideEditor", true);
+    if (isMobile) setConfig("fullscreen", true);
   }, [isMobile, setConfig]);
 
   return (
     <StyledEditor proportionalLayout={false} vertical={isMobile}>
       <Allotment.Pane
         preferredSize={isMobile ? "100%" : 400}
-        minSize={hideEditor ? 0 : 300}
+        minSize={fullscreen ? 0 : 300}
         maxSize={isMobile ? Infinity : 800}
-        visible={!hideEditor}
+        visible={!fullscreen}
       >
         <JsonEditor />
       </Allotment.Pane>
-      <Allotment.Pane minSize={0} maxSize={isMobile && !hideEditor ? 0 : Infinity}>
+      <Allotment.Pane minSize={0} maxSize={isMobile && !fullscreen ? 0 : Infinity}>
         <LiveEditor />
       </Allotment.Pane>
     </StyledEditor>

+ 2 - 2
src/containers/Editor/Tools.tsx

@@ -48,13 +48,13 @@ const StyledToolElement = styled.button`
 export const Tools: React.FC = () => {
   const setVisible = useModal(state => state.setVisible);
 
-  const hideEditor = useConfig(state => state.hideEditor);
+  const fullscreen = useConfig(state => state.fullscreen);
   const setConfig = useConfig(state => state.setConfig);
 
   const zoomIn = useConfig(state => state.zoomIn);
   const zoomOut = useConfig(state => state.zoomOut);
   const centerView = useConfig(state => state.centerView);
-  const toggleEditor = () => setConfig("hideEditor", !hideEditor);
+  const toggleEditor = () => setConfig("fullscreen", !fullscreen);
 
   return (
     <>

+ 7 - 5
src/containers/Home/index.tsx

@@ -2,6 +2,7 @@ import React from "react";
 import Head from "next/head";
 import Link from "next/link";
 import Script from "next/script";
+import { AiOutlineRight } from "react-icons/ai";
 import { FaGithub, FaHeart, FaLinkedin, FaTwitter } from "react-icons/fa";
 import {
   HiCursorClick,
@@ -51,10 +52,10 @@ const HeroSection = () => {
         <Styles.StyledHighlightedText>instantly</Styles.StyledHighlightedText> into
         graphs.
       </Styles.StyledSubTitle>
-      <Styles.StyledMinorTitle>Paste - Import - Fetch!</Styles.StyledMinorTitle>
 
       <Styles.StyledButton rel="prefetch" href="/editor" link>
         GO TO EDITOR
+        <AiOutlineRight strokeWidth="30px" />
       </Styles.StyledButton>
 
       <Styles.StyledButtonWrapper>
@@ -238,8 +239,8 @@ const EmbedSection = () => (
                 json: defaultJson,
                 options: {
                   theme: "dark",
-                  direction: "DOWN"
-                }
+                  direction: "DOWN",
+                },
               },
               "*"
             );
@@ -288,7 +289,8 @@ const SponsorSection = () => (
 const Footer = () => (
   <Styles.StyledFooter>
     <Styles.StyledFooterText>
-      © 2022 JSON Crack - {pkg.version}
+      © <img width="100" src="assets/icon.png" alt="icon" />
+      {new Date().getFullYear()} - {pkg.version}
     </Styles.StyledFooterText>
     <Styles.StyledIconLinks>
       <Styles.StyledNavLink
@@ -335,8 +337,8 @@ const Home: React.FC = () => {
       <EmbedSection />
       <SupportSection />
       <SponsorSection />
-      <Footer />
       <SupportButton />
+      <Footer />
     </Styles.StyledHome>
   );
 };

+ 25 - 6
src/containers/Home/styles.tsx

@@ -137,6 +137,7 @@ export const StyledSubTitle = styled.h2`
   font-size: 2.5rem;
   max-width: 40rem;
   margin: 0;
+  margin-bottom: 25px;
 
   @media only screen and (max-width: 768px) {
     font-size: 1.5rem;
@@ -158,11 +159,12 @@ export const StyledMinorTitle = styled.p`
 export const StyledButton = styled(Button)`
   background: ${({ status }) => !status && "#a13cc2"};
   padding: 12px 24px;
+  height: 46px;
 
   div {
-    font-family: "Roboto", sans-serif;
+    font-family: "Mona Sans";
     font-weight: 700;
-    font-size: 16px;
+    font-size: 1rem;
   }
 `;
 
@@ -196,11 +198,15 @@ export const StyledSponsorButton = styled(Button)<{ isBlue?: boolean }>`
 `;
 
 export const StyledFeaturesSection = styled.section`
-  display: flex;
-  max-width: 85%;
+  max-width: 60%;
   margin: 0 auto;
-  gap: 2rem;
-  padding: 50px 3%;
+  padding: 0 3%;
+
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  grid-template-rows: repeat(2, 1fr);
+  grid-column-gap: 60px;
+  grid-row-gap: 60px;
 
   @media only screen and (max-width: 768px) {
     flex-direction: column;
@@ -211,6 +217,16 @@ export const StyledFeaturesSection = styled.section`
 export const StyledSectionCard = styled.div`
   text-align: center;
   flex: 1;
+  border: 1px solid ${({ theme }) => theme.BACKGROUND_MODIFIER_ACCENT};
+  background: rgb(48, 0, 65);
+  background: linear-gradient(
+    138deg,
+    rgba(48, 0, 65, 0.8870141806722689) 0%,
+    rgba(72, 12, 84, 0.40802258403361347) 33%,
+    rgba(65, 8, 92, 0.6012998949579832) 100%
+  );
+  border-radius: 6px;
+  padding: 16px;
 `;
 
 export const StyledCardTitle = styled.div`
@@ -350,6 +366,9 @@ export const StyledFooter = styled.footer`
 `;
 
 export const StyledFooterText = styled.p`
+  display: flex;
+  align-items: center;
+  gap: 5px;
   color: #b4b4b4;
 `;
 

+ 33 - 8
src/containers/ModalController/index.tsx

@@ -4,23 +4,48 @@ import { ClearModal } from "src/containers/Modals/ClearModal";
 import { CloudModal } from "src/containers/Modals/CloudModal";
 import { DownloadModal } from "src/containers/Modals/DownloadModal";
 import { ImportModal } from "src/containers/Modals/ImportModal";
+import { LoginModal } from "src/containers/Modals/LoginModal";
 import { SettingsModal } from "src/containers/Modals/SettingsModal";
 import { ShareModal } from "src/containers/Modals/ShareModal";
 import useModal from "src/store/useModal";
+import shallow from "zustand/shallow";
 
 export const ModalController = () => {
   const setVisible = useModal(state => state.setVisible);
-  const state = useModal(state => state);
+
+  const [
+    importModal,
+    clearModal,
+    downloadModal,
+    settingsModal,
+    cloudModal,
+    accountModal,
+    loginModal,
+    shareModal,
+  ] = useModal(
+    state => [
+      state.import,
+      state.clear,
+      state.download,
+      state.settings,
+      state.cloud,
+      state.account,
+      state.login,
+      state.share,
+    ],
+    shallow
+  );
 
   return (
     <>
-      <ImportModal visible={state.import} setVisible={setVisible("import")} />
-      <ClearModal visible={state.clear} setVisible={setVisible("clear")} />
-      <DownloadModal visible={state.download} setVisible={setVisible("download")} />
-      <SettingsModal visible={state.settings} setVisible={setVisible("settings")} />
-      <CloudModal visible={state.cloud} setVisible={setVisible("cloud")} />
-      <AccountModal visible={state.account} setVisible={setVisible("account")} />
-      <ShareModal visible={state.share} setVisible={setVisible("share")} />
+      <ImportModal visible={importModal} setVisible={setVisible("import")} />
+      <ClearModal visible={clearModal} setVisible={setVisible("clear")} />
+      <DownloadModal visible={downloadModal} setVisible={setVisible("download")} />
+      <SettingsModal visible={settingsModal} setVisible={setVisible("settings")} />
+      <CloudModal visible={cloudModal} setVisible={setVisible("cloud")} />
+      <AccountModal visible={accountModal} setVisible={setVisible("account")} />
+      <LoginModal visible={loginModal} setVisible={setVisible("login")} />
+      <ShareModal visible={shareModal} setVisible={setVisible("share")} />
     </>
   );
 };

+ 0 - 12
src/containers/Modals/AccountModal/index.tsx

@@ -26,18 +26,6 @@ const StyledTitle = styled.p`
   }
 `;
 
-const StyledModalContent = styled.div`
-  margin-bottom: 20px;
-`;
-
-const StyledLoginWrapper = styled.div`
-  display: flex;
-  justify-content: center;
-  align-items: center;
-`;
-
-const StyledButton = styled(Button)``;
-
 const StyledAccountWrapper = styled.div`
   display: flex;
   flex-wrap: wrap;

+ 12 - 4
src/containers/Modals/CloudModal/index.tsx

@@ -1,12 +1,13 @@
 import React from "react";
+import { useRouter } from "next/router";
 import { useQuery } from "@tanstack/react-query";
 import dayjs from "dayjs";
 import relativeTime from "dayjs/plugin/relativeTime";
 import { AiOutlinePlus } from "react-icons/ai";
 import { Modal, ModalProps } from "src/components/Modal";
 import { getAllJson } from "src/services/db/json";
+import useUser from "src/store/useUser";
 import styled from "styled-components";
-import { useRouter } from "next/router";
 
 dayjs.extend(relativeTime);
 
@@ -91,8 +92,15 @@ const CreateCard: React.FC = () => (
 );
 
 export const CloudModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
-  const { query } = useRouter();
-  const { data, isLoading } = useQuery(["allJson", query], () => getAllJson());
+  const { isReady, query } = useRouter();
+  const user = useUser(state => state.user);
+  const { data, isLoading } = useQuery(
+    ["allJson", query, user],
+    () => getAllJson(),
+    {
+      enabled: isReady,
+    }
+  );
 
   if (isLoading) return <div>loading</div>;
   return (
@@ -109,7 +117,7 @@ export const CloudModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
                 preview:
                   "https://blog.shevarezo.fr/uploads/posts/bulk/FNj3yQLp_visualiser-donnees-json-diagramme-json-crack_rotate3.png",
               }}
-              key={json.id}
+              key={json._id}
             />
           ))}
           <CreateCard />

+ 24 - 0
src/containers/Modals/LoginModal/index.tsx

@@ -0,0 +1,24 @@
+import React from "react";
+import { altogic } from "src/api/altogic";
+import { Button } from "src/components/Button";
+import { Modal, ModalProps } from "src/components/Modal";
+
+export const LoginModal: React.FC<ModalProps> = ({ setVisible, visible }) => {
+  const handleLoginClick = () => {
+    altogic.auth.signInWithProvider("google");
+  };
+
+  return (
+    <Modal visible={visible} setVisible={setVisible}>
+      <Modal.Header>Login</Modal.Header>
+      <Modal.Content>
+        <h2>Welcome Back!</h2>
+        <p>Login to unlock full potential of JSON Crack!</p>
+        <Button onClick={handleLoginClick} status="SECONDARY" block>
+          Login
+        </Button>
+      </Modal.Content>
+      <Modal.Controls setVisible={setVisible} />
+    </Modal>
+  );
+};

+ 35 - 0
src/hooks/useFetchedJson.tsx

@@ -0,0 +1,35 @@
+import React from "react";
+import { useRouter } from "next/router";
+import { useQuery } from "@tanstack/react-query";
+import { decompressFromBase64 } from "lz-string";
+import { defaultJson } from "src/constants/data";
+import { getJson } from "src/services/db/json";
+import useGraph from "src/store/useGraph";
+
+export function useJson() {
+  const { query, isReady } = useRouter();
+  const setLoading = useGraph(state => state.setLoading);
+  const setJson = useGraph(state => state.setJson);
+
+  const { data, isLoading, status } = useQuery(
+    ["dbJson", query.json],
+    () => getJson(query.json as string),
+    {
+      enabled: isReady && !!query.json,
+    }
+  );
+
+  React.useEffect(() => {
+    if (isReady) {
+      if (query.json) {
+        if (isLoading) return setLoading(true);
+        if (status || !data) setJson(defaultJson);
+
+        if (data?.data) setJson(decompressFromBase64(data.data.json) as string);
+        setLoading(false);
+      } else setJson(defaultJson);
+    }
+  }, [data, isLoading, isReady, query.json, setJson, setLoading, status]);
+
+  return { data };
+}

+ 2 - 30
src/pages/editor.tsx

@@ -1,14 +1,9 @@
 import React from "react";
 import Head from "next/head";
-import { useRouter } from "next/router";
-import { useQuery } from "@tanstack/react-query";
-import { decompressFromBase64 } from "lz-string";
 import { Sidebar } from "src/components/Sidebar";
-import { defaultJson } from "src/constants/data";
 import { BottomBar } from "src/containers/Editor/BottomBar";
 import Panes from "src/containers/Editor/Panes";
-import { getJson } from "src/services/db/json";
-import useGraph from "src/store/useGraph";
+import { useJson } from "src/hooks/useFetchedJson";
 import useUser from "src/store/useUser";
 import styled from "styled-components";
 
@@ -32,36 +27,13 @@ export const StyledEditorWrapper = styled.div`
 `;
 
 const EditorPage: React.FC = () => {
-  const { query, isReady } = useRouter();
   const checkSession = useUser(state => state.checkSession);
-  const { data, isLoading, status } = useQuery(
-    ["dbJson", query.json],
-    () => getJson(query.json as string),
-    {
-      enabled: isReady && !!query.json,
-    }
-  );
-
-  const setJson = useGraph(state => state.setJson);
-  const setLoading = useGraph(state => state.setLoading);
+  useJson();
 
   React.useEffect(() => {
     checkSession();
   }, [checkSession]);
 
-  React.useEffect(() => {
-    if (isReady) {
-      if (query.json) {
-        
-        if (isLoading) return setLoading(true);
-        if (status || !data) setJson(defaultJson);
-        
-        if (data?.data) setJson(decompressFromBase64(data.data.json) as string);
-        setLoading(false);
-      } else setJson(defaultJson);
-    }
-  }, [data, status, isLoading, isReady, query.json, setJson, setLoading]);
-
   return (
     <StyledEditorWrapper>
       <Head>

+ 10 - 3
src/store/useConfig.tsx

@@ -13,11 +13,11 @@ interface ConfigActions {
 
 const initialStates = {
   foldNodes: false,
-  hideEditor: false,
+  fullscreen: false,
   performanceMode: true,
   zoomPanPinch: undefined as ReactZoomPanPinchRef | undefined,
   hasChanges: false,
-  hasError: false
+  hasError: false,
 };
 
 export type Config = typeof initialStates;
@@ -49,7 +49,14 @@ const useConfig = create<Config & ConfigActions>()((set, get) => ({
     const canvas = document.querySelector(".jsoncrack-canvas") as HTMLElement;
     if (zoomPanPinch && canvas) zoomPanPinch.zoomToElement(canvas);
   },
-  setConfig: (setting: keyof Config, value: unknown) => set({ [setting]: value }),
+  setConfig: (setting, value) => {
+    if (setting === "fullscreen" && value) {
+      set({ fullscreen: true });
+      return get().centerView();
+    }
+
+    set({ [setting]: value });
+  },
 }));
 
 export default useConfig;

+ 1 - 1
src/store/useGraph.tsx

@@ -9,7 +9,7 @@ import useConfig from "./useConfig";
 
 const initialStates = {
   json: null as unknown as string,
-  loading: false,
+  loading: true,
   direction: "RIGHT" as CanvasDirection,
   graphCollapsed: false,
   nodes: [] as NodeData[],

+ 3 - 2
src/store/useModal.tsx

@@ -15,11 +15,12 @@ const initialStates = {
   node: false,
   settings: false,
   share: false,
+  login: false
 };
 
 type ModalType = keyof typeof initialStates;
 
-const authModals: ModalType[] = ["cloud", "share"];
+const authModals: ModalType[] = ["cloud", "share", "account"];
 
 export type ModalStates = typeof initialStates;
 
@@ -27,7 +28,7 @@ const useModal = create<ModalStates & ModalActions>()(set => ({
   ...initialStates,
   setVisible: modal => visible => {
     if (authModals.includes(modal) && !useUser.getState().isAuthenticated) {
-      return set({ account: true });
+      return set({ login: true });
     }
 
     set({ [modal]: visible });

+ 10 - 4
src/store/useUser.tsx

@@ -2,6 +2,7 @@ import toast from "react-hot-toast";
 import { altogic } from "src/api/altogic";
 import { AltogicAuth } from "src/typings/altogic";
 import create from "zustand";
+import useModal from "./useModal";
 
 type User = {
   _id: string;
@@ -32,22 +33,27 @@ const useUser = create<UserStates & UserActions>()(set => ({
   setUser: (key, value) => set({ [key]: value }),
   logout: () => {
     altogic.auth.signOut();
-
     toast.success("Logged out.");
+    useModal.setState({ account: false });
     set(initialStates);
   },
   login: response => {
     set({ user: response.user, isAuthenticated: true });
   },
-  checkSession: () => {
+  checkSession: async () => {
     const currentSession = altogic.auth.getSession();
     const currentUser = altogic.auth.getUser();
 
     if (currentSession) {
-      alert("has");
-      
       altogic.auth.setSession(currentSession);
       set({ user: currentUser as any, isAuthenticated: true });
+    } else {
+      if (!new URLSearchParams(window.location.search).get("access_token")) return;
+
+      const data = await altogic.auth.getAuthGrant();
+      if (!data.errors?.items.length) {
+        set({ user: data.user as any, isAuthenticated: true });
+      }
     }
   },
 }));