mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
feat: add ga events
This commit is contained in:
parent
e4d9fff148
commit
4a5dcfb704
@ -15,6 +15,7 @@ import { BiSolidDockLeft } from "react-icons/bi";
|
||||
import { MdOutlineCheckCircleOutline } from "react-icons/md";
|
||||
import { TbTransform } from "react-icons/tb";
|
||||
import { VscError, VscFeedback, VscSourceControl, VscSync, VscSyncIgnored } from "react-icons/vsc";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import { documentSvc } from "src/services/document.service";
|
||||
import useConfig from "src/store/useConfig";
|
||||
import useFile from "src/store/useFile";
|
||||
@ -106,7 +107,10 @@ export const BottomBar = () => {
|
||||
const [isPrivate, setIsPrivate] = React.useState(false);
|
||||
const [isUpdating, setIsUpdating] = React.useState(false);
|
||||
|
||||
const toggleEditor = () => toggleFullscreen(!fullscreen);
|
||||
const toggleEditor = () => {
|
||||
toggleFullscreen(!fullscreen);
|
||||
gaEvent("Bottom Bar", "toggle fullscreen");
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsPrivate(data?.private ?? true);
|
||||
@ -239,12 +243,22 @@ export const BottomBar = () => {
|
||||
Share
|
||||
</StyledBottomBarItem>
|
||||
{liveTransformEnabled ? (
|
||||
<StyledBottomBarItem onClick={() => toggleLiveTransform(false)}>
|
||||
<StyledBottomBarItem
|
||||
onClick={() => {
|
||||
toggleLiveTransform(false);
|
||||
gaEvent("Bottom Bar", "toggle live transform", "manual");
|
||||
}}
|
||||
>
|
||||
<VscSync />
|
||||
<Text fz="xs">Live Transform</Text>
|
||||
</StyledBottomBarItem>
|
||||
) : (
|
||||
<StyledBottomBarItem onClick={() => toggleLiveTransform(true)}>
|
||||
<StyledBottomBarItem
|
||||
onClick={() => {
|
||||
toggleLiveTransform(true);
|
||||
gaEvent("Bottom Bar", "toggle live transform", "live");
|
||||
}}
|
||||
>
|
||||
<VscSyncIgnored />
|
||||
<Text fz="xs">Manual Transform</Text>
|
||||
</StyledBottomBarItem>
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
Badge,
|
||||
} from "@mantine/core";
|
||||
import { IoRocketSharp } from "react-icons/io5";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useModal from "src/store/useModal";
|
||||
import useUser from "src/store/useUser";
|
||||
|
||||
@ -62,7 +63,10 @@ export const AccountModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
variant="gradient"
|
||||
gradient={{ from: "teal", to: "lime", deg: 105 }}
|
||||
leftSection={<IoRocketSharp />}
|
||||
onClick={() => setVisible("premium")(true)}
|
||||
onClick={() => {
|
||||
setVisible("premium")(true);
|
||||
gaEvent("Account Modal", "click upgrade premium");
|
||||
}}
|
||||
>
|
||||
Upgrade to Premium
|
||||
</Button>
|
||||
|
@ -30,6 +30,7 @@ import { FaTrash } from "react-icons/fa";
|
||||
import { SlOptionsVertical } from "react-icons/sl";
|
||||
import { VscAdd } from "react-icons/vsc";
|
||||
import { FileFormat } from "src/enums/file.enum";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import { documentSvc } from "src/services/document.service";
|
||||
import useFile, { File } from "src/store/useFile";
|
||||
|
||||
@ -124,6 +125,7 @@ export const CloudModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
if (error) throw new Error(error.message);
|
||||
|
||||
if (data[0]) setFile(data[0]);
|
||||
gaEvent("Cloud Modal", "open file");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) toast.error(error.message);
|
||||
} finally {
|
||||
@ -134,14 +136,23 @@ export const CloudModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
);
|
||||
|
||||
const onDeleteClick = React.useCallback(
|
||||
(file: File) => {
|
||||
toast
|
||||
.promise(documentSvc.delete(file.id), {
|
||||
loading: "Deleting file...",
|
||||
error: "An error occurred while deleting the file!",
|
||||
success: `Deleted ${file.name}!`,
|
||||
})
|
||||
.then(() => refetch());
|
||||
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("Cloud Modal", "delete file");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
toast.error(error.message, { id: "delete-file" });
|
||||
}
|
||||
} finally {
|
||||
toast.dismiss("delete-file");
|
||||
}
|
||||
},
|
||||
[refetch]
|
||||
);
|
||||
|
@ -90,7 +90,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
]);
|
||||
|
||||
toast.success("Copied to clipboard");
|
||||
gaEvent("click", "clipboard image");
|
||||
gaEvent("Download Modal", "clipboard image");
|
||||
} catch (error) {
|
||||
toast.error("Failed to copy to clipboard");
|
||||
} finally {
|
||||
@ -111,7 +111,7 @@ export const DownloadModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
});
|
||||
|
||||
downloadURI(dataURI, `${fileDetails.filename}.${extension}`);
|
||||
gaEvent("download", "download graph image", extension);
|
||||
gaEvent("Download Modal", "download image", extension);
|
||||
} catch (error) {
|
||||
toast.error("Failed to download image!");
|
||||
} finally {
|
||||
|
@ -14,6 +14,7 @@ import { Dropzone } from "@mantine/dropzone";
|
||||
import toast from "react-hot-toast";
|
||||
import { AiOutlineUpload } from "react-icons/ai";
|
||||
import { FileFormat } from "src/enums/file.enum";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useFile from "src/store/useFile";
|
||||
|
||||
export const ImportModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
@ -28,6 +29,8 @@ export const ImportModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
setFile(null);
|
||||
|
||||
toast.loading("Loading...", { id: "toastFetch" });
|
||||
gaEvent("Import Modal", "fetch url");
|
||||
|
||||
return fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
@ -47,6 +50,8 @@ export const ImportModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
setURL("");
|
||||
onClose();
|
||||
});
|
||||
|
||||
gaEvent("Import Modal", "import file", format);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Modal, Button, ModalProps, Textarea, Divider, Group } from "@mantine/core";
|
||||
import { decode } from "jsonwebtoken";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useFile from "src/store/useFile";
|
||||
|
||||
export const JWTModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
@ -10,8 +11,9 @@ export const JWTModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
const resolve = () => {
|
||||
if (!token) return;
|
||||
const json = decode(token);
|
||||
|
||||
setContents({ contents: JSON.stringify(json, null, 2) });
|
||||
|
||||
gaEvent("JWT Modal", "resolve");
|
||||
setToken("");
|
||||
onClose();
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ import React from "react";
|
||||
import { Modal, Stack, Text, ScrollArea, ModalProps, Button } from "@mantine/core";
|
||||
import { CodeHighlight } from "@mantine/code-highlight";
|
||||
import { VscLock } from "react-icons/vsc";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useGraph from "src/store/useGraph";
|
||||
import useModal from "src/store/useModal";
|
||||
|
||||
@ -32,7 +33,10 @@ export const NodeModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
</ScrollArea.Autosize>
|
||||
</Stack>
|
||||
<Button
|
||||
onClick={() => setVisible("premium")(true)}
|
||||
onClick={() => {
|
||||
setVisible("premium")(true);
|
||||
gaEvent("Node Modal", "edit");
|
||||
}}
|
||||
rightSection={<VscLock strokeWidth={0.5} />}
|
||||
>
|
||||
Edit
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import { BsCheck } from "react-icons/bs";
|
||||
import { MdChevronRight } from "react-icons/md";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
|
||||
export const PremiumModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
return (
|
||||
@ -42,6 +43,7 @@ export const PremiumModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
<Stack gap="xs">
|
||||
<Title order={3}>Premium</Title>
|
||||
<Button
|
||||
onClick={() => gaEvent("Premium Modal", "click upgrade premium")}
|
||||
component={Link}
|
||||
prefetch={false}
|
||||
href="/pricing"
|
||||
|
@ -3,6 +3,7 @@ import { Stack, Modal, Button, ModalProps, Text, Anchor, Group, Divider } from "
|
||||
import Editor from "@monaco-editor/react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { VscLinkExternal } from "react-icons/vsc";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useConfig from "src/store/useConfig";
|
||||
import useFile from "src/store/useFile";
|
||||
|
||||
@ -32,8 +33,9 @@ export const SchemaModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
const onApply = () => {
|
||||
try {
|
||||
const parsedSchema = JSON.parse(schema);
|
||||
|
||||
setJsonSchema(parsedSchema);
|
||||
|
||||
gaEvent("Schema Modal", "apply");
|
||||
toast.success("Applied schema!");
|
||||
onClose();
|
||||
} catch (error) {
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import { FiExternalLink } from "react-icons/fi";
|
||||
import { MdCheck, MdCopyAll } from "react-icons/md";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
|
||||
export const ShareModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
const { query } = useRouter();
|
||||
@ -32,7 +33,13 @@ export const ShareModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
<CopyButton value={shareURL} timeout={2000}>
|
||||
{({ copied, copy }) => (
|
||||
<Tooltip label={copied ? "Copied" : "Copy"} withArrow position="right">
|
||||
<ActionIcon color={copied ? "teal" : "gray"} onClick={copy}>
|
||||
<ActionIcon
|
||||
color={copied ? "teal" : "gray"}
|
||||
onClick={() => {
|
||||
copy();
|
||||
gaEvent("Share Modal", "copy");
|
||||
}}
|
||||
>
|
||||
{copied ? <MdCheck size="1rem" /> : <MdCopyAll size="1rem" />}
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Stack, Modal, ModalProps, Select, ScrollArea } from "@mantine/core";
|
||||
import { CodeHighlight } from "@mantine/code-highlight";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useJson from "src/store/useJson";
|
||||
|
||||
enum Language {
|
||||
@ -93,7 +94,10 @@ export const TypeModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||
<Select
|
||||
value={selectedType}
|
||||
data={typeOptions}
|
||||
onChange={e => setSelectedType(e as Language)}
|
||||
onChange={e => {
|
||||
setSelectedType(e as Language);
|
||||
gaEvent("Type Modal", "generate", e as string);
|
||||
}}
|
||||
allowDeselect={false}
|
||||
/>
|
||||
<ScrollArea.Autosize mah={400} maw={700}>
|
||||
|
@ -19,7 +19,7 @@ export const FileMenu = () => {
|
||||
a.download = `jsoncrack.${getFormat()}`;
|
||||
a.click();
|
||||
|
||||
gaEvent("download", "file download");
|
||||
gaEvent("File Menu", "download", getFormat());
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -2,6 +2,7 @@ import React from "react";
|
||||
import { Menu, Text, Flex } from "@mantine/core";
|
||||
import { BsCheck2 } from "react-icons/bs";
|
||||
import { MdSettings } from "react-icons/md";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useConfig from "src/store/useConfig";
|
||||
import * as Styles from "./styles";
|
||||
|
||||
@ -32,37 +33,55 @@ export const OptionsMenu = () => {
|
||||
<Menu.Dropdown>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={rulersEnabled ? 100 : 0} />}
|
||||
onClick={() => toggleRulers(!rulersEnabled)}
|
||||
onClick={() => {
|
||||
toggleRulers(!rulersEnabled);
|
||||
gaEvent("Options Menu", "toggle rulers", rulersEnabled ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Rulers</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={gesturesEnabled ? 100 : 0} />}
|
||||
onClick={() => toggleGestures(!gesturesEnabled)}
|
||||
onClick={() => {
|
||||
toggleGestures(!gesturesEnabled);
|
||||
gaEvent("Options Menu", "toggle gestures", gesturesEnabled ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Trackpad Gestures</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={childrenCountVisible ? 100 : 0} />}
|
||||
onClick={() => toggleChildrenCount(!childrenCountVisible)}
|
||||
onClick={() => {
|
||||
toggleChildrenCount(!childrenCountVisible);
|
||||
gaEvent("Options Menu", "toggle children count", childrenCountVisible ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Item Count</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={imagePreviewEnabled ? 100 : 0} />}
|
||||
onClick={() => toggleImagePreview(!imagePreviewEnabled)}
|
||||
onClick={() => {
|
||||
toggleImagePreview(!imagePreviewEnabled);
|
||||
gaEvent("Options Menu", "toggle image preview", imagePreviewEnabled ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Image Link Preview</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={collapseButtonVisible ? 100 : 0} />}
|
||||
onClick={() => toggleCollapseButton(!collapseButtonVisible)}
|
||||
onClick={() => {
|
||||
toggleCollapseButton(!collapseButtonVisible);
|
||||
gaEvent("Options Menu", "toggle collapse button", collapseButtonVisible ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Show Expand/Collapse</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
leftSection={<BsCheck2 opacity={darkmodeEnabled ? 100 : 0} />}
|
||||
onClick={() => toggleDarkMode(!darkmodeEnabled)}
|
||||
onClick={() => {
|
||||
toggleDarkMode(!darkmodeEnabled);
|
||||
gaEvent("Options Menu", "toggle dark mode", darkmodeEnabled ? "on" : "off");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Dark Mode</Text>
|
||||
</Menu.Item>
|
||||
|
@ -14,7 +14,7 @@ export const ToolsMenu = () => {
|
||||
return (
|
||||
<Menu shadow="md" withArrow>
|
||||
<Menu.Target>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("click", "tools menu")}>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("Tools Menu", "toggle menu")}>
|
||||
<Flex align="center" gap={3}>
|
||||
Tools <CgChevronDown />
|
||||
</Flex>
|
||||
@ -25,27 +25,50 @@ export const ToolsMenu = () => {
|
||||
fz={12}
|
||||
leftSection={<MdCompare />}
|
||||
rightSection={<VscLock />}
|
||||
onClick={() => setVisible("premium")(true)}
|
||||
onClick={() => {
|
||||
setVisible("premium")(true);
|
||||
gaEvent("Tools Menu", "open", "Compare Data");
|
||||
}}
|
||||
>
|
||||
Compare Data
|
||||
</Menu.Item>
|
||||
<Menu.Item fz={12} leftSection={<VscSearchFuzzy />} onClick={() => setVisible("jq")(true)}>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
leftSection={<VscSearchFuzzy />}
|
||||
onClick={() => {
|
||||
setVisible("jq")(true);
|
||||
gaEvent("Tools Menu", "open", "JSON Query");
|
||||
}}
|
||||
>
|
||||
JSON Query (jq)
|
||||
</Menu.Item>
|
||||
<Menu.Item fz={12} leftSection={<VscJson />} onClick={() => setVisible("schema")(true)}>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
leftSection={<VscJson />}
|
||||
onClick={() => {
|
||||
setVisible("schema")(true);
|
||||
gaEvent("Tools Menu", "open", "JSON Schema");
|
||||
}}
|
||||
>
|
||||
JSON Schema
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
leftSection={<SiJsonwebtokens />}
|
||||
onClick={() => setVisible("jwt")(true)}
|
||||
onClick={() => {
|
||||
setVisible("jwt")(true);
|
||||
gaEvent("Tools Menu", "open", "Decode JWT");
|
||||
}}
|
||||
>
|
||||
Decode JWT
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
leftSection={<VscGroupByRefType />}
|
||||
onClick={() => setVisible("type")(true)}
|
||||
onClick={() => {
|
||||
setVisible("type")(true);
|
||||
gaEvent("Tools Menu", "open", "Generate Type");
|
||||
}}
|
||||
>
|
||||
Generate Type
|
||||
</Menu.Item>
|
||||
|
@ -65,7 +65,7 @@ export const ViewMenu = () => {
|
||||
return (
|
||||
<Menu shadow="md" closeOnItemClick={false} withArrow>
|
||||
<Menu.Target>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("click", "view menu")}>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("View Menu", "open menu")}>
|
||||
<Flex align="center" gap={3}>
|
||||
View <CgChevronDown />
|
||||
</Flex>
|
||||
@ -76,7 +76,10 @@ export const ViewMenu = () => {
|
||||
miw={205}
|
||||
size="xs"
|
||||
value={viewMode}
|
||||
onChange={e => setViewMode(e as ViewMode)}
|
||||
onChange={e => {
|
||||
setViewMode(e as ViewMode);
|
||||
gaEvent("View Menu", "change view mode", e as string);
|
||||
}}
|
||||
data={[
|
||||
{ value: ViewMode.Graph, label: "Graph" },
|
||||
{ value: ViewMode.Tree, label: "Tree" },
|
||||
@ -88,7 +91,10 @@ export const ViewMenu = () => {
|
||||
<Menu.Item
|
||||
mt="xs"
|
||||
fz={12}
|
||||
onClick={toggleDirection}
|
||||
onClick={() => {
|
||||
toggleDirection();
|
||||
gaEvent("View Menu", "rotate layout");
|
||||
}}
|
||||
leftSection={<Styles.StyledFlowIcon rotate={rotateLayout(direction || "RIGHT")} />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} c="dimmed">
|
||||
@ -100,7 +106,10 @@ export const ViewMenu = () => {
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
fz={12}
|
||||
onClick={toggleExpandCollapseGraph}
|
||||
onClick={() => {
|
||||
toggleExpandCollapseGraph();
|
||||
gaEvent("View Menu", "expand collapse graph");
|
||||
}}
|
||||
leftSection={graphCollapsed ? <VscExpandAll /> : <VscCollapseAll />}
|
||||
rightSection={
|
||||
<Text ml="md" fz={10} c="dimmed">
|
||||
|
@ -27,7 +27,7 @@ export const ZoomMenu = () => {
|
||||
return (
|
||||
<Menu shadow="md" trigger="click" closeOnItemClick={false} withArrow>
|
||||
<Menu.Target>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("click", "zoom menu")}>
|
||||
<Styles.StyledToolElement onClick={() => gaEvent("Zoom Menu", "open menu")}>
|
||||
<Flex gap={4} align="center">
|
||||
{Math.round(zoomFactor * 100)}%
|
||||
<CgChevronDown />
|
||||
@ -45,22 +45,56 @@ export const ZoomMenu = () => {
|
||||
rightSection="%"
|
||||
/>
|
||||
</Menu.Item>
|
||||
<Menu.Item rightSection="+" onClick={zoomIn}>
|
||||
<Menu.Item
|
||||
rightSection="+"
|
||||
onClick={() => {
|
||||
zoomIn();
|
||||
gaEvent("Zoom Menu", "zoom in");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom in</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item rightSection="-" onClick={zoomOut}>
|
||||
<Menu.Item
|
||||
rightSection="-"
|
||||
onClick={() => {
|
||||
zoomOut();
|
||||
gaEvent("Zoom Menu", "zoom out");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom out</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item rightSection="⇧ 1" onClick={centerView}>
|
||||
<Menu.Item
|
||||
rightSection="⇧ 1"
|
||||
onClick={() => {
|
||||
centerView();
|
||||
gaEvent("Zoom Menu", "center view");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom to fit</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item onClick={() => setZoomFactor(50 / 100)}>
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
setZoomFactor(50 / 100);
|
||||
gaEvent("Zoom Menu", "zoom to 50%");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom to %50</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item rightSection="⇧ 0" onClick={() => setZoomFactor(100 / 100)}>
|
||||
<Menu.Item
|
||||
rightSection="⇧ 0"
|
||||
onClick={() => {
|
||||
setZoomFactor(100 / 100);
|
||||
gaEvent("Zoom Menu", "zoom to 100%");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom to %100</Text>
|
||||
</Menu.Item>
|
||||
<Menu.Item onClick={() => setZoomFactor(200 / 100)}>
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
setZoomFactor(200 / 100);
|
||||
gaEvent("Zoom Menu", "zoom to 200%");
|
||||
}}
|
||||
>
|
||||
<Text size="xs">Zoom to %200</Text>
|
||||
</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
|
@ -8,6 +8,7 @@ import { FiDownload } from "react-icons/fi";
|
||||
import { SearchInput } from "src/components/SearchInput";
|
||||
import { FileFormat } from "src/enums/file.enum";
|
||||
import { JSONCrackLogo } from "src/layout/JsonCrackLogo";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useFile from "src/store/useFile";
|
||||
import useModal from "src/store/useModal";
|
||||
import { AccountMenu } from "./AccountMenu";
|
||||
@ -80,6 +81,7 @@ export const Toolbar: React.FC<{ isWidget?: boolean }> = ({ isWidget = false })
|
||||
onClick={() => {
|
||||
setSeenPremium(true);
|
||||
setVisible("premium")(true);
|
||||
gaEvent("Toolbar", "click upgrade premium");
|
||||
}}
|
||||
>
|
||||
<Indicator
|
||||
|
@ -4,6 +4,7 @@ import { Button, Title } from "@mantine/core";
|
||||
import styled from "styled-components";
|
||||
import { MdChevronRight } from "react-icons/md";
|
||||
import { JSONCrackLogo } from "src/layout/JsonCrackLogo";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
|
||||
const StyledPremiumView = styled.div`
|
||||
position: relative;
|
||||
@ -166,6 +167,7 @@ export const PremiumView = () => (
|
||||
</StyledInfo>
|
||||
|
||||
<Button
|
||||
onClick={() => gaEvent("Premium View", "click upgrade premium")}
|
||||
component={Link}
|
||||
prefetch={false}
|
||||
href="/pricing"
|
||||
|
@ -39,7 +39,7 @@ export const useFocusNode = () => {
|
||||
setNodeCount(0);
|
||||
}
|
||||
|
||||
gaEvent("input", "search node in graph");
|
||||
gaEvent("Graph", "search");
|
||||
}, [selectedNode, debouncedValue, value, viewPort]);
|
||||
|
||||
return [value, setValue, skip, nodeCount, selectedNode] as const;
|
||||
|
@ -15,6 +15,7 @@ import styled from "styled-components";
|
||||
import { AiOutlineInfoCircle } from "react-icons/ai";
|
||||
import { VscArrowRight } from "react-icons/vsc";
|
||||
import Layout from "src/layout/Layout";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useUser from "src/store/useUser";
|
||||
|
||||
const purchaseLinks = {
|
||||
@ -161,6 +162,7 @@ export const PricingCards = () => {
|
||||
</Flex>
|
||||
<Button
|
||||
component="a"
|
||||
onClick={() => gaEvent("Pricing", "click upgrade premium")}
|
||||
href={paymentURL(isMonthly ? purchaseLinks.monthly : purchaseLinks.annual)}
|
||||
target="_blank"
|
||||
size="lg"
|
||||
|
@ -45,6 +45,6 @@ export const documentSvc = {
|
||||
return await supabase.from("document").update(data).eq("id", id).select("private");
|
||||
},
|
||||
delete: async (id: string) => {
|
||||
await supabase.from("document").delete().eq("id", id);
|
||||
return await supabase.from("document").delete().eq("id", id);
|
||||
},
|
||||
};
|
||||
|
@ -3,7 +3,6 @@ import { toast } from "react-hot-toast";
|
||||
import { create } from "zustand";
|
||||
import { defaultJson } from "src/constants/data";
|
||||
import { FileFormat } from "src/enums/file.enum";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import { contentToJson, jsonToContent } from "src/lib/utils/json/jsonAdapter";
|
||||
import { isIframe } from "src/lib/utils/widget";
|
||||
import { documentSvc } from "src/services/document.service";
|
||||
@ -69,19 +68,6 @@ const debouncedUpdateJson = debounce((value: unknown) => {
|
||||
useJson.getState().setJson(JSON.stringify(value, null, 2));
|
||||
}, 800);
|
||||
|
||||
const filterArrayAndObjectFields = (obj: object) => {
|
||||
const result = {};
|
||||
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (Array.isArray(obj[key]) || typeof obj[key] === "object") {
|
||||
result[key] = obj[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
const useFile = create<FileStates & JsonActions>()((set, get) => ({
|
||||
...initialStates,
|
||||
clear: () => {
|
||||
@ -105,7 +91,6 @@ const useFile = create<FileStates & JsonActions>()((set, get) => ({
|
||||
const jsonContent = await jsonToContent(JSON.stringify(contentJson, null, 2), format);
|
||||
|
||||
get().setContents({ contents: jsonContent });
|
||||
gaEvent("input", "file format change");
|
||||
} catch (error) {
|
||||
get().clear();
|
||||
console.warn("The content was unable to be converted, so it was cleared instead.");
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import { Modal } from "src/containers/Modals";
|
||||
import { gaEvent } from "src/lib/utils/gaEvent";
|
||||
import useUser from "./useUser";
|
||||
|
||||
type ModalState = {
|
||||
@ -40,7 +39,6 @@ const useModal = create<ModalState & ModalActions>()(set => ({
|
||||
return set({ login: true });
|
||||
}
|
||||
|
||||
if (visible) gaEvent("modal", `open ${modal}`);
|
||||
set({ [modal]: visible });
|
||||
},
|
||||
}));
|
||||
|
Loading…
x
Reference in New Issue
Block a user