mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-27 15:22:56 +08:00
update pricing styles
This commit is contained in:
parent
321a13ab37
commit
319abe039b
@ -53,10 +53,15 @@ const StyledBottomBarItem = styled.button`
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||||
|
|
||||||
&:hover {
|
&:hover:not(&:disabled) {
|
||||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
||||||
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: progress;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledImg = styled.img<{ light: boolean }>`
|
const StyledImg = styled.img<{ light: boolean }>`
|
||||||
@ -74,6 +79,7 @@ export const BottomBar = () => {
|
|||||||
const setVisible = useModal(state => state.setVisible);
|
const setVisible = useModal(state => state.setVisible);
|
||||||
const setHasChanges = useJson(state => state.setHasChanges);
|
const setHasChanges = useJson(state => state.setHasChanges);
|
||||||
const [isPrivate, setIsPrivate] = React.useState(false);
|
const [isPrivate, setIsPrivate] = React.useState(false);
|
||||||
|
const [isUpdating, setIsUpdating] = React.useState(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setIsPrivate(data?.private ?? false);
|
setIsPrivate(data?.private ?? false);
|
||||||
@ -84,6 +90,7 @@ export const BottomBar = () => {
|
|||||||
|
|
||||||
if (hasChanges) {
|
if (hasChanges) {
|
||||||
try {
|
try {
|
||||||
|
setIsUpdating(true);
|
||||||
toast.loading("Saving JSON...", { id: "jsonSave" });
|
toast.loading("Saving JSON...", { id: "jsonSave" });
|
||||||
const res = await saveJson({ id: query.json as string, data: getJson() });
|
const res = await saveJson({ id: query.json as string, data: getJson() });
|
||||||
|
|
||||||
@ -98,6 +105,8 @@ export const BottomBar = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toast.error("Failed to save JSON!", { id: "jsonSave" });
|
toast.error("Failed to save JSON!", { id: "jsonSave" });
|
||||||
|
} finally {
|
||||||
|
setIsUpdating(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [getJson, hasChanges, query.json, replace, setHasChanges, setVisible, user]);
|
}, [getJson, hasChanges, query.json, replace, setHasChanges, setVisible, user]);
|
||||||
@ -107,10 +116,24 @@ export const BottomBar = () => {
|
|||||||
else setVisible("login")(true);
|
else setVisible("login")(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPrivate = () => {
|
const setPrivate = async () => {
|
||||||
if (!query.json) return handleSaveJson();
|
try {
|
||||||
setIsPrivate(!isPrivate);
|
if (!query.json) return handleSaveJson();
|
||||||
updateJson(query.json as string, { private: !isPrivate });
|
if (!isPrivate && user?.type === 0) {
|
||||||
|
return window.open("https://jsoncrack.com/pricing", "_blank");
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsUpdating(true);
|
||||||
|
const res = await updateJson(query.json as string, { private: !isPrivate });
|
||||||
|
if (!res.errors?.items.length) {
|
||||||
|
setIsPrivate(res.data.private);
|
||||||
|
toast.success(`Document set to ${isPrivate ? "public" : "private"}.`);
|
||||||
|
} else throw res.errors;
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("An error occured while updating document!");
|
||||||
|
} finally {
|
||||||
|
setIsUpdating(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -120,14 +143,14 @@ export const BottomBar = () => {
|
|||||||
<VscAccount />
|
<VscAccount />
|
||||||
{user ? user.name : "Login"}
|
{user ? user.name : "Login"}
|
||||||
</StyledBottomBarItem>
|
</StyledBottomBarItem>
|
||||||
<StyledBottomBarItem onClick={handleSaveJson}>
|
<StyledBottomBarItem onClick={handleSaveJson} disabled={isUpdating}>
|
||||||
{hasChanges ? <AiOutlineCloudUpload /> : <AiOutlineCloudSync />}
|
{hasChanges ? <AiOutlineCloudUpload /> : <AiOutlineCloudSync />}
|
||||||
{hasChanges ? "Unsaved Changes" : "Saved"}
|
{hasChanges ? "Unsaved Changes" : "Saved"}
|
||||||
</StyledBottomBarItem>
|
</StyledBottomBarItem>
|
||||||
{data && (
|
{data && (
|
||||||
<>
|
<>
|
||||||
{typeof data.private !== "undefined" && (
|
{typeof data.private !== "undefined" && (
|
||||||
<StyledBottomBarItem onClick={setPrivate}>
|
<StyledBottomBarItem onClick={setPrivate} disabled={isUpdating}>
|
||||||
{isPrivate ? <AiOutlineLock /> : <AiOutlineUnlock />}
|
{isPrivate ? <AiOutlineLock /> : <AiOutlineUnlock />}
|
||||||
{isPrivate ? "Private" : "Public"}
|
{isPrivate ? "Private" : "Public"}
|
||||||
</StyledBottomBarItem>
|
</StyledBottomBarItem>
|
||||||
|
@ -18,6 +18,7 @@ import { Sponsors } from "src/components/Sponsors";
|
|||||||
import { SupportButton } from "src/components/SupportButton";
|
import { SupportButton } from "src/components/SupportButton";
|
||||||
import { baseURL } from "src/constants/data";
|
import { baseURL } from "src/constants/data";
|
||||||
import * as Styles from "./styles";
|
import * as Styles from "./styles";
|
||||||
|
import { PricingCards } from "../PricingCards";
|
||||||
|
|
||||||
const Navbar = () => (
|
const Navbar = () => (
|
||||||
<Styles.StyledNavbar>
|
<Styles.StyledNavbar>
|
||||||
@ -282,6 +283,7 @@ const Home: React.FC = () => {
|
|||||||
<FeaturesSection />
|
<FeaturesSection />
|
||||||
<GitHubSection />
|
<GitHubSection />
|
||||||
<EmbedSection />
|
<EmbedSection />
|
||||||
|
<PricingCards />
|
||||||
<SupportSection />
|
<SupportSection />
|
||||||
<SponsorSection />
|
<SponsorSection />
|
||||||
<SupportButton />
|
<SupportButton />
|
||||||
|
@ -80,7 +80,7 @@ const AccountView: React.FC<Pick<ModalProps, "setVisible">> = ({ setVisible }) =
|
|||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
ACCOUNT STATUS
|
ACCOUNT STATUS
|
||||||
<div>
|
<div>
|
||||||
{isPremium ? "PREMIUM " : "Normal"}
|
{isPremium ? "PREMIUM " : "Free"}
|
||||||
{isPremium && <MdVerified />}
|
{isPremium && <MdVerified />}
|
||||||
</div>
|
</div>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
@ -93,7 +93,11 @@ const AccountView: React.FC<Pick<ModalProps, "setVisible">> = ({ setVisible }) =
|
|||||||
<div>{user?.signUpAt && new Date(user.signUpAt).toDateString()}</div>
|
<div>{user?.signUpAt && new Date(user.signUpAt).toDateString()}</div>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
{isPremium ? (
|
{isPremium ? (
|
||||||
<Button status="DANGER" block>
|
<Button
|
||||||
|
status="DANGER"
|
||||||
|
block
|
||||||
|
onClick={() => window.open("https://patreon.com/jsoncrack", "_blank")}
|
||||||
|
>
|
||||||
<IoRocketSharp />
|
<IoRocketSharp />
|
||||||
Cancel Subscription
|
Cancel Subscription
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -4,7 +4,13 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import relativeTime from "dayjs/plugin/relativeTime";
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { AiOutlineEdit, AiOutlineLock, AiOutlinePlus, AiOutlineUnlock } from "react-icons/ai";
|
import {
|
||||||
|
AiOutlineEdit,
|
||||||
|
AiOutlineInfoCircle,
|
||||||
|
AiOutlineLock,
|
||||||
|
AiOutlinePlus,
|
||||||
|
AiOutlineUnlock,
|
||||||
|
} from "react-icons/ai";
|
||||||
import { FaTrash } from "react-icons/fa";
|
import { FaTrash } from "react-icons/fa";
|
||||||
import { IoRocketSharp } from "react-icons/io5";
|
import { IoRocketSharp } from "react-icons/io5";
|
||||||
import { Button } from "src/components/Button";
|
import { Button } from "src/components/Button";
|
||||||
@ -94,6 +100,16 @@ const StyledNameInput = styled.input`
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledInfoText = styled.span`
|
||||||
|
font-size: 10px;
|
||||||
|
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||||
|
|
||||||
|
svg {
|
||||||
|
vertical-align: text-top;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const GraphCard: React.FC<{ data: Json; refetch: () => void; active: boolean }> = ({
|
const GraphCard: React.FC<{ data: Json; refetch: () => void; active: boolean }> = ({
|
||||||
data,
|
data,
|
||||||
refetch,
|
refetch,
|
||||||
@ -241,7 +257,13 @@ export const CloudModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
|
|||||||
)}
|
)}
|
||||||
</StyledModalContent>
|
</StyledModalContent>
|
||||||
</Modal.Content>
|
</Modal.Content>
|
||||||
<Modal.Controls setVisible={setVisible}></Modal.Controls>
|
|
||||||
|
<Modal.Controls setVisible={setVisible}>
|
||||||
|
<StyledInfoText>
|
||||||
|
<AiOutlineInfoCircle />
|
||||||
|
Cloud Save feature is for ease-of-access only and recommended to not store sensitive data.
|
||||||
|
</StyledInfoText>
|
||||||
|
</Modal.Controls>
|
||||||
</StyledModal>
|
</StyledModal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
129
src/containers/PricingCards/index.tsx
Normal file
129
src/containers/PricingCards/index.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Button } from "src/components/Button";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const StyledSectionBody = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 50px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: rgba(181, 116, 214, 0.23);
|
||||||
|
width: 80%;
|
||||||
|
margin: 5% auto 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 50px;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingCard = styled.div<{ premium?: boolean }>`
|
||||||
|
padding: 6px;
|
||||||
|
padding-bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
${({ premium }) =>
|
||||||
|
premium
|
||||||
|
? `
|
||||||
|
background: rgba(255, 5, 214, 0.19);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
border: 1px solid rgba(255, 5, 214, 0.74);`
|
||||||
|
: `background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
-webkit-backdrop-filter: blur(5px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);`};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingCardTitle = styled.h2`
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 24px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingCardPrice = styled.h3`
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 24px;
|
||||||
|
color: ${({ theme }) => theme.SILVER};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingCardDetails = styled.ul`
|
||||||
|
color: ${({ theme }) => theme.TEXT_NORMAL};
|
||||||
|
line-height: 2.3;
|
||||||
|
padding: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingCardDetailsItem = styled.li`
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
@media only screen and (max-width: 768px) {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledButton = styled(Button)`
|
||||||
|
border: 1px solid white;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledPricingSection = styled.section`
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 25px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const PricingCards = () => {
|
||||||
|
return (
|
||||||
|
<StyledPricingSection>
|
||||||
|
<h1>Unlock Full Potential of JSON Crack</h1>
|
||||||
|
<StyledSectionBody>
|
||||||
|
<StyledPricingCard>
|
||||||
|
<StyledPricingCardTitle>Free</StyledPricingCardTitle>
|
||||||
|
<StyledPricingCardDetails>
|
||||||
|
<StyledPricingCardDetailsItem>Store up to 15 files</StyledPricingCardDetailsItem>
|
||||||
|
<StyledPricingCardDetailsItem>
|
||||||
|
Create short-links for saved JSON files
|
||||||
|
</StyledPricingCardDetailsItem>
|
||||||
|
<StyledPricingCardDetailsItem>Embed saved JSON instantly</StyledPricingCardDetailsItem>
|
||||||
|
</StyledPricingCardDetails>
|
||||||
|
</StyledPricingCard>
|
||||||
|
<StyledPricingCard premium>
|
||||||
|
<StyledPricingCardTitle>Premium</StyledPricingCardTitle>
|
||||||
|
<StyledPricingCardPrice>$5/mo</StyledPricingCardPrice>
|
||||||
|
<StyledPricingCardDetails>
|
||||||
|
<StyledPricingCardDetailsItem>
|
||||||
|
Create and share up to 200 files
|
||||||
|
</StyledPricingCardDetailsItem>
|
||||||
|
<StyledPricingCardDetailsItem>Store private JSON</StyledPricingCardDetailsItem>
|
||||||
|
<StyledPricingCardDetailsItem>
|
||||||
|
Get access to JSON Crack API to generate JSON remotely
|
||||||
|
</StyledPricingCardDetailsItem>
|
||||||
|
<StyledPricingCardDetailsItem>Everything in previous tier</StyledPricingCardDetailsItem>
|
||||||
|
</StyledPricingCardDetails>
|
||||||
|
<StyledButton
|
||||||
|
href="https://www.patreon.com/jsoncrack"
|
||||||
|
target="_blank"
|
||||||
|
status="SUCCESS"
|
||||||
|
block
|
||||||
|
link
|
||||||
|
>
|
||||||
|
GET IT NOW!
|
||||||
|
</StyledButton>
|
||||||
|
</StyledPricingCard>
|
||||||
|
</StyledSectionBody>
|
||||||
|
</StyledPricingSection>
|
||||||
|
);
|
||||||
|
};
|
@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button } from "src/components/Button";
|
import { Button } from "src/components/Button";
|
||||||
import { Footer } from "src/components/Footer";
|
import { Footer } from "src/components/Footer";
|
||||||
|
import { PricingCards } from "src/containers/PricingCards";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const StyledPageWrapper = styled.div`
|
const StyledPageWrapper = styled.div`
|
||||||
@ -13,108 +14,18 @@ const StyledHeroSection = styled.section`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledPricingSection = styled.section`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
background: rgba(181, 116, 214, 0.23);
|
|
||||||
width: 60%;
|
|
||||||
margin: 5% auto 0;
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 40px 20px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledPricingCard = styled.div<{ premium?: boolean }>`
|
|
||||||
padding: 6px;
|
|
||||||
width: 40%;
|
|
||||||
|
|
||||||
${({ premium }) =>
|
|
||||||
premium
|
|
||||||
? `
|
|
||||||
background: rgba(255, 5, 214, 0.19);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
-webkit-backdrop-filter: blur(5px);
|
|
||||||
border: 1px solid rgba(255, 5, 214, 0.74);`
|
|
||||||
: `background: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
-webkit-backdrop-filter: blur(5px);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);`};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledPricingCardTitle = styled.h2`
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 800;
|
|
||||||
font-size: 24px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledPricingCardPrice = styled.h3`
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 24px;
|
|
||||||
color: ${({ theme }) => theme.SILVER};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledPricingCardDetails = styled.ul`
|
|
||||||
color: ${({ theme }) => theme.TEXT_NORMAL};
|
|
||||||
line-height: 2.3;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledPricingCardDetailsItem = styled.li`
|
|
||||||
font-weight: 500;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledButton = styled(Button)`
|
|
||||||
border: 1px solid white;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Pricing = () => {
|
const Pricing = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledPageWrapper>
|
<StyledPageWrapper>
|
||||||
|
<Button href="/" link>
|
||||||
|
< Go Back
|
||||||
|
</Button>
|
||||||
<StyledHeroSection>
|
<StyledHeroSection>
|
||||||
<img src="assets/icon.png" alt="json crack" width="400" />
|
<img src="assets/icon.png" alt="json crack" width="400" />
|
||||||
<h1>Premium</h1>
|
<h1>Premium</h1>
|
||||||
</StyledHeroSection>
|
</StyledHeroSection>
|
||||||
<StyledPricingSection>
|
<PricingCards />
|
||||||
<StyledPricingCard>
|
|
||||||
<StyledPricingCardTitle>Free</StyledPricingCardTitle>
|
|
||||||
<StyledPricingCardDetails>
|
|
||||||
<StyledPricingCardDetailsItem>Store up to 20 files</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Create short-links for saved JSON files
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Embed saved JSON instantly
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
</StyledPricingCardDetails>
|
|
||||||
</StyledPricingCard>
|
|
||||||
<StyledPricingCard premium>
|
|
||||||
<StyledPricingCardTitle>Premium</StyledPricingCardTitle>
|
|
||||||
<StyledPricingCardPrice>$5/mo</StyledPricingCardPrice>
|
|
||||||
<StyledPricingCardDetails>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Create and share up to 200 files
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>Store private JSON</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Premium role at Discord server
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Get access to JSON Crack API to generate JSON remotely
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
<StyledPricingCardDetailsItem>
|
|
||||||
Everything in previous tier
|
|
||||||
</StyledPricingCardDetailsItem>
|
|
||||||
</StyledPricingCardDetails>
|
|
||||||
<StyledButton href="https://www.patreon.com/jsoncrack" status="SUCCESS" block link>
|
|
||||||
GET IT NOW!
|
|
||||||
</StyledButton>
|
|
||||||
</StyledPricingCard>
|
|
||||||
</StyledPricingSection>
|
|
||||||
</StyledPageWrapper>
|
</StyledPageWrapper>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user