payment plan settings
parent
cf0b173ab7
commit
dac70b358a
|
@ -126,7 +126,9 @@
|
||||||
},
|
},
|
||||||
"support": "Unterstützung",
|
"support": "Unterstützung",
|
||||||
"feedback": "Feedback",
|
"feedback": "Feedback",
|
||||||
"paymentPlan": "Zahlungsplan"
|
"paymentPlan": "Zahlungsplan",
|
||||||
|
"paymentPlanTrailingDaysLeft": "{{daysLeft}} {{dayUnit}} verbleibend",
|
||||||
|
"paymentPlanUpgradeButton": "Jetzt upgraden"
|
||||||
},
|
},
|
||||||
"employees": {
|
"employees": {
|
||||||
"pageTitle": "Mitarbeiter",
|
"pageTitle": "Mitarbeiter",
|
||||||
|
@ -184,7 +186,6 @@
|
||||||
"choosenProduct": {
|
"choosenProduct": {
|
||||||
"title": "Ausgewähltes Produkt",
|
"title": "Ausgewähltes Produkt",
|
||||||
"products": [
|
"products": [
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
"price": "9,99 € / Monat",
|
"price": "9,99 € / Monat",
|
||||||
"featuresCount": 9,
|
"featuresCount": 9,
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
"hour": "hour",
|
"hour": "hour",
|
||||||
"minutes": "minutes",
|
"minutes": "minutes",
|
||||||
"minute": "minute",
|
"minute": "minute",
|
||||||
"days": "Days",
|
"days": "days",
|
||||||
"day": "Day",
|
"day": "day",
|
||||||
"separator": "and"
|
"separator": "and"
|
||||||
},
|
},
|
||||||
"failed": "Failed",
|
"failed": "Failed",
|
||||||
|
@ -126,7 +126,9 @@
|
||||||
},
|
},
|
||||||
"support": "Support",
|
"support": "Support",
|
||||||
"feedback": "Feedback",
|
"feedback": "Feedback",
|
||||||
"paymentPlan": "Payment plan"
|
"paymentPlan": "Payment plan",
|
||||||
|
"paymentPlanTrailingDaysLeft": "{{daysLeft}} {{dayUnit}} left",
|
||||||
|
"paymentPlanUpgradeButton": "Upgrade now"
|
||||||
},
|
},
|
||||||
"employees": {
|
"employees": {
|
||||||
"pageTitle": "Employees",
|
"pageTitle": "Employees",
|
||||||
|
@ -184,7 +186,6 @@
|
||||||
"choosenProduct": {
|
"choosenProduct": {
|
||||||
"title": "Choosen product",
|
"title": "Choosen product",
|
||||||
"products": [
|
"products": [
|
||||||
{},
|
|
||||||
{
|
{
|
||||||
"price": "9,99 € / month",
|
"price": "9,99 € / month",
|
||||||
"featuresCount": 9,
|
"featuresCount": 9,
|
||||||
|
|
|
@ -132,6 +132,9 @@ 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,
|
||||||
|
paymentPlanCanceledAt: appUserData.user.payment_plan_canceled_at,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UserProfileProvider>
|
<UserProfileProvider>
|
||||||
|
@ -139,6 +142,7 @@ export function App() {
|
||||||
<AppProvider
|
<AppProvider
|
||||||
options={{
|
options={{
|
||||||
paymentPlan: appUserData.user.payment_plan,
|
paymentPlan: appUserData.user.payment_plan,
|
||||||
|
paymentPlanSettings: appUserData.paymentPlanSettings,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StoresProvider options={{ stores: appUserData.stores }}>
|
<StoresProvider options={{ stores: appUserData.stores }}>
|
||||||
|
|
|
@ -134,10 +134,7 @@ export function MyCalendarMaxFutureBookingDaysFormInput({
|
||||||
<MyFormInput
|
<MyFormInput
|
||||||
formItemName={formItemName}
|
formItemName={formItemName}
|
||||||
minLength={Constants.GLOBALS.MIN_CALENDAR_FUTURE_BOOKING_DAYS}
|
minLength={Constants.GLOBALS.MIN_CALENDAR_FUTURE_BOOKING_DAYS}
|
||||||
maxLength={
|
maxLength={appContext.paymentPlanSettings.maxEmployees}
|
||||||
Constants.PAYMENT_PLAN[appContext.paymentPlan]
|
|
||||||
.calendarMaxFutureBookingDays
|
|
||||||
}
|
|
||||||
label={t("common.calendarMaxFutureBookingDays")}
|
label={t("common.calendarMaxFutureBookingDays")}
|
||||||
ruleMessageValueRequired={t(
|
ruleMessageValueRequired={t(
|
||||||
"common.inputRules.calendarMaxFutureBookingDaysRequired"
|
"common.inputRules.calendarMaxFutureBookingDaysRequired"
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
WalletOutlined,
|
WalletOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { Divider, Menu } from "antd";
|
import { Button, Card, Divider, Flex, Menu, Typography } from "antd";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { BreakpointLgWidth, Constants, isDevelopmentEnv } from "../../utils";
|
import { BreakpointLgWidth, Constants, isDevelopmentEnv } from "../../utils";
|
||||||
|
@ -100,6 +100,12 @@ export function SideMenuContent({
|
||||||
return items;
|
return items;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showPaymentPlanInfoBanner =
|
||||||
|
sideBarContext.permissions.includes("paymentPlan") &&
|
||||||
|
sideBarContext.paymentPlanStatus === "trialing" &&
|
||||||
|
sideBarContext.paymentPlanTrialEnd !== null &&
|
||||||
|
sideBarContext.paymentPlanCanceledAt !== null;
|
||||||
|
|
||||||
const getSecondMenuItems = () => {
|
const getSecondMenuItems = () => {
|
||||||
let items = [];
|
let items = [];
|
||||||
|
|
||||||
|
@ -118,7 +124,7 @@ export function SideMenuContent({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sideBarContext.permissions.includes("paymentPlan")) {
|
if (!showPaymentPlanInfoBanner) {
|
||||||
items.push({
|
items.push({
|
||||||
label: t("sideMenu.paymentPlan"),
|
label: t("sideMenu.paymentPlan"),
|
||||||
icon: <WalletOutlined />,
|
icon: <WalletOutlined />,
|
||||||
|
@ -162,6 +168,17 @@ export function SideMenuContent({
|
||||||
}
|
}
|
||||||
}, [location.pathname]);
|
}, [location.pathname]);
|
||||||
|
|
||||||
|
const calculateExpiry = () => {
|
||||||
|
const currentDate = new Date();
|
||||||
|
const expiryDate = new Date(sideBarContext.paymentPlanTrialEnd * 1000);
|
||||||
|
const diffTime = Math.abs(expiryDate - currentDate);
|
||||||
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||||
|
|
||||||
|
return diffDays;
|
||||||
|
};
|
||||||
|
|
||||||
|
const accountPlanExpiry = calculateExpiry();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -216,6 +233,36 @@ export function SideMenuContent({
|
||||||
<div>
|
<div>
|
||||||
<Divider style={{ margin: 0 }} />
|
<Divider style={{ margin: 0 }} />
|
||||||
|
|
||||||
|
{showPaymentPlanInfoBanner && (
|
||||||
|
<Card
|
||||||
|
style={{ backgroundColor: "#6878d6", margin: 8 }}
|
||||||
|
styles={{ body: { padding: 10 } }}
|
||||||
|
>
|
||||||
|
<Flex justify="center" align="center">
|
||||||
|
<Typography.Title
|
||||||
|
level={5}
|
||||||
|
style={{ color: "#fff", textAlign: "center" }}
|
||||||
|
>
|
||||||
|
{t("sideMenu.paymentPlanTrailingDaysLeft", {
|
||||||
|
daysLeft: accountPlanExpiry,
|
||||||
|
dayUnit:
|
||||||
|
accountPlanExpiry > 1
|
||||||
|
? t("common.unit.days")
|
||||||
|
: t("common.unit.day"),
|
||||||
|
})}
|
||||||
|
</Typography.Title>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
block
|
||||||
|
style={{ fontWeight: "bold", fontSize: 13 }}
|
||||||
|
onClick={() => navigate(Constants.ROUTE_PATHS.PAYMENT_PLAN)}
|
||||||
|
>
|
||||||
|
{t("sideMenu.paymentPlanUpgradeButton")}
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
<Menu
|
<Menu
|
||||||
selectable={true}
|
selectable={true}
|
||||||
selectedKeys={[selectedKeys]}
|
selectedKeys={[selectedKeys]}
|
||||||
|
|
|
@ -3,6 +3,12 @@ import { createContext, useContext, useState } from "react";
|
||||||
const preview = {
|
const preview = {
|
||||||
paymentPlan: "",
|
paymentPlan: "",
|
||||||
setPaymentPlan: () => {},
|
setPaymentPlan: () => {},
|
||||||
|
paymentPlanSettings: {
|
||||||
|
name: "",
|
||||||
|
maxEmployees: 0,
|
||||||
|
calendarMaxFutureBookingDays: 0,
|
||||||
|
},
|
||||||
|
setPaymentPlanSettings: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const AppContext = createContext(preview);
|
const AppContext = createContext(preview);
|
||||||
|
@ -11,12 +17,17 @@ export const useAppContext = () => useContext(AppContext);
|
||||||
|
|
||||||
export function AppProvider({ children, options }) {
|
export function AppProvider({ children, options }) {
|
||||||
const [paymentPlan, setPaymentPlan] = useState(options.paymentPlan);
|
const [paymentPlan, setPaymentPlan] = useState(options.paymentPlan);
|
||||||
|
const [paymentPlanSettings, setPaymentPlanSettings] = useState(
|
||||||
|
options.paymentPlanSettings
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider
|
<AppContext.Provider
|
||||||
value={{
|
value={{
|
||||||
paymentPlan,
|
paymentPlan,
|
||||||
setPaymentPlan,
|
setPaymentPlan,
|
||||||
|
paymentPlanSettings,
|
||||||
|
setPaymentPlanSettings,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -5,8 +5,12 @@ const preview = {
|
||||||
setUsername: () => {},
|
setUsername: () => {},
|
||||||
permissions: [],
|
permissions: [],
|
||||||
setPermissions: () => {},
|
setPermissions: () => {},
|
||||||
accountPlanExpiry: "",
|
paymentPlanStatus: "",
|
||||||
setAccountPlanExpiry: () => {},
|
setPaymentPlanStatus: () => {},
|
||||||
|
paymentPlanTrialEnd: "",
|
||||||
|
setPaymentPlanTrialEnd: () => {},
|
||||||
|
paymentPlanCanceledAt: "",
|
||||||
|
setPaymentPlanCanceledAt: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const SideBarContext = createContext(preview);
|
const SideBarContext = createContext(preview);
|
||||||
|
@ -16,8 +20,14 @@ export const useSideBarContext = () => useContext(SideBarContext);
|
||||||
export default function SideBarProvider({ children, options }) {
|
export default function SideBarProvider({ children, options }) {
|
||||||
const [username, setUsername] = useState(options.username);
|
const [username, setUsername] = useState(options.username);
|
||||||
const [permissions, setPermissions] = useState(options.permissions);
|
const [permissions, setPermissions] = useState(options.permissions);
|
||||||
const [accountPlanExpiry, setAccountPlanExpiry] = useState(
|
const [paymentPlanStatus, setPaymentPlanStatus] = useState(
|
||||||
options.accountPlanExpiry
|
options.paymentPlanStatus
|
||||||
|
);
|
||||||
|
const [paymentPlanTrialEnd, setPaymentPlanTrialEnd] = useState(
|
||||||
|
options.paymentPlanTrialEnd
|
||||||
|
);
|
||||||
|
const [paymentPlanCanceledAt, setPaymentPlanCanceledAt] = useState(
|
||||||
|
options.paymentPlanCanceledAt
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,8 +37,12 @@ export default function SideBarProvider({ children, options }) {
|
||||||
setUsername,
|
setUsername,
|
||||||
permissions,
|
permissions,
|
||||||
setPermissions,
|
setPermissions,
|
||||||
accountPlanExpiry,
|
paymentPlanStatus,
|
||||||
setAccountPlanExpiry,
|
setPaymentPlanStatus,
|
||||||
|
paymentPlanTrialEnd,
|
||||||
|
setPaymentPlanTrialEnd,
|
||||||
|
paymentPlanCanceledAt,
|
||||||
|
setPaymentPlanCanceledAt,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -34,6 +34,7 @@ import { MyRecaptcha, PrivacyPolicyCheckbox } from ".";
|
||||||
import MyAppLogo from "../../Components/MyAppLogo";
|
import MyAppLogo from "../../Components/MyAppLogo";
|
||||||
import { CheckOutlined } from "@ant-design/icons";
|
import { CheckOutlined } from "@ant-design/icons";
|
||||||
import { RequestState } from "../../Components/MyRequestStateItem";
|
import { RequestState } from "../../Components/MyRequestStateItem";
|
||||||
|
import { useAppContext } from "../../Contexts/AppContext";
|
||||||
/*
|
/*
|
||||||
const SignUpStep = {
|
const SignUpStep = {
|
||||||
SIGN_UP: 1,
|
SIGN_UP: 1,
|
||||||
|
@ -131,6 +132,10 @@ function AccountDetails({ t, form }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ChoosenProduct({ t, paymentPlan, extra }) {
|
export function ChoosenProduct({ t, paymentPlan, extra }) {
|
||||||
|
const appContext = useAppContext();
|
||||||
|
|
||||||
|
console.log(appContext.paymentPlanSettings);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t("authentication.signUp.choosenProduct.title")}
|
title={t("authentication.signUp.choosenProduct.title")}
|
||||||
|
@ -138,7 +143,7 @@ export function ChoosenProduct({ t, paymentPlan, extra }) {
|
||||||
extra={extra}
|
extra={extra}
|
||||||
>
|
>
|
||||||
<Typography.Title level={2}>
|
<Typography.Title level={2}>
|
||||||
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
|
{Constants.APP_NAME} - {appContext.paymentPlanSettings.name}
|
||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
@ -173,6 +178,7 @@ export function ChoosenProduct({ t, paymentPlan, extra }) {
|
||||||
|
|
||||||
function CostSummary({ notificationApi, paymentPlan, form }) {
|
function CostSummary({ notificationApi, paymentPlan, form }) {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
const appContext = useAppContext();
|
||||||
|
|
||||||
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
|
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
|
||||||
const recaptchaRef = useRef(null);
|
const recaptchaRef = useRef(null);
|
||||||
|
@ -290,7 +296,7 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
|
{Constants.APP_NAME} - {appContext.paymentPlanSettings.name}
|
||||||
</div>
|
</div>
|
||||||
<Flex justify="space-between">
|
<Flex justify="space-between">
|
||||||
<Typography.Text style={{ fontSize: 16 }}>
|
<Typography.Text style={{ fontSize: 16 }}>
|
||||||
|
|
|
@ -183,7 +183,7 @@ export default function StoreEmployees() {
|
||||||
setModalOptions={setAddEditEmployeeModalOptions}
|
setModalOptions={setAddEditEmployeeModalOptions}
|
||||||
fetchEmployees={fetchEmployees}
|
fetchEmployees={fetchEmployees}
|
||||||
disabled={
|
disabled={
|
||||||
Constants.PAYMENT_PLAN[appContext.paymentPlan].maxEmployees <=
|
appContext.paymentPlanSettings.maxEmployees <=
|
||||||
requestData.employees.length
|
requestData.employees.length
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
17
src/utils.js
17
src/utils.js
|
@ -110,23 +110,6 @@ export const Constants = {
|
||||||
INIT_PAYMENT: 5,
|
INIT_PAYMENT: 5,
|
||||||
},
|
},
|
||||||
SUPPORT_EMAIL: process.env.REACT_APP_SUPPORT_EMAIL,
|
SUPPORT_EMAIL: process.env.REACT_APP_SUPPORT_EMAIL,
|
||||||
PAYMENT_PLAN: [
|
|
||||||
{
|
|
||||||
name: "Demo",
|
|
||||||
maxEmployees: 5,
|
|
||||||
calendarMaxFutureBookingDays: 14,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Basic",
|
|
||||||
maxEmployees: 15,
|
|
||||||
calendarMaxFutureBookingDays: 60,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Premium",
|
|
||||||
maxEmployees: 50, // temporary
|
|
||||||
calendarMaxFutureBookingDays: 365, // temporary
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function isEmailValid(email) {
|
export function isEmailValid(email) {
|
||||||
|
|
Loading…
Reference in New Issue