mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-12 19:02:53 +08:00
feat: add react-ga events
This commit is contained in:
parent
5bcc9b0c7c
commit
d2b7d94183
@ -40,6 +40,7 @@
|
||||
"react": "^18.2.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-ga": "^3.3.1",
|
||||
"react-hot-toast": "^2.4.1",
|
||||
"react-icons": "^4.10.1",
|
||||
"react-linkify-it": "^1.0.7",
|
||||
|
@ -1,9 +1,12 @@
|
||||
import React from "react";
|
||||
import Script from "next/script";
|
||||
import ReactGA from "react-ga";
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV === "development";
|
||||
const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID;
|
||||
|
||||
ReactGA.initialize(GA_TRACKING_ID, { testMode: isDevelopment });
|
||||
|
||||
const GoogleAnalytics: React.FC = () => {
|
||||
if (isDevelopment) return null;
|
||||
|
||||
|
@ -149,7 +149,13 @@ export const Graph = ({ isWidget = false }: GraphProps) => {
|
||||
return (
|
||||
<>
|
||||
<Loading message="Painting graph..." loading={loading} />
|
||||
<StyledEditorWrapper onContextMenu={e => e.preventDefault()} widget={isWidget}>
|
||||
<StyledEditorWrapper
|
||||
onClick={() => {
|
||||
if ("activeElement" in document) (document.activeElement as HTMLElement)?.blur();
|
||||
}}
|
||||
onContextMenu={e => e.preventDefault()}
|
||||
widget={isWidget}
|
||||
>
|
||||
<TransformWrapper
|
||||
maxScale={2}
|
||||
minScale={0.05}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Flex, Input, Text } from "@mantine/core";
|
||||
import { getHotkeyHandler } from "@mantine/hooks";
|
||||
import { event } from "react-ga";
|
||||
import { AiOutlineSearch } from "react-icons/ai";
|
||||
import { useFocusNode } from "src/hooks/useFocusNode";
|
||||
|
||||
@ -14,6 +15,7 @@ export const SearchInput: React.FC = () => {
|
||||
id="search-node"
|
||||
value={searchValue}
|
||||
onChange={e => setValue(e.currentTarget.value)}
|
||||
onFocus={() => event({ action: "focus_node_search", category: "User" })}
|
||||
placeholder="Search Node"
|
||||
onKeyDown={getHotkeyHandler([["Enter", skip]])}
|
||||
icon={<AiOutlineSearch />}
|
||||
|
@ -2,6 +2,7 @@ import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { Flex, Group, MediaQuery, Menu, Select, Text } from "@mantine/core";
|
||||
import { useHotkeys } from "@mantine/hooks";
|
||||
import { event } from "react-ga";
|
||||
import toast from "react-hot-toast";
|
||||
import { AiOutlineFullscreen, AiOutlineMinus, AiOutlinePlus } from "react-icons/ai";
|
||||
import { CgArrowsMergeAltH, CgArrowsShrinkH, CgChevronDown } from "react-icons/cg";
|
||||
@ -207,7 +208,10 @@ export const Tools: React.FC<{ isWidget?: boolean }> = ({ isWidget = false }) =>
|
||||
<Menu.Dropdown>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
onClick={toggleEditor}
|
||||
onClick={() => {
|
||||
toggleEditor();
|
||||
event({ action: "toggle_hide_editor", category: "User", label: "Tools" });
|
||||
}}
|
||||
icon={fullscreen ? <VscLayoutSidebarLeft /> : <VscLayoutSidebarLeftOff />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} color="dimmed">
|
||||
@ -219,7 +223,10 @@ export const Tools: React.FC<{ isWidget?: boolean }> = ({ isWidget = false }) =>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
onClick={toggleDirection}
|
||||
onClick={() => {
|
||||
toggleDirection();
|
||||
event({ action: "toggle_layout_direction", category: "User", label: "Tools" });
|
||||
}}
|
||||
icon={<StyledFlowIcon rotate={rotateLayout(direction)} />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} color="dimmed">
|
||||
@ -231,7 +238,10 @@ export const Tools: React.FC<{ isWidget?: boolean }> = ({ isWidget = false }) =>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
onClick={toggleFoldNodes}
|
||||
onClick={() => {
|
||||
toggleFoldNodes();
|
||||
event({ action: "toggle_fold_nodes", category: "User", label: "Tools" });
|
||||
}}
|
||||
icon={foldNodes ? <CgArrowsShrinkH /> : <CgArrowsMergeAltH />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} color="dimmed">
|
||||
@ -243,7 +253,10 @@ export const Tools: React.FC<{ isWidget?: boolean }> = ({ isWidget = false }) =>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
onClick={toggleExpandCollapseGraph}
|
||||
onClick={() => {
|
||||
toggleExpandCollapseGraph();
|
||||
event({ action: "toggle_collapse_nodes", category: "User", label: "Tools" });
|
||||
}}
|
||||
icon={graphCollapsed ? <VscExpandAll /> : <VscCollapseAll />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} color="dimmed">
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
Stack,
|
||||
} from "@mantine/core";
|
||||
import { toBlob, toPng, toSvg } from "html-to-image";
|
||||
import { event } from "react-ga";
|
||||
import toast from "react-hot-toast";
|
||||
import { FiCopy, FiDownload } from "react-icons/fi";
|
||||
|
||||
@ -83,6 +84,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
toast.error("Failed to copy to clipboard");
|
||||
} finally {
|
||||
toast.dismiss("toastClipboard");
|
||||
event({ action: "click_clipboard_image", category: "User" });
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
@ -105,6 +107,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
toast.error("Failed to download image!");
|
||||
} finally {
|
||||
toast.dismiss("toastDownload");
|
||||
event({ action: "click_download_image", category: "User" });
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React from "react";
|
||||
import type { AppProps } from "next/app";
|
||||
import dynamic from "next/dynamic";
|
||||
import { useRouter } from "next/router";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
import { MantineProvider, MantineThemeOverride } from "@mantine/core";
|
||||
import { pageview } from "react-ga";
|
||||
import { monaSans } from "src/constants/customFonts";
|
||||
import GlobalStyle from "src/constants/globalStyle";
|
||||
import { lightTheme } from "src/constants/theme";
|
||||
@ -20,6 +22,20 @@ const mantineTheme: MantineThemeOverride = {
|
||||
};
|
||||
|
||||
function JsonCrack({ Component, pageProps }: AppProps) {
|
||||
const router = useRouter();
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleRouteChange = (url: string) => {
|
||||
pageview(url);
|
||||
};
|
||||
|
||||
router.events.on("routeChangeComplete", handleRouteChange);
|
||||
|
||||
return () => {
|
||||
router.events.off("routeChangeComplete", handleRouteChange);
|
||||
};
|
||||
}, [router.events]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<GoogleAnalytics />
|
||||
|
@ -1,6 +1,7 @@
|
||||
import debounce from "lodash.debounce";
|
||||
import _get from "lodash.get";
|
||||
import _set from "lodash.set";
|
||||
import { event } from "react-ga";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { create } from "zustand";
|
||||
import { defaultJson } from "src/constants/data";
|
||||
@ -105,6 +106,7 @@ const useFile = create<FileStates & JsonActions>()((set, get) => ({
|
||||
const jsonContent = await jsonToContent(JSON.stringify(contentJson, null, 2), format);
|
||||
|
||||
get().setContents({ contents: jsonContent, hasChanges: false });
|
||||
event({ action: "change_data_format", category: "User" });
|
||||
} catch (error) {
|
||||
get().clear();
|
||||
console.info("The content was unable to be converted, so it was cleared instead.");
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { modalview } from "react-ga";
|
||||
import { create } from "zustand";
|
||||
import { Modal } from "src/containers/Modals";
|
||||
import useUser from "./useUser";
|
||||
@ -40,6 +41,7 @@ const useModal = create<ModalState & ModalActions>()(set => ({
|
||||
return set({ premium: true });
|
||||
}
|
||||
|
||||
if (visible) modalview(modal);
|
||||
set({ [modal]: visible });
|
||||
},
|
||||
}));
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { setUser } from "@sentry/nextjs";
|
||||
import { set as gaSet } from "react-ga";
|
||||
import toast from "react-hot-toast";
|
||||
import { create } from "zustand";
|
||||
import { altogic } from "src/lib/api/altogic";
|
||||
@ -57,7 +58,10 @@ const useUser = create<UserStates & UserActions>()(set => ({
|
||||
toast.success("Logged out.");
|
||||
useModal.setState({ account: false });
|
||||
},
|
||||
login: user => set({ user: user as unknown as User, isAuthenticated: true }),
|
||||
login: user => {
|
||||
set({ user: user as unknown as User, isAuthenticated: true });
|
||||
gaSet({ userId: (user as User)._id });
|
||||
},
|
||||
checkSession: async () => {
|
||||
if (isDevelopment) {
|
||||
return set({ user: devUser as User, isAuthenticated: true, premium: true });
|
||||
@ -84,6 +88,7 @@ const useUser = create<UserStates & UserActions>()(set => ({
|
||||
premium: premiumData.premium,
|
||||
premiumCancelled: premiumData?.status === "cancelled" || false,
|
||||
});
|
||||
gaSet({ userId: user._id });
|
||||
} else if (new URLSearchParams(window.location.search).get("access_token")) {
|
||||
const { errors, user } = await altogic.auth.getAuthGrant();
|
||||
|
||||
@ -97,6 +102,7 @@ const useUser = create<UserStates & UserActions>()(set => ({
|
||||
|
||||
setUser({ id: user._id, email: user.email, username: user.name });
|
||||
set({ user: user as User, isAuthenticated: true, premium: premiumData.premium });
|
||||
gaSet({ userId: user._id });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
9
src/types/env.d.ts
vendored
Normal file
9
src/types/env.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NEXT_PUBLIC_BASE_URL: string;
|
||||
NEXT_PUBLIC_ALTOGIC_ENV_URL: string;
|
||||
NEXT_PUBLIC_ALTOGIC_CLIENT_KEY: string;
|
||||
NEXT_PUBLIC_PAYMENT_URL: string;
|
||||
NEXT_PUBLIC_GA_ID: string;
|
||||
}
|
||||
}
|
@ -3719,6 +3719,11 @@ react-fast-compare@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
|
||||
integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
|
||||
|
||||
react-ga@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-3.3.1.tgz#d8e1f4e05ec55ed6ff944dcb14b99011dfaf9504"
|
||||
integrity sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ==
|
||||
|
||||
react-hot-toast@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
|
||||
|
Loading…
x
Reference in New Issue
Block a user