mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
feat: update premium modal ui
This commit is contained in:
parent
5c290a35d1
commit
53138b50c8
@ -93,7 +93,7 @@ export const Graph = ({ isWidget = false }: GraphProps) => {
|
|||||||
const changeRatio = Math.abs((areaSize * 100) / (paneWidth * paneHeight) - 100);
|
const changeRatio = Math.abs((areaSize * 100) / (paneWidth * paneHeight) - 100);
|
||||||
|
|
||||||
setPaneWidth(layout.width + 50);
|
setPaneWidth(layout.width + 50);
|
||||||
setPaneHeight(layout.height as number + 50);
|
setPaneHeight((layout.height as number) + 50);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
AiOutlineUnlock,
|
AiOutlineUnlock,
|
||||||
} from "react-icons/ai";
|
} from "react-icons/ai";
|
||||||
import { MdReportGmailerrorred, MdOutlineCheckCircleOutline } from "react-icons/md";
|
import { MdReportGmailerrorred, MdOutlineCheckCircleOutline } from "react-icons/md";
|
||||||
import { VscAccount } from "react-icons/vsc";
|
import { VscAccount, VscWorkspaceTrusted } from "react-icons/vsc";
|
||||||
import { saveJson, updateJson } from "src/services/db/json";
|
import { saveJson, updateJson } from "src/services/db/json";
|
||||||
import useJson from "src/store/useJson";
|
import useJson from "src/store/useJson";
|
||||||
import useModal from "src/store/useModal";
|
import useModal from "src/store/useModal";
|
||||||
@ -81,6 +81,7 @@ export const BottomBar = () => {
|
|||||||
const data = useJson(state => state.data);
|
const data = useJson(state => state.data);
|
||||||
const hasError = useJson(state => state.hasError);
|
const hasError = useJson(state => state.hasError);
|
||||||
const user = useUser(state => state.user);
|
const user = useUser(state => state.user);
|
||||||
|
const premium = useUser(state => state.isPremium());
|
||||||
const lightmode = useStored(state => state.lightmode);
|
const lightmode = useStored(state => state.lightmode);
|
||||||
const hasChanges = useJson(state => state.hasChanges);
|
const hasChanges = useJson(state => state.hasChanges);
|
||||||
|
|
||||||
@ -155,6 +156,12 @@ export const BottomBar = () => {
|
|||||||
<VscAccount />
|
<VscAccount />
|
||||||
{user ? user.name : "Login"}
|
{user ? user.name : "Login"}
|
||||||
</StyledBottomBarItem>
|
</StyledBottomBarItem>
|
||||||
|
{!premium && (
|
||||||
|
<StyledBottomBarItem onClick={() => setVisible("premium")(true)}>
|
||||||
|
<VscWorkspaceTrusted />
|
||||||
|
Upgrade to Premium
|
||||||
|
</StyledBottomBarItem>
|
||||||
|
)}
|
||||||
<StyledBottomBarItem error={!!hasError}>
|
<StyledBottomBarItem error={!!hasError}>
|
||||||
{hasError ? (
|
{hasError ? (
|
||||||
<Flex align="center" gap={2}>
|
<Flex align="center" gap={2}>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "next/link";
|
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Modal, Group, Button, Badge, Avatar, Grid, Divider, ModalProps } from "@mantine/core";
|
import { Modal, Group, Button, Badge, Avatar, Grid, Divider, ModalProps } from "@mantine/core";
|
||||||
import { IoRocketSharp } from "react-icons/io5";
|
import { IoRocketSharp } from "react-icons/io5";
|
||||||
|
import useModal from "src/store/useModal";
|
||||||
import useUser from "src/store/useUser";
|
import useUser from "src/store/useUser";
|
||||||
|
|
||||||
const StyledTitle = styled.div`
|
const StyledTitle = styled.div`
|
||||||
@ -43,6 +43,7 @@ const StyledContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const AccountModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
export const AccountModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||||
|
const setVisible = useModal(state => state.setVisible);
|
||||||
const user = useUser(state => state.user);
|
const user = useUser(state => state.user);
|
||||||
const isPremium = useUser(state => state.isPremium());
|
const isPremium = useUser(state => state.isPremium());
|
||||||
const logout = useUser(state => state.logout);
|
const logout = useUser(state => state.logout);
|
||||||
@ -101,15 +102,14 @@ export const AccountModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
|||||||
Cancel Subscription
|
Cancel Subscription
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Link href="/pricing" target="_blank" rel="noreferrer">
|
<Button
|
||||||
<Button
|
variant="gradient"
|
||||||
variant="gradient"
|
gradient={{ from: "teal", to: "lime", deg: 105 }}
|
||||||
gradient={{ from: "teal", to: "lime", deg: 105 }}
|
leftIcon={<IoRocketSharp />}
|
||||||
leftIcon={<IoRocketSharp />}
|
onClick={() => setVisible("premium")(true)}
|
||||||
>
|
>
|
||||||
UPGRADE TO PREMIUM!
|
UPGRADE TO PREMIUM!
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
|
||||||
)}
|
)}
|
||||||
<Button
|
<Button
|
||||||
color="red"
|
color="red"
|
||||||
|
@ -1,35 +1,85 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Link from "next/link";
|
import {
|
||||||
import { Modal, Group, Button, Divider, ModalProps, Title, Image } from "@mantine/core";
|
Modal,
|
||||||
import { IoRocketSharp } from "react-icons/io5";
|
ModalProps,
|
||||||
|
Title,
|
||||||
|
Flex,
|
||||||
|
Button,
|
||||||
|
Stack,
|
||||||
|
List,
|
||||||
|
ThemeIcon,
|
||||||
|
Divider,
|
||||||
|
Text,
|
||||||
|
Anchor,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { BsCheck } from "react-icons/bs";
|
||||||
|
|
||||||
export const PremiumModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
export const PremiumModal: React.FC<ModalProps> = ({ opened, onClose }) => {
|
||||||
return (
|
return (
|
||||||
<Modal title="JSON Crack Premium" opened={opened} onClose={onClose} centered>
|
<Modal title="Your Plan" size="auto" opened={opened} onClose={onClose} centered>
|
||||||
<Group py="sm">
|
<Flex gap="lg">
|
||||||
<Title
|
<Stack spacing="xs">
|
||||||
variant="gradient"
|
<Title order={3}>
|
||||||
order={3}
|
Free plan
|
||||||
gradient={{ from: "yellow", to: "hotpink" }}
|
<Text size="sm" color="dimmed">
|
||||||
strikethrough
|
(Free)
|
||||||
align="center"
|
</Text>
|
||||||
>
|
</Title>
|
||||||
Enhance your experience, unlock full benefits of JSON Crack!
|
<Button variant="filled" color="dark" size="md">
|
||||||
</Title>
|
Your current plan
|
||||||
<Image mx="auto" src="assets/bunny.png" width={150} alt="bunny" />
|
|
||||||
</Group>
|
|
||||||
<Divider py="xs" />
|
|
||||||
<Group position="center">
|
|
||||||
<Link href="/pricing" target="_blank" rel="noreferrer">
|
|
||||||
<Button
|
|
||||||
variant="gradient"
|
|
||||||
gradient={{ from: "yellow", to: "hotpink" }}
|
|
||||||
leftIcon={<IoRocketSharp />}
|
|
||||||
>
|
|
||||||
UPGRADE TO PREMIUM!
|
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
<List
|
||||||
</Group>
|
spacing="xs"
|
||||||
|
size="sm"
|
||||||
|
center
|
||||||
|
icon={
|
||||||
|
<ThemeIcon color="dark.6" size={20} radius="xl">
|
||||||
|
<BsCheck size="1rem" />
|
||||||
|
</ThemeIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<List.Item>Store up to 15 files</List.Item>
|
||||||
|
<List.Item>Visualize standard size data</List.Item>
|
||||||
|
</List>
|
||||||
|
</Stack>
|
||||||
|
<Divider color="gray" orientation="vertical" />
|
||||||
|
<Stack spacing="xs">
|
||||||
|
<Title order={3}>
|
||||||
|
Herowand Premium
|
||||||
|
<Text size="sm" color="dimmed">
|
||||||
|
USD 5$/mo
|
||||||
|
</Text>
|
||||||
|
</Title>
|
||||||
|
<Button
|
||||||
|
component="a"
|
||||||
|
href="https://www.patreon.com/herowand"
|
||||||
|
variant="filled"
|
||||||
|
color="teal"
|
||||||
|
size="md"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Upgrade plan
|
||||||
|
</Button>
|
||||||
|
<List
|
||||||
|
spacing="xs"
|
||||||
|
size="sm"
|
||||||
|
center
|
||||||
|
icon={
|
||||||
|
<ThemeIcon color="teal" size={20} radius="xl">
|
||||||
|
<BsCheck size="1rem" />
|
||||||
|
</ThemeIcon>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<List.Item>Edit directly on graph</List.Item>
|
||||||
|
<List.Item>JSON Schema support</List.Item>
|
||||||
|
<List.Item>Visualize data at full capability</List.Item>
|
||||||
|
<List.Item>Save up to 200 files</List.Item>
|
||||||
|
</List>
|
||||||
|
<Anchor fz="sm" href="https://editor.herowand.com" target="_blank">
|
||||||
|
Features are available at Herowand Editor
|
||||||
|
</Anchor>
|
||||||
|
</Stack>
|
||||||
|
</Flex>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,6 @@ interface UserActions {
|
|||||||
setUser: (key: keyof typeof initialStates, value: any) => void;
|
setUser: (key: keyof typeof initialStates, value: any) => void;
|
||||||
checkSession: () => void;
|
checkSession: () => void;
|
||||||
isPremium: () => boolean;
|
isPremium: () => boolean;
|
||||||
validatePremium: (cb: () => void) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialStates = {
|
const initialStates = {
|
||||||
@ -55,14 +54,6 @@ const useUser = create<UserStates & UserActions>()((set, get) => ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
validatePremium: callback => {
|
|
||||||
if (get().isAuthenticated) {
|
|
||||||
if (!get().isPremium()) return useModal.getState().setVisible("premium")(true);
|
|
||||||
return callback();
|
|
||||||
} else {
|
|
||||||
return useModal.getState().setVisible("account")(true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default useUser;
|
export default useUser;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user