diff --git a/.env b/.env index f0164403aad..b0a489c7c18 100644 --- a/.env +++ b/.env @@ -1,3 +1 @@ NEXT_PUBLIC_GA_MEASUREMENT_ID=G-JKZEHMJBMH -NEXT_PUBLIC_SUPABASE_URL=https://bxkgqurwqjmvrqekcbws.supabase.co -NEXT_PUBLIC_SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJ4a2dxdXJ3cWptdnJxZWtjYndzIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTA2NDU0MjUsImV4cCI6MjAwNjIyMTQyNX0.3nZ0yhuFjnI3yHbAL8S9UtK-Ny-6F5AylNHgo1tymTU diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a8d3e65272..879600e1e97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approacha In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR. ## Getting Started -JSON Crack is built with React, Reaflow for visualization, Mantine UI for components, Zustand for state management, and Supabase for backend integration. If you are not familiar with these technologies, we recommend you to read their documentation to get started. You can find the links to the respective documentations below: +JSON Crack is built with React, Reaflow for visualization, Mantine UI for components, Zustand for state management. If you are not familiar with these technologies, we recommend you to read their documentation to get started. You can find the links to the respective documentations below: * [React](https://reactjs.org/docs/getting-started.html) * [Reaflow](https://github.com/reaviz/reaflow) diff --git a/README.md b/README.md index 16ec16b5044..e2b6f1861df 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,6 @@ JSON Crack is a free, open-source data visualization app capable of visualizing - [Next.js](https://nextjs.org/?ref=jsoncrack.com) - [React.js](https://reactjs.org/?ref=jsoncrack.com) -- [Supabase](https://supabase.com/?ref=jsoncrack.com) - [Reaflow](https://reaflow.dev/?ref=jsoncrack.com) - [Monaco Editor](https://github.com/suren-atoyan/monaco-react) diff --git a/default.conf b/default.conf index 4f310f84bba..ba264f5711f 100644 --- a/default.conf +++ b/default.conf @@ -14,12 +14,4 @@ server { location /docs { try_files $uri /docs.html; } - - location /forgot-password { - try_files $uri /forgot-password.html; - } - - location /sign-in { - try_files $uri /sign-in.html; - } } diff --git a/package.json b/package.json index 7ee7aa19f8e..9ab516c32b9 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ }, "homepage": "https://jsoncrack.com", "bugs": { - "url": "https://github.com/AykutSarac/jsoncrack.com/issues" - }, + "url": "https://github.com/AykutSarac/jsoncrack.com/issues" + }, "scripts": { "dev": "next dev", "build": "next build", @@ -25,7 +25,6 @@ "@mantine/hooks": "^7.11.2", "@monaco-editor/react": "^4.6.0", "@sentry/nextjs": "^7.118.0", - "@supabase/supabase-js": "^2.44.4", "@tanstack/react-query": "^4.36.1", "allotment": "^1.20.2", "axios": "^1.7.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 373275d6ae9..6a38fc5a176 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,9 +26,6 @@ importers: '@sentry/nextjs': specifier: ^7.118.0 version: 7.118.0(next@14.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) - '@supabase/supabase-js': - specifier: ^2.44.4 - version: 2.44.4 '@tanstack/react-query': specifier: ^4.36.1 version: 4.36.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -618,28 +615,6 @@ packages: resolution: {integrity: sha512-x0PYIMWcsTauqxgl7vWUY6sANl+XGKtx7DCVnnY7aOIIlIna0jChTAPANTfA2QrK+VK+4I/4JxatCEZBnXh3Og==} engines: {node: '>= 8'} - '@supabase/auth-js@2.64.4': - resolution: {integrity: sha512-9ITagy4WP4FLl+mke1rchapOH0RQpf++DI+WSG2sO1OFOZ0rW3cwAM0nCrMOxu+Zw4vJ4zObc08uvQrXx590Tg==} - - '@supabase/functions-js@2.4.1': - resolution: {integrity: sha512-8sZ2ibwHlf+WkHDUZJUXqqmPvWQ3UHN0W30behOJngVh/qHHekhJLCFbh0AjkE9/FqqXtf9eoVvmYgfCLk5tNA==} - - '@supabase/node-fetch@2.6.15': - resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==} - engines: {node: 4.x || >=6.0.0} - - '@supabase/postgrest-js@1.15.8': - resolution: {integrity: sha512-YunjXpoQjQ0a0/7vGAvGZA2dlMABXFdVI/8TuVKtlePxyT71sl6ERl6ay1fmIeZcqxiuFQuZw/LXUuStUG9bbg==} - - '@supabase/realtime-js@2.10.2': - resolution: {integrity: sha512-qyCQaNg90HmJstsvr2aJNxK2zgoKh9ZZA8oqb7UT2LCh3mj9zpa3Iwu167AuyNxsxrUE8eEJ2yH6wLCij4EApA==} - - '@supabase/storage-js@2.6.0': - resolution: {integrity: sha512-REAxr7myf+3utMkI2oOmZ6sdplMZZ71/2NEIEMBZHL9Fkmm3/JnaOZVSRqvG4LStYj2v5WhCruCzuMn6oD/Drw==} - - '@supabase/supabase-js@2.44.4': - resolution: {integrity: sha512-vqtUp8umqcgj+RPUc7LiEcQmgsEWFDPJdJizRJF/5tf2zSlVB+3YbUwyQE/hLagYA8TLvGXe7oAqtYyFde6llw==} - '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} @@ -706,9 +681,6 @@ packages: '@types/node@20.14.11': resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} - '@types/phoenix@1.6.5': - resolution: {integrity: sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==} - '@types/prop-types@15.7.12': resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -724,9 +696,6 @@ packages: '@types/stylis@4.2.5': resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} - '@types/ws@8.5.11': - resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} - '@typescript-eslint/eslint-plugin@7.17.0': resolution: {integrity: sha512-pyiDhEuLM3PuANxH7uNYan1AaFs5XE0zw1hq69JBvGvE7gSuEoQl1ydtEe/XQeoC3GQxLXyOVa5kNOATgM638A==} engines: {node: ^18.18.0 || >=20.0.0} @@ -2793,18 +2762,6 @@ packages: utf-8-validate: optional: true - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - xmldom@0.1.31: resolution: {integrity: sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==} engines: {node: '>=0.1'} @@ -3332,48 +3289,6 @@ snapshots: - encoding - supports-color - '@supabase/auth-js@2.64.4': - dependencies: - '@supabase/node-fetch': 2.6.15 - - '@supabase/functions-js@2.4.1': - dependencies: - '@supabase/node-fetch': 2.6.15 - - '@supabase/node-fetch@2.6.15': - dependencies: - whatwg-url: 5.0.0 - - '@supabase/postgrest-js@1.15.8': - dependencies: - '@supabase/node-fetch': 2.6.15 - - '@supabase/realtime-js@2.10.2': - dependencies: - '@supabase/node-fetch': 2.6.15 - '@types/phoenix': 1.6.5 - '@types/ws': 8.5.11 - ws: 8.18.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@supabase/storage-js@2.6.0': - dependencies: - '@supabase/node-fetch': 2.6.15 - - '@supabase/supabase-js@2.44.4': - dependencies: - '@supabase/auth-js': 2.64.4 - '@supabase/functions-js': 2.4.1 - '@supabase/node-fetch': 2.6.15 - '@supabase/postgrest-js': 1.15.8 - '@supabase/realtime-js': 2.10.2 - '@supabase/storage-js': 2.6.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - '@swc/counter@0.1.3': {} '@swc/helpers@0.5.5': @@ -3431,8 +3346,6 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/phoenix@1.6.5': {} - '@types/prop-types@15.7.12': {} '@types/react-dom@18.3.0': @@ -3449,10 +3362,6 @@ snapshots: '@types/stylis@4.2.5': {} - '@types/ws@8.5.11': - dependencies: - '@types/node': 20.14.11 - '@typescript-eslint/eslint-plugin@7.17.0(@typescript-eslint/parser@7.17.0(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0)(typescript@5.3.3)': dependencies: '@eslint-community/regexpp': 4.11.0 @@ -5771,8 +5680,6 @@ snapshots: ws@7.5.10: {} - ws@8.18.0: {} - xmldom@0.1.31: {} yn@3.1.1: {} diff --git a/public/robots.txt b/public/robots.txt index 37d92c8b521..b46953096fd 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -2,7 +2,6 @@ User-agent: * Allow: / User-agent: * -Disallow: /forgot-password Disallow: /widget Sitemap: https://jsoncrack.com/sitemap.txt diff --git a/public/sitemap.txt b/public/sitemap.txt index ce50d5477a0..2e6bb1f0565 100644 --- a/public/sitemap.txt +++ b/public/sitemap.txt @@ -1,6 +1,4 @@ https://jsoncrack.com -https://jsoncrack.com/sign-in -https://jsoncrack.com/sign-up https://jsoncrack.com/editor https://jsoncrack.com/docs https://jsoncrack.com/widget diff --git a/src/containers/Editor/components/BottomBar.tsx b/src/containers/Editor/components/BottomBar.tsx index e289e13ed11..5533e93820c 100644 --- a/src/containers/Editor/components/BottomBar.tsx +++ b/src/containers/Editor/components/BottomBar.tsx @@ -9,14 +9,12 @@ import { VscError, VscFeedback, VscRunAll, - VscSourceControl, VscSync, VscSyncIgnored, } from "react-icons/vsc"; import useGraph from "src/containers/Editor/components/views/GraphView/stores/useGraph"; import useConfig from "src/store/useConfig"; import useFile from "src/store/useFile"; -import useModal from "src/store/useModal"; const StyledBottomBar = styled.div` position: relative; @@ -88,12 +86,9 @@ export const BottomBar = () => { const error = useFile(state => state.error); const setContents = useFile(state => state.setContents); const nodeCount = useGraph(state => state.nodes.length); - const fileName = useFile(state => state.fileData?.name); const toggleFullscreen = useGraph(state => state.toggleFullscreen); const fullscreen = useGraph(state => state.fullscreen); - const setVisible = useModal(state => state.setVisible); - const toggleEditor = () => { toggleFullscreen(!fullscreen); gaEvent("toggle_fullscreen"); @@ -109,12 +104,6 @@ export const BottomBar = () => { - {fileName && ( - setVisible("cloud")(true)}> - - {fileName} - - )} {error ? ( diff --git a/src/containers/Modals/AccountModal/index.tsx b/src/containers/Modals/AccountModal/index.tsx deleted file mode 100644 index b8329363067..00000000000 --- a/src/containers/Modals/AccountModal/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React from "react"; -import type { ModalProps } from "@mantine/core"; -import { Modal, Group, Button, Avatar, Text, Divider, Paper, Badge, Anchor } from "@mantine/core"; -import useUser from "src/store/useUser"; - -export const AccountModal = ({ opened, onClose }: ModalProps) => { - const user = useUser(state => state.user); - const logout = useUser(state => state.logout); - - const username = - user?.user_metadata.full_name || user?.user_metadata.display_name || user?.user_metadata.name; - - return ( - - - - - JC - -
- - {username} - - - - - {user?.email} - - - - - - - Free - - - -
-
-
- - If you're already a premium user, please login at{" "} - - ToDiagram - - . - - - - - -
- ); -}; diff --git a/src/containers/Modals/ClearModal/index.tsx b/src/containers/Modals/ClearModal/index.tsx deleted file mode 100644 index ae57d118e5d..00000000000 --- a/src/containers/Modals/ClearModal/index.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from "react"; -import { useRouter } from "next/router"; -import type { ModalProps } from "@mantine/core"; -import { Modal, Group, Button, Text, Divider } from "@mantine/core"; -import { documentSvc } from "src/lib/api/document.service"; -import useJson from "src/store/useJson"; - -export const ClearModal = ({ opened, onClose }: ModalProps) => { - const setJson = useJson(state => state.setJson); - const { query, replace } = useRouter(); - - const handleClear = () => { - setJson("{}"); - onClose(); - - if (typeof query.json === "string") { - documentSvc.delete(query.json); - replace("/editor"); - } - }; - - return ( - - - Are you sure you want to delete JSON? - - - - - - - ); -}; diff --git a/src/containers/Modals/CloudModal/index.tsx b/src/containers/Modals/CloudModal/index.tsx deleted file mode 100644 index 671f158c302..00000000000 --- a/src/containers/Modals/CloudModal/index.tsx +++ /dev/null @@ -1,260 +0,0 @@ -import React from "react"; -import { useRouter } from "next/router"; -import type { ModalProps, DefaultMantineColor } from "@mantine/core"; -import { - Text, - ScrollArea, - Table, - ActionIcon, - Badge, - Paper, - Flex, - Button, - RingProgress, - Drawer, - LoadingOverlay, - Menu, - TextInput, - Alert, -} from "@mantine/core"; -import { useDebouncedValue } from "@mantine/hooks"; -import { useQuery } from "@tanstack/react-query"; -import dayjs from "dayjs"; -import relativeTime from "dayjs/plugin/relativeTime"; -import { event as gaEvent } from "nextjs-google-analytics"; -import toast from "react-hot-toast"; -import { BiSearch } from "react-icons/bi"; -import { FaTrash } from "react-icons/fa"; -import { LuDownload } from "react-icons/lu"; -import { SlOptionsVertical } from "react-icons/sl"; -import { VscAdd, VscWarning } from "react-icons/vsc"; -import type { FileFormat } from "src/enums/file.enum"; -import { documentSvc } from "src/lib/api/document.service"; -import type { File } from "src/store/useFile"; -import useFile from "src/store/useFile"; -import useModal from "src/store/useModal"; - -dayjs.extend(relativeTime); - -const colorByFormat: Record = { - json: "orange", - yaml: "blue", - xml: "red", - toml: "dark", - csv: "grape", -}; - -const TOTAL_QUOTA = 25; - -export const CloudModal = ({ opened, onClose }: ModalProps) => { - const setVisible = useModal(state => state.setVisible); - const setFile = useFile(state => state.setFile); - const [searchValue, setSearchValue] = React.useState(""); - const [debouncedSearchValue] = useDebouncedValue(searchValue, 1000); - const { isReady, replace } = useRouter(); - - const { data, isLoading, refetch } = useQuery( - ["allJson", debouncedSearchValue], - () => documentSvc.getAll(debouncedSearchValue), - { enabled: isReady && opened } - ); - - const isCreateDisabled = React.useMemo(() => { - if (!data?.length) return false; - return data.length >= TOTAL_QUOTA; - }, [data?.length]); - - const onCreate = async () => { - replace({ query: undefined }); - onClose(); - }; - - const openFile = React.useCallback( - async (id: string) => { - try { - const { data, error } = await documentSvc.getById(id); - if (error) throw new Error(error.message); - - if (data[0]) setFile(data[0]); - gaEvent("open_cloud_file"); - } catch (error) { - if (error instanceof Error) toast.error(error.message); - } finally { - onClose(); - } - }, - [onClose, setFile] - ); - - const downloadFile = React.useCallback(async (id: string) => { - try { - // it will fetch the file first, then download it with corresponsing format - const { data, error } = await documentSvc.getById(id); - if (error) throw new Error(error.message); - - const blob = new Blob([data[0].content], { type: "text/plain" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = `${data[0].name}.${data[0].format}`; - a.click(); - URL.revokeObjectURL(url); - - gaEvent("download_cloud_file"); - - return true; - } catch (error) { - if (error instanceof Error) { - toast.error(error.message); - } - return false; - } - }, []); - - const onDeleteClick = React.useCallback( - async (file: File) => { - try { - toast.loading("Deleting file...", { id: "delete-file" }); - - const { error } = await documentSvc.delete(file.id); - if (error) throw new Error(error.message); - - await refetch(); - toast.success(`Deleted ${file.name}!`, { id: "delete-file" }); - gaEvent("delete_cloud_file"); - } catch (error) { - if (error instanceof Error) { - toast.error(error.message, { id: "delete-file" }); - } - } finally { - toast.dismiss("delete-file"); - } - }, - [refetch] - ); - - const rows = React.useMemo( - () => - data?.map(element => ( - openFile(element.id)} - style={{ cursor: "pointer" }} - > - - - {element.format.toUpperCase()} - - - {element.name} - - {dayjs(element.updated_at).fromNow()} - - e.stopPropagation()}> - - - - - - - - - downloadFile(element.id)} - leftSection={} - > - Download - - - onDeleteClick(element)} - leftSection={} - > - Delete - - - - - - - )), - [data, downloadFile, onDeleteClick, openFile] - ); - - return ( - - }> - Cloud storage will be terminated on 1 October 2024. Please download your data before - the deadline. - - - - The Cloud Save feature is primarily designed for convenient access and is not advisable for - storing sensitive data. - - - setSearchValue(e.currentTarget.value)} - size="xs" - mb="sm" - placeholder="Search" - leftSection={} - /> - - - - {rows} -
-
- {data && ( - - - - TOTAL_QUOTA / 1.5 ? "red" : "blue", - }, - ]} - /> - - {data.length} / {TOTAL_QUOTA} - - - - )} -
-
- ); -}; diff --git a/src/containers/Modals/LoginModal/index.tsx b/src/containers/Modals/LoginModal/index.tsx deleted file mode 100644 index de3b56b3576..00000000000 --- a/src/containers/Modals/LoginModal/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import Link from "next/link"; -import type { ModalProps } from "@mantine/core"; -import { Modal, Stack, Button } from "@mantine/core"; - -export const LoginModal = ({ opened, onClose }: ModalProps) => { - return ( - - - - - - ); -}; diff --git a/src/containers/Modals/NoticeModal/index.tsx b/src/containers/Modals/NoticeModal/index.tsx deleted file mode 100644 index 37fff04d436..00000000000 --- a/src/containers/Modals/NoticeModal/index.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from "react"; -import type { ModalProps } from "@mantine/core"; -import { Anchor, Button, Center, Divider, Group, Modal, Text } from "@mantine/core"; -import { useLocalStorage } from "@mantine/hooks"; -import useModal from "src/store/useModal"; -import useUser from "src/store/useUser"; - -export const NoticeModal = (props: ModalProps) => { - const isAuthenticated = useUser(state => state.isAuthenticated); - const setVisible = useModal(state => state.setVisible); - const [seenModal, setSeenModal] = useLocalStorage({ - key: "seenNoticeModal", - defaultValue: false, - getInitialValueInEffect: false, - }); - - const closeModal = () => { - setSeenModal(true); - props.onClose?.(); - }; - - if (!isAuthenticated) return null; - - return ( - - Important Notice: Changes to Free Version - - } - opened={!seenModal || props.opened} - onClose={closeModal} - centered - zIndex={1000} - size="lg" - > -
- - Hello, -
-
- We want to inform you that starting from 1 October 2024, the following features will - be removed from the free version of our service: -
-
- • Sign-in / Sign-up -
- • Cloud Storage -
- • Share -
-
- - Any cloud-stored data that has not been accessed in the past 4 months will be - automatically deleted at 1 October 2024. - -
- To ensure you don't lose any important data, please download your data before the - deadline. If you wish to continue using these features, we recommend upgrading to{" "} - - ToDiagram - - , which will allow you to retain full access to these services and more. -
-
- Thank you for your understanding and continued support. -
- - - - - -
- ); -}; diff --git a/src/containers/Modals/index.ts b/src/containers/Modals/index.ts index 4705e264353..f581f0ba148 100644 --- a/src/containers/Modals/index.ts +++ b/src/containers/Modals/index.ts @@ -1,31 +1,22 @@ -export { CloudModal } from "./CloudModal"; -export { ClearModal } from "./ClearModal"; export { DownloadModal } from "./DownloadModal"; export { ImportModal } from "./ImportModal"; -export { AccountModal } from "./AccountModal"; export { NodeModal } from "./NodeModal"; -export { LoginModal } from "./LoginModal"; export { UpgradeModal } from "./UpgradeModal"; export { JWTModal } from "./JWTModal"; export { SchemaModal } from "./SchemaModal"; export { JQModal } from "./JQModal"; export { TypeModal } from "./TypeModal"; export { JPathModal } from "./JPathModal"; -export { NoticeModal } from "./NoticeModal"; type Modal = - | "cloud" | "download" | "import" - | "account" | "node" - | "login" | "upgrade" | "jwt" | "schema" | "jq" | "type" - | "jpath" - | "notice"; + | "jpath"; export type { Modal }; diff --git a/src/containers/Toolbar/AccountMenu.tsx b/src/containers/Toolbar/AccountMenu.tsx index 57dae29d47e..4516357d4ea 100644 --- a/src/containers/Toolbar/AccountMenu.tsx +++ b/src/containers/Toolbar/AccountMenu.tsx @@ -1,56 +1,28 @@ import React from "react"; -import Link from "next/link"; import { Menu, Avatar, Text } from "@mantine/core"; -import { VscSignIn, VscFeedback, VscSignOut } from "react-icons/vsc"; -import useModal from "src/store/useModal"; -import useUser from "src/store/useUser"; +import { FaRegCircleUser } from "react-icons/fa6"; +import { VscSignIn } from "react-icons/vsc"; import { StyledToolElement } from "./styles"; export const AccountMenu = () => { - const user = useUser(state => state.user?.user_metadata); - const logout = useUser(state => state.logout); - const setVisible = useModal(state => state.setVisible); - - const username = user?.full_name || user?.display_name || user?.name; - return ( - - {user && "JC"} + + - {user ? ( - } - onClick={() => setVisible("account")(true)} - closeMenuOnClick - > - {username ?? "Account"} - - ) : ( - - }> - Sign in - - - )} - {user && ( - <> - - - } closeMenuOnClick> - Feedback - - - } onClick={() => logout()} closeMenuOnClick> - Log out - - - )} + } + > + Sign up + ); diff --git a/src/containers/Toolbar/ToolsMenu.tsx b/src/containers/Toolbar/ToolsMenu.tsx index 8ea2435cc01..e52733db90f 100644 --- a/src/containers/Toolbar/ToolsMenu.tsx +++ b/src/containers/Toolbar/ToolsMenu.tsx @@ -6,6 +6,7 @@ import toast from "react-hot-toast"; import { CgChevronDown } from "react-icons/cg"; import { FaRandom } from "react-icons/fa"; import { FaWandMagicSparkles } from "react-icons/fa6"; +import { LuGlobe } from "react-icons/lu"; import { MdCompare, MdFilterListAlt } from "react-icons/md"; import { SiJsonwebtokens } from "react-icons/si"; import { VscSearchFuzzy, VscJson, VscGroupByRefType, VscLock } from "react-icons/vsc"; @@ -86,17 +87,6 @@ export const ToolsMenu = () => { JSON Path - } - rightSection={} - onClick={() => { - setVisible("upgrade")(true); - gaEvent("open_ai_filter_modal"); - }} - > - AI-Powered Filter - } @@ -120,6 +110,28 @@ export const ToolsMenu = () => { } onClick={randomizeData}> Randomize Data + } + rightSection={} + onClick={() => { + setVisible("upgrade")(true); + gaEvent("rest_client_modal"); + }} + > + REST Client + + } + rightSection={} + onClick={() => { + setVisible("upgrade")(true); + gaEvent("open_ai_filter_modal"); + }} + > + AI-Powered Filter + } diff --git a/src/containers/Toolbar/index.tsx b/src/containers/Toolbar/index.tsx index 96589fc4cb9..22ae57999fe 100644 --- a/src/containers/Toolbar/index.tsx +++ b/src/containers/Toolbar/index.tsx @@ -10,7 +10,6 @@ import { FileFormat } from "src/enums/file.enum"; import { JSONCrackLogo } from "src/layout/JsonCrackLogo"; import useFile from "src/store/useFile"; import useModal from "src/store/useModal"; -import useUser from "src/store/useUser"; import { AccountMenu } from "./AccountMenu"; import { FileMenu } from "./FileMenu"; import { Logo } from "./Logo"; @@ -57,7 +56,6 @@ export const Toolbar = ({ isWidget = false }: ToolbarProps) => { const setVisible = useModal(state => state.setVisible); const setFormat = useFile(state => state.setFormat); const format = useFile(state => state.format); - const isAuthenticated = useUser(state => state.isAuthenticated); return ( @@ -90,11 +88,6 @@ export const Toolbar = ({ isWidget = false }: ToolbarProps) => { - {isAuthenticated && ( - setVisible("cloud")(true)}> - Cloud - - )} )} diff --git a/src/layout/ModalController.tsx b/src/layout/ModalController.tsx index 9ba8f78b146..47aceb79faf 100644 --- a/src/layout/ModalController.tsx +++ b/src/layout/ModalController.tsx @@ -9,17 +9,13 @@ type ModalComponent = { key: Modal; component: React.FC }; const modalComponents: ModalComponent[] = [ { key: "import", component: Modals.ImportModal }, { key: "download", component: Modals.DownloadModal }, - { key: "cloud", component: Modals.CloudModal }, - { key: "account", component: Modals.AccountModal }, { key: "upgrade", component: Modals.UpgradeModal }, - { key: "login", component: Modals.LoginModal }, { key: "jwt", component: Modals.JWTModal }, { key: "node", component: Modals.NodeModal }, { key: "schema", component: Modals.SchemaModal }, { key: "jq", component: Modals.JQModal }, { key: "type", component: Modals.TypeModal }, { key: "jpath", component: Modals.JPathModal }, - { key: "notice", component: Modals.NoticeModal }, ]; const ModalController = () => { diff --git a/src/layout/Navbar.tsx b/src/layout/Navbar.tsx index 13eb67b9f81..52ea4e0eb01 100644 --- a/src/layout/Navbar.tsx +++ b/src/layout/Navbar.tsx @@ -60,48 +60,48 @@ export const Navbar = () => {
- - ) : ( -
- {errorMessage && ( - setErrorMessage(null)} - color="red" - py="xs" - mb="lg" - icon={} - withCloseButton - > - - {errorMessage} - - - )} - - - setEmail(e.target.value)} - required - label="Email" - placeholder="hello@jsoncrack.com" - radius="sm" - style={{ color: "black" }} - data-autofocus - /> - - - - - - -
- )} - - - Don't have an account? - - Sign up - - - - - )} - - ); -}; - -export default ForgotPassword; diff --git a/src/pages/oauth.tsx b/src/pages/oauth.tsx deleted file mode 100644 index f88d6a4c3d3..00000000000 --- a/src/pages/oauth.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useEffect } from "react"; -import { useRouter } from "next/router"; -import { NextSeo } from "next-seo"; -import { SEO } from "src/constants/seo"; -import { supabase } from "src/lib/api/supabase"; - -const Oauth = () => { - const { push } = useRouter(); - - useEffect(() => { - supabase.auth.getSession().then(({ data, error }) => { - if (error) return console.error(error); - if (!data.session) return; - push("/editor"); - }); - }, [push]); - - return ( - <> - - - ); -}; - -export default Oauth; diff --git a/src/pages/sign-in.tsx b/src/pages/sign-in.tsx deleted file mode 100644 index 2cbaa4dc85c..00000000000 --- a/src/pages/sign-in.tsx +++ /dev/null @@ -1,198 +0,0 @@ -import React, { useEffect } from "react"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import { - TextInput, - PasswordInput, - Button, - Anchor, - Stack, - Center, - Text, - FocusTrap, - Alert, - Box, - Flex, -} from "@mantine/core"; -import { NextSeo } from "next-seo"; -import { AiOutlineGithub } from "react-icons/ai"; -import { FcGoogle } from "react-icons/fc"; -import { MdErrorOutline } from "react-icons/md"; -import { SEO } from "src/constants/seo"; -import { AuthLayout } from "src/layout/AuthLayout"; -import { supabase } from "src/lib/api/supabase"; -import useUser from "src/store/useUser"; - -export function AuthenticationForm() { - const { push } = useRouter(); - const setSession = useUser(state => state.setSession); - const isAuthenticated = useUser(state => state.isAuthenticated); - const [errorMessage, setErrorMessage] = React.useState(null); - const [loading, setLoading] = React.useState(false); - const [userData, setUserData] = React.useState({ - name: "", - email: "", - password: "", - }); - - const onSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - - const { data, error } = await supabase.auth.signInWithPassword({ - email: userData.email, - password: userData.password, - }); - - if (error) { - setLoading(false); - return setErrorMessage("Incorrect email or password."); - } - - setSession(data.session); - push("/editor"); - }; - - const handleLoginClick = async (provider: "github" | "google") => { - await supabase.auth.signInWithOAuth({ - provider, - options: { redirectTo: `${window.location.origin}/oauth` }, - }); - }; - - if (isAuthenticated) { - return ( - - - You are already signed in. Click the button below to go to the editor. - - - - - - ); - } - - return ( - - {errorMessage && ( - setErrorMessage(null)} - color="red" - py="xs" - mb="lg" - icon={} - withCloseButton - > - - {errorMessage} - - - )} - -
- - setUserData(d => ({ ...d, email: event.target.value }))} - radius="sm" - style={{ color: "black" }} - withAsterisk={false} - /> - - setUserData(d => ({ ...d, password: event.target.value }))} - radius="sm" - style={{ color: "black" }} - withAsterisk={false} - /> - - - Forgot password? - - - -
-
- - - - - -
- ); -} - -const SignIn = () => { - const { push, query, pathname } = useRouter(); - - useEffect(() => { - supabase.auth.getSession().then(({ data, error }) => { - if (error) return console.error(error); - if (!data.session) return; - push("/editor"); - }); - }, [pathname, push, query.code]); - - return ( - - - -
- - Don't have an account? - - Sign up - - -
-
- ); -}; - -export default SignIn; diff --git a/src/pages/sign-up.tsx b/src/pages/sign-up.tsx deleted file mode 100644 index 3deda584363..00000000000 --- a/src/pages/sign-up.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React, { useEffect } from "react"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import { Anchor, Button, Center, Text } from "@mantine/core"; -import { NextSeo } from "next-seo"; -import { SEO } from "src/constants/seo"; -import { AuthLayout } from "src/layout/AuthLayout"; -import { supabase } from "src/lib/api/supabase"; - -const SignUp = () => { - const { push } = useRouter(); - - useEffect(() => { - supabase.auth.getSession().then(({ data }) => { - if (data.session) push("/editor"); - }); - }, [push]); - - return ( - - - JSON Crack is no longer accepting new sign-ups. - - For advanced features, please visit{" "} - - ToDiagram - - , or you can continue using JSON Crack without an account. - -
- - - -
-
- - Already have an account? - - Sign in - - -
-
- ); -}; - -export default SignUp; diff --git a/src/store/useFile.ts b/src/store/useFile.ts index a962d3762d2..9d4c35eebf3 100644 --- a/src/store/useFile.ts +++ b/src/store/useFile.ts @@ -3,7 +3,6 @@ import { event as gaEvent } from "nextjs-google-analytics"; import { toast } from "react-hot-toast"; import { create } from "zustand"; import { FileFormat } from "src/enums/file.enum"; -import { documentSvc } from "src/lib/api/document.service"; import { isIframe } from "src/lib/utils/helpers"; import { contentToJson, jsonToContent } from "src/lib/utils/jsonAdapter"; import useGraph from "../containers/Editor/components/views/GraphView/stores/useGraph"; @@ -64,7 +63,6 @@ interface JsonActions { setError: (error: string | null) => void; setHasChanges: (hasChanges: boolean) => void; setContents: (data: SetContents) => void; - fetchFile: (fileId: string) => void; fetchUrl: (url: string) => void; setFormat: (format: FileFormat) => void; clear: () => void; @@ -182,7 +180,6 @@ const useFile = create()((set, get) => ({ checkEditorSession: (url, widget) => { if (url && typeof url === "string") { if (isURL(url)) return get().fetchUrl(url); - return get().fetchFile(url); } let contents = defaultJson; @@ -193,18 +190,6 @@ const useFile = create()((set, get) => ({ if (format) set({ format }); get().setContents({ contents, hasChanges: false }); }, - fetchFile: async id => { - try { - const { data, error } = await documentSvc.getById(id); - if (error) throw error; - - if (data?.length) get().setFile(data[0]); - if (data?.length === 0) throw new Error("Document not found"); - } catch (error: any) { - if (error?.message) toast.error(error?.message); - get().setContents({ contents: defaultJson, hasChanges: false }); - } - }, })); export default useFile; diff --git a/src/store/useModal.ts b/src/store/useModal.ts index e75692af3a7..c40f3967b55 100644 --- a/src/store/useModal.ts +++ b/src/store/useModal.ts @@ -1,6 +1,5 @@ import { create } from "zustand"; import type { Modal } from "src/containers/Modals"; -import useUser from "./useUser"; type ModalState = { [key in Modal]: boolean; @@ -11,34 +10,20 @@ interface ModalActions { } const initialStates: ModalState = { - cloud: false, download: false, import: false, - account: false, node: false, - login: false, upgrade: false, jwt: false, schema: false, jq: false, type: false, jpath: false, - notice: false, }; -const authModals: Modal[] = ["cloud", "account"]; - const useModal = create()(set => ({ ...initialStates, - setVisible: modal => visible => { - const user = useUser.getState(); - - if (authModals.includes(modal) && !user.isAuthenticated) { - return set({ login: true }); - } - - set({ [modal]: visible }); - }, + setVisible: modal => visible => set({ [modal]: visible }), })); export default useModal; diff --git a/src/store/useUser.ts b/src/store/useUser.ts deleted file mode 100644 index 933aa56ec9e..00000000000 --- a/src/store/useUser.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { Session, User } from "@supabase/supabase-js"; -import { event as gaEvent } from "nextjs-google-analytics"; -import toast from "react-hot-toast"; -import { create } from "zustand"; -import { supabase } from "src/lib/api/supabase"; - -interface UserActions { - logout: () => void; - setSession: (session: Session) => void; -} - -interface UserStates { - user: User | null; - isAuthenticated: boolean; -} - -const initialStates: UserStates = { - user: null, - isAuthenticated: false, -}; - -const useUser = create()(set => ({ - ...initialStates, - setSession: async session => { - gaEvent("login"); - set({ user: session.user, isAuthenticated: true }); - }, - logout: async () => { - toast.loading("Logging out...", { id: "logout" }); - - const { error } = await supabase.auth.signOut({ scope: "local" }); - if (error) { - toast.error("Failed to log out."); - return; - } - - gaEvent("logout"); - set(initialStates); - toast.success("Logged out.", { id: "logout" }); - }, -})); - -export default useUser;