payment plan settings

master
alex 2024-02-24 07:33:05 +01:00
parent cf0b173ab7
commit dac70b358a
10 changed files with 102 additions and 38 deletions

View File

@ -126,7 +126,9 @@
},
"support": "Unterstützung",
"feedback": "Feedback",
"paymentPlan": "Zahlungsplan"
"paymentPlan": "Zahlungsplan",
"paymentPlanTrailingDaysLeft": "{{daysLeft}} {{dayUnit}} verbleibend",
"paymentPlanUpgradeButton": "Jetzt upgraden"
},
"employees": {
"pageTitle": "Mitarbeiter",
@ -184,7 +186,6 @@
"choosenProduct": {
"title": "Ausgewähltes Produkt",
"products": [
{},
{
"price": "9,99 € / Monat",
"featuresCount": 9,

View File

@ -20,8 +20,8 @@
"hour": "hour",
"minutes": "minutes",
"minute": "minute",
"days": "Days",
"day": "Day",
"days": "days",
"day": "day",
"separator": "and"
},
"failed": "Failed",
@ -126,7 +126,9 @@
},
"support": "Support",
"feedback": "Feedback",
"paymentPlan": "Payment plan"
"paymentPlan": "Payment plan",
"paymentPlanTrailingDaysLeft": "{{daysLeft}} {{dayUnit}} left",
"paymentPlanUpgradeButton": "Upgrade now"
},
"employees": {
"pageTitle": "Employees",
@ -184,7 +186,6 @@
"choosenProduct": {
"title": "Choosen product",
"products": [
{},
{
"price": "9,99 € / month",
"featuresCount": 9,

View File

@ -132,6 +132,9 @@ export function App() {
options={{
username: appUserData.user.username,
permissions: appUserData.permissions,
paymentPlanStatus: appUserData.user.payment_plan_status,
paymentPlanTrialEnd: appUserData.user.payment_plan_trial_end,
paymentPlanCanceledAt: appUserData.user.payment_plan_canceled_at,
}}
>
<UserProfileProvider>
@ -139,6 +142,7 @@ export function App() {
<AppProvider
options={{
paymentPlan: appUserData.user.payment_plan,
paymentPlanSettings: appUserData.paymentPlanSettings,
}}
>
<StoresProvider options={{ stores: appUserData.stores }}>

View File

@ -134,10 +134,7 @@ export function MyCalendarMaxFutureBookingDaysFormInput({
<MyFormInput
formItemName={formItemName}
minLength={Constants.GLOBALS.MIN_CALENDAR_FUTURE_BOOKING_DAYS}
maxLength={
Constants.PAYMENT_PLAN[appContext.paymentPlan]
.calendarMaxFutureBookingDays
}
maxLength={appContext.paymentPlanSettings.maxEmployees}
label={t("common.calendarMaxFutureBookingDays")}
ruleMessageValueRequired={t(
"common.inputRules.calendarMaxFutureBookingDaysRequired"

View File

@ -10,7 +10,7 @@ import {
UserOutlined,
WalletOutlined,
} from "@ant-design/icons";
import { Divider, Menu } from "antd";
import { Button, Card, Divider, Flex, Menu, Typography } from "antd";
import { useEffect, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { BreakpointLgWidth, Constants, isDevelopmentEnv } from "../../utils";
@ -100,6 +100,12 @@ export function SideMenuContent({
return items;
};
const showPaymentPlanInfoBanner =
sideBarContext.permissions.includes("paymentPlan") &&
sideBarContext.paymentPlanStatus === "trialing" &&
sideBarContext.paymentPlanTrialEnd !== null &&
sideBarContext.paymentPlanCanceledAt !== null;
const getSecondMenuItems = () => {
let items = [];
@ -118,7 +124,7 @@ export function SideMenuContent({
);
}
if (sideBarContext.permissions.includes("paymentPlan")) {
if (!showPaymentPlanInfoBanner) {
items.push({
label: t("sideMenu.paymentPlan"),
icon: <WalletOutlined />,
@ -162,6 +168,17 @@ export function SideMenuContent({
}
}, [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 (
<div
style={{
@ -216,6 +233,36 @@ export function SideMenuContent({
<div>
<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
selectable={true}
selectedKeys={[selectedKeys]}

View File

@ -3,6 +3,12 @@ import { createContext, useContext, useState } from "react";
const preview = {
paymentPlan: "",
setPaymentPlan: () => {},
paymentPlanSettings: {
name: "",
maxEmployees: 0,
calendarMaxFutureBookingDays: 0,
},
setPaymentPlanSettings: () => {},
};
const AppContext = createContext(preview);
@ -11,12 +17,17 @@ export const useAppContext = () => useContext(AppContext);
export function AppProvider({ children, options }) {
const [paymentPlan, setPaymentPlan] = useState(options.paymentPlan);
const [paymentPlanSettings, setPaymentPlanSettings] = useState(
options.paymentPlanSettings
);
return (
<AppContext.Provider
value={{
paymentPlan,
setPaymentPlan,
paymentPlanSettings,
setPaymentPlanSettings,
}}
>
{children}

View File

@ -5,8 +5,12 @@ const preview = {
setUsername: () => {},
permissions: [],
setPermissions: () => {},
accountPlanExpiry: "",
setAccountPlanExpiry: () => {},
paymentPlanStatus: "",
setPaymentPlanStatus: () => {},
paymentPlanTrialEnd: "",
setPaymentPlanTrialEnd: () => {},
paymentPlanCanceledAt: "",
setPaymentPlanCanceledAt: () => {},
};
const SideBarContext = createContext(preview);
@ -16,8 +20,14 @@ export const useSideBarContext = () => useContext(SideBarContext);
export default function SideBarProvider({ children, options }) {
const [username, setUsername] = useState(options.username);
const [permissions, setPermissions] = useState(options.permissions);
const [accountPlanExpiry, setAccountPlanExpiry] = useState(
options.accountPlanExpiry
const [paymentPlanStatus, setPaymentPlanStatus] = useState(
options.paymentPlanStatus
);
const [paymentPlanTrialEnd, setPaymentPlanTrialEnd] = useState(
options.paymentPlanTrialEnd
);
const [paymentPlanCanceledAt, setPaymentPlanCanceledAt] = useState(
options.paymentPlanCanceledAt
);
return (
@ -27,8 +37,12 @@ export default function SideBarProvider({ children, options }) {
setUsername,
permissions,
setPermissions,
accountPlanExpiry,
setAccountPlanExpiry,
paymentPlanStatus,
setPaymentPlanStatus,
paymentPlanTrialEnd,
setPaymentPlanTrialEnd,
paymentPlanCanceledAt,
setPaymentPlanCanceledAt,
}}
>
{children}

View File

@ -34,6 +34,7 @@ import { MyRecaptcha, PrivacyPolicyCheckbox } from ".";
import MyAppLogo from "../../Components/MyAppLogo";
import { CheckOutlined } from "@ant-design/icons";
import { RequestState } from "../../Components/MyRequestStateItem";
import { useAppContext } from "../../Contexts/AppContext";
/*
const SignUpStep = {
SIGN_UP: 1,
@ -131,6 +132,10 @@ function AccountDetails({ t, form }) {
}
export function ChoosenProduct({ t, paymentPlan, extra }) {
const appContext = useAppContext();
console.log(appContext.paymentPlanSettings);
return (
<Card
title={t("authentication.signUp.choosenProduct.title")}
@ -138,7 +143,7 @@ export function ChoosenProduct({ t, paymentPlan, extra }) {
extra={extra}
>
<Typography.Title level={2}>
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
{Constants.APP_NAME} - {appContext.paymentPlanSettings.name}
</Typography.Title>
<Divider />
@ -173,6 +178,7 @@ export function ChoosenProduct({ t, paymentPlan, extra }) {
function CostSummary({ notificationApi, paymentPlan, form }) {
const { t, i18n } = useTranslation();
const appContext = useAppContext();
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
const recaptchaRef = useRef(null);
@ -290,7 +296,7 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
marginBottom: 12,
}}
>
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
{Constants.APP_NAME} - {appContext.paymentPlanSettings.name}
</div>
<Flex justify="space-between">
<Typography.Text style={{ fontSize: 16 }}>

View File

@ -183,7 +183,7 @@ export default function StoreEmployees() {
setModalOptions={setAddEditEmployeeModalOptions}
fetchEmployees={fetchEmployees}
disabled={
Constants.PAYMENT_PLAN[appContext.paymentPlan].maxEmployees <=
appContext.paymentPlanSettings.maxEmployees <=
requestData.employees.length
}
/>

View File

@ -110,23 +110,6 @@ export const Constants = {
INIT_PAYMENT: 5,
},
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) {