payment
parent
1a50324895
commit
f646a19cdf
|
@ -152,7 +152,7 @@
|
||||||
"privacyPolicyLink": "Datenschutzerklärung",
|
"privacyPolicyLink": "Datenschutzerklärung",
|
||||||
"loginLink": "Jetzt anmelden",
|
"loginLink": "Jetzt anmelden",
|
||||||
"signUpLink": "Jetzt registrieren",
|
"signUpLink": "Jetzt registrieren",
|
||||||
"languageSwitchTo": "Switch to",
|
"languageSwitchTo": "Switch language to",
|
||||||
"login": {
|
"login": {
|
||||||
"button": "Anmelden",
|
"button": "Anmelden",
|
||||||
"forgotPassword": "Passwort vergessen?",
|
"forgotPassword": "Passwort vergessen?",
|
||||||
|
|
|
@ -132,7 +132,6 @@ export function App() {
|
||||||
options={{
|
options={{
|
||||||
username: appUserData.user.username,
|
username: appUserData.user.username,
|
||||||
permissions: appUserData.permissions,
|
permissions: appUserData.permissions,
|
||||||
paymentPlanStatus: appUserData.user.payment_plan_status,
|
|
||||||
paymentPlanTrialEnd: appUserData.user.payment_plan_trial_end,
|
paymentPlanTrialEnd: appUserData.user.payment_plan_trial_end,
|
||||||
paymentPlanCanceledAt: appUserData.user.payment_plan_canceled_at,
|
paymentPlanCanceledAt: appUserData.user.payment_plan_canceled_at,
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import Verification from "../../Pages/Verification";
|
||||||
|
|
||||||
// Lazy-loaded components
|
// Lazy-loaded components
|
||||||
const Authentication = lazy(() => import("../../Pages/Authentication"));
|
const Authentication = lazy(() => import("../../Pages/Authentication"));
|
||||||
const SignUp = lazy(() => import("../../Pages/Authentication/SignUp"));
|
|
||||||
const CheckoutSuccess = lazy(() =>
|
const CheckoutSuccess = lazy(() =>
|
||||||
import("../../Pages/Authentication/CheckoutSuccess")
|
import("../../Pages/Authentication/CheckoutSuccess")
|
||||||
);
|
);
|
||||||
|
|
|
@ -106,9 +106,8 @@ export function SideMenuContent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const showPaymentPlanInfoBanner =
|
const showPaymentPlanInfoBanner =
|
||||||
sideBarContext.paymentPlanStatus === "trialing" &&
|
sideBarContext.paymentPlanTrialEnd !== undefined ||
|
||||||
sideBarContext.paymentPlanTrialEnd !== null &&
|
sideBarContext.paymentPlanCanceledAt !== undefined;
|
||||||
sideBarContext.paymentPlanCanceledAt !== null;
|
|
||||||
|
|
||||||
const getSecondMenuItems = () => {
|
const getSecondMenuItems = () => {
|
||||||
let items = [];
|
let items = [];
|
||||||
|
@ -177,7 +176,8 @@ export function SideMenuContent({
|
||||||
|
|
||||||
const calculateExpiry = () => {
|
const calculateExpiry = () => {
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const expiryDate = new Date(sideBarContext.paymentPlanTrialEnd * 1000);
|
const expiryDate = new Date(sideBarContext.paymentPlanTrialEnd);
|
||||||
|
|
||||||
const diffTime = Math.abs(expiryDate - currentDate);
|
const diffTime = Math.abs(expiryDate - currentDate);
|
||||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,30 @@
|
||||||
import { Button, notification } from "antd";
|
import {
|
||||||
|
Alert,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Space,
|
||||||
|
Flex,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Typography,
|
||||||
|
Grid,
|
||||||
|
Skeleton,
|
||||||
|
notification,
|
||||||
|
} from "antd";
|
||||||
import { useAppContext } from "../../Contexts/AppContext";
|
import { useAppContext } from "../../Contexts/AppContext";
|
||||||
import { myFetch, showUnkownErrorNotification } from "../../utils";
|
import {
|
||||||
|
AppStyle,
|
||||||
|
FormatDatetime,
|
||||||
|
myFetch,
|
||||||
|
showUnkownErrorNotification,
|
||||||
|
} from "../../utils";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { CreditCardOutlined } from "@ant-design/icons";
|
import { CheckOutlined, CloseOutlined } from "@ant-design/icons";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import PageInDevelopment from "../PageInDevelopment";
|
import { ReactComponent as RocketLaunch } from "./rocket_launch_FILL1_wght400_GRAD0_opsz24.svg";
|
||||||
// import { ChoosenProduct } from "../Authentication/SignUp";
|
import { ReactComponent as Check } from "./task_alt_FILL0_wght400_GRAD0_opsz24.svg";
|
||||||
|
|
||||||
|
const { useBreakpoint } = Grid;
|
||||||
|
|
||||||
export default function PaymentPlan() {
|
export default function PaymentPlan() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -14,13 +33,287 @@ export default function PaymentPlan() {
|
||||||
const [notificationApi, notificationContextHolder] =
|
const [notificationApi, notificationContextHolder] =
|
||||||
notification.useNotification();
|
notification.useNotification();
|
||||||
|
|
||||||
const [isRequestingBillingDetails, setIsRequestingBillingDetails] =
|
const screenBreakpoint = useBreakpoint();
|
||||||
useState(false);
|
|
||||||
|
const [isRequesting, setIsRequesting] = useState(true);
|
||||||
|
const [requestData, setRequestData] = useState({
|
||||||
|
payment_plan: 0,
|
||||||
|
payment_plan_interval: 0,
|
||||||
|
prices: [],
|
||||||
|
payment_plan_trial_end: undefined,
|
||||||
|
payment_plan_canceled_at: undefined,
|
||||||
|
});
|
||||||
|
const [requestingCheckout, setRequestingCheckout] = useState(false);
|
||||||
|
|
||||||
|
const [selectedBillingPeriod, setSelectedBillingPeriod] = useState(0);
|
||||||
|
|
||||||
|
const fetchPaymentPlan = () => {
|
||||||
|
myFetch({
|
||||||
|
url: "/payment",
|
||||||
|
method: "GET",
|
||||||
|
notificationApi,
|
||||||
|
t,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
setRequestData(data);
|
||||||
|
setIsRequesting(false);
|
||||||
|
|
||||||
|
if (data.payment_plan_interval !== null) {
|
||||||
|
setSelectedBillingPeriod(data.payment_plan_interval);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setIsRequesting(false);
|
||||||
|
showUnkownErrorNotification(notificationApi, t);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => fetchPaymentPlan(), []);
|
||||||
|
|
||||||
|
const showAlert = () => {
|
||||||
|
if (
|
||||||
|
!isRequesting &&
|
||||||
|
requestData.payment_plan === 0 &&
|
||||||
|
requestData.payment_plan_trial_end &&
|
||||||
|
!requestData.payment_plan_canceled_at
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
message={
|
||||||
|
<Typography.Text>
|
||||||
|
Ihre Demo endet in <b>7 Tagen</b>. Jetzt einen Plan auswählen, um
|
||||||
|
den vollen Funktionsumfang zu nutzen.
|
||||||
|
</Typography.Text>
|
||||||
|
}
|
||||||
|
type="warning"
|
||||||
|
closable
|
||||||
|
showIcon
|
||||||
|
style={{ marginBottom: 12 }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{notificationContextHolder}
|
{notificationContextHolder}
|
||||||
<PageInDevelopment showBackButton={false} />
|
|
||||||
|
{showAlert()}
|
||||||
|
|
||||||
|
<Card title="Features & Preisübersicht">
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
<Col xs={24} xl={12}>
|
||||||
|
<Flex vertical>
|
||||||
|
<Space>
|
||||||
|
<Check />
|
||||||
|
<Typography.Text style={{ fontSize: 20 }}>
|
||||||
|
Unbegrenzte <b>Terminanzahl</b>
|
||||||
|
</Typography.Text>
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<Check />
|
||||||
|
<Typography.Text style={{ fontSize: 20 }}>
|
||||||
|
Bis zu <b>20 Mitarbeiter</b>
|
||||||
|
</Typography.Text>
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<Check />
|
||||||
|
<Typography.Text style={{ fontSize: 20 }}>
|
||||||
|
Buchungen bis zu <b>6 Wochen</b> im Voraus
|
||||||
|
</Typography.Text>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col xs={24} xl={12}>
|
||||||
|
<Flex justify="center" style={{ marginBottom: 12 }}>
|
||||||
|
<Space>
|
||||||
|
{isRequesting ? (
|
||||||
|
<Skeleton.Button shape="round" size="default" active />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type={selectedBillingPeriod === 0 ? "primary" : "default"}
|
||||||
|
shape="round"
|
||||||
|
icon={
|
||||||
|
requestData.payment_plan_interval === 0 &&
|
||||||
|
(requestData.payment_plan_canceled_at === undefined ? (
|
||||||
|
<CheckOutlined />
|
||||||
|
) : (
|
||||||
|
<CloseOutlined />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
onClick={() => setSelectedBillingPeriod(0)}
|
||||||
|
>
|
||||||
|
Monatlich
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isRequesting ? (
|
||||||
|
<Skeleton.Button shape="round" size="default" active />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
type={selectedBillingPeriod === 1 ? "primary" : "default"}
|
||||||
|
shape="round"
|
||||||
|
icon={
|
||||||
|
requestData.payment_plan_interval === 1 &&
|
||||||
|
(requestData.payment_plan_canceled_at === undefined ? (
|
||||||
|
<CheckOutlined />
|
||||||
|
) : (
|
||||||
|
<CloseOutlined />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
onClick={() => setSelectedBillingPeriod(1)}
|
||||||
|
>
|
||||||
|
Jährlich
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Card style={{ backgroundColor: AppStyle.colors.primary }}>
|
||||||
|
<Flex
|
||||||
|
justify="space-between"
|
||||||
|
vertical={screenBreakpoint.xs}
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<RocketLaunch
|
||||||
|
style={{
|
||||||
|
width: 62,
|
||||||
|
height: 62,
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
padding: 12,
|
||||||
|
borderRadius: 12,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
vertical
|
||||||
|
style={{ marginBottom: screenBreakpoint.xs && 12 }}
|
||||||
|
>
|
||||||
|
<Typography.Title
|
||||||
|
level={screenBreakpoint.xs ? 3 : 2}
|
||||||
|
style={{ color: "#fff" }}
|
||||||
|
>
|
||||||
|
Unternehmensplan
|
||||||
|
</Typography.Title>
|
||||||
|
|
||||||
|
{isRequesting ? (
|
||||||
|
<Skeleton.Button shape="round" block active />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
loading={requestingCheckout}
|
||||||
|
shape="round"
|
||||||
|
style={{ fontWeight: "bold" }}
|
||||||
|
onClick={() => {
|
||||||
|
setRequestingCheckout(true);
|
||||||
|
|
||||||
|
if (
|
||||||
|
selectedBillingPeriod ===
|
||||||
|
requestData.payment_plan_interval
|
||||||
|
) {
|
||||||
|
myFetch({
|
||||||
|
method: "GET",
|
||||||
|
url: "/payment/portal",
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (data.url) {
|
||||||
|
window.location.href = data.url;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setRequestingCheckout(false);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
myFetch({
|
||||||
|
method: "POST",
|
||||||
|
url: "/payment/checkout",
|
||||||
|
body: {
|
||||||
|
lookupKey: `za-basic-${
|
||||||
|
selectedBillingPeriod === 0 ? "monthly" : "yearly"
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
notificationApi,
|
||||||
|
t,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
if (data.url) {
|
||||||
|
window.location.href = data.url;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.status === "ok") {
|
||||||
|
fetchPaymentPlan();
|
||||||
|
setRequestingCheckout(false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
setRequestingCheckout(false);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedBillingPeriod ===
|
||||||
|
requestData.payment_plan_interval
|
||||||
|
? "Plan verwalten"
|
||||||
|
: "Jetzt buchen"}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex vertical align="center">
|
||||||
|
{isRequesting ? (
|
||||||
|
<Skeleton.Button shape="round" size="large" active />
|
||||||
|
) : (
|
||||||
|
<Typography.Title
|
||||||
|
level={screenBreakpoint.xs ? 3 : 2}
|
||||||
|
style={{
|
||||||
|
color: "#fff",
|
||||||
|
padding: 0,
|
||||||
|
margin: 0,
|
||||||
|
width: 76,
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{`${
|
||||||
|
requestData.prices.find(
|
||||||
|
(price) =>
|
||||||
|
price.lookup_key ===
|
||||||
|
`za-basic-${
|
||||||
|
selectedBillingPeriod === 0 ? "monthly" : "yearly"
|
||||||
|
}`
|
||||||
|
).unit_amount / (selectedBillingPeriod === 0 ? 1 : 12)
|
||||||
|
} €`}
|
||||||
|
</Typography.Title>
|
||||||
|
)}
|
||||||
|
<Typography.Text
|
||||||
|
style={{ color: "#fff", textAlign: "center" }}
|
||||||
|
>
|
||||||
|
/monatlich
|
||||||
|
</Typography.Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{selectedBillingPeriod === requestData.payment_plan &&
|
||||||
|
requestData.payment_plan_canceled_at !== undefined && (
|
||||||
|
<Flex justify="center">
|
||||||
|
<Typography.Text type="secondary">
|
||||||
|
Gekündigt am{" "}
|
||||||
|
{FormatDatetime(requestData.payment_plan_canceled_at)} Uhr
|
||||||
|
</Typography.Text>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m98-537 168-168q14-14 33-20t39-2l52 11q-54 64-85 116t-60 126L98-537Zm205 91q23-72 62.5-136T461-702q88-88 201-131.5T873-860q17 98-26 211T716-448q-55 55-120 95.5T459-289L303-446Zm276-120q23 23 56.5 23t56.5-23q23-23 23-56.5T692-679q-23-23-56.5-23T579-679q-23 23-23 56.5t23 56.5ZM551-85l-64-147q74-29 126.5-60T730-377l10 52q4 20-2 39.5T718-252L551-85ZM162-318q35-35 85-35.5t85 34.5q35 35 35 85t-35 85q-25 25-83.5 43T87-74q14-103 32-161t43-83Z"/></svg>
|
After Width: | Height: | Size: 544 B |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q65 0 123 19t107 53l-58 59q-38-24-81-37.5T480-800q-133 0-226.5 93.5T160-480q0 133 93.5 226.5T480-160q133 0 226.5-93.5T800-480q0-18-2-36t-6-35l65-65q11 32 17 66t6 70q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm-56-216L254-466l56-56 114 114 400-401 56 56-456 457Z"/></svg>
|
After Width: | Height: | Size: 467 B |
|
@ -14,7 +14,7 @@ root.render(
|
||||||
<ConfigProvider
|
<ConfigProvider
|
||||||
theme={{
|
theme={{
|
||||||
token: {
|
token: {
|
||||||
fontFamily: "Roboto, sans-serif",
|
fontFamily: "Outfit, sans-serif",
|
||||||
colorPrimary: "#1395f8",
|
colorPrimary: "#1395f8",
|
||||||
colorInfo: "#1395f8",
|
colorInfo: "#1395f8",
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue