mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 22:30:31 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
161d60393a | ||
|
|
79413fa85e | ||
|
|
58552c6c94 | ||
|
|
2072e35cfa | ||
|
|
1eaac9d691 | ||
|
|
a916e8a0cb |
@@ -246,8 +246,11 @@ module.exports = {
|
|||||||
apiKey: process.env.LOOPS_API_KEY,
|
apiKey: process.env.LOOPS_API_KEY,
|
||||||
},
|
},
|
||||||
|
|
||||||
oneClickDemoAccounts: parseBoolean(
|
/**
|
||||||
process.env.ONE_CLICK_DEMO_ACCOUNTS,
|
* One-click demo accounts.
|
||||||
false
|
*/
|
||||||
),
|
oneClickDemoAccounts: {
|
||||||
|
enable: parseBoolean(process.env.ONE_CLICK_DEMO_ACCOUNTS, false),
|
||||||
|
demoUrl: process.env.ONE_CLICK_DEMO_ACCOUNTS_URL || '',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ export interface IAuthSendedResetPassword {
|
|||||||
|
|
||||||
export interface IAuthGetMetaPOJO {
|
export interface IAuthGetMetaPOJO {
|
||||||
signupDisabled: boolean;
|
signupDisabled: boolean;
|
||||||
|
oneClickDemo: {
|
||||||
|
enable: boolean;
|
||||||
|
demoUrl: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAuthSignUpVerifingEventPayload {
|
export interface IAuthSignUpVerifingEventPayload {
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ export class GetAuthMeta {
|
|||||||
public async getAuthMeta(): Promise<IAuthGetMetaPOJO> {
|
public async getAuthMeta(): Promise<IAuthGetMetaPOJO> {
|
||||||
return {
|
return {
|
||||||
signupDisabled: config.signupRestrictions.disabled,
|
signupDisabled: config.signupRestrictions.disabled,
|
||||||
|
oneClickDemo: {
|
||||||
|
enable: config.oneClickDemoAccounts.enable,
|
||||||
|
demoUrl: config.oneClickDemoAccounts.demoUrl,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ export class LemonResumeSubscription {
|
|||||||
* @param {string} subscriptionSlug - Subscription slug by default main subscription.
|
* @param {string} subscriptionSlug - Subscription slug by default main subscription.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public async resumeSubscription(tenantId: number, subscriptionSlug: string = 'main') {
|
public async resumeSubscription(
|
||||||
|
tenantId: number,
|
||||||
|
subscriptionSlug: string = 'main'
|
||||||
|
) {
|
||||||
configureLemonSqueezy();
|
configureLemonSqueezy();
|
||||||
|
|
||||||
const subscription = await PlanSubscription.query().findOne({
|
const subscription = await PlanSubscription.query().findOne({
|
||||||
@@ -34,7 +37,7 @@ export class LemonResumeSubscription {
|
|||||||
cancelled: false,
|
cancelled: false,
|
||||||
});
|
});
|
||||||
if (returnedSub.error) {
|
if (returnedSub.error) {
|
||||||
throw new ServiceError(ٌٌُERRORS.SOMETHING_WENT_WRONG_WITH_LS);
|
throw new ServiceError(ERRORS.SOMETHING_WENT_WRONG_WITH_LS);
|
||||||
}
|
}
|
||||||
// Triggers `onSubscriptionResume` event.
|
// Triggers `onSubscriptionResume` event.
|
||||||
await this.eventPublisher.emitAsync(
|
await this.eventPublisher.emitAsync(
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { queryConfig } from '../hooks/query/base';
|
|||||||
import { EnsureUserEmailVerified } from './Guards/EnsureUserEmailVerified';
|
import { EnsureUserEmailVerified } from './Guards/EnsureUserEmailVerified';
|
||||||
import { EnsureAuthNotAuthenticated } from './Guards/EnsureAuthNotAuthenticated';
|
import { EnsureAuthNotAuthenticated } from './Guards/EnsureAuthNotAuthenticated';
|
||||||
import { EnsureUserEmailNotVerified } from './Guards/EnsureUserEmailNotVerified';
|
import { EnsureUserEmailNotVerified } from './Guards/EnsureUserEmailNotVerified';
|
||||||
import { EnsureOneClickDemoAccountEnabled } from '@/containers/OneClickDemo/EnsureOneClickDemoAccountEnabled';
|
|
||||||
|
|
||||||
const EmailConfirmation = LazyLoader({
|
const EmailConfirmation = LazyLoader({
|
||||||
loader: () => import('@/containers/Authentication/EmailConfirmation'),
|
loader: () => import('@/containers/Authentication/EmailConfirmation'),
|
||||||
@@ -31,6 +30,7 @@ const RegisterVerify = LazyLoader({
|
|||||||
const OneClickDemoPage = LazyLoader({
|
const OneClickDemoPage = LazyLoader({
|
||||||
loader: () => import('@/containers/OneClickDemo/OneClickDemoPage'),
|
loader: () => import('@/containers/OneClickDemo/OneClickDemoPage'),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App inner.
|
* App inner.
|
||||||
*/
|
*/
|
||||||
@@ -40,13 +40,7 @@ function AppInsider({ history }) {
|
|||||||
<DashboardThemeProvider>
|
<DashboardThemeProvider>
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path={'/one_click_demo'}>
|
<Route path={'/one_click_demo'} children={<OneClickDemoPage />} />
|
||||||
<EnsureOneClickDemoAccountEnabled>
|
|
||||||
<EnsureAuthNotAuthenticated>
|
|
||||||
<OneClickDemoPage />
|
|
||||||
</EnsureAuthNotAuthenticated>
|
|
||||||
</EnsureOneClickDemoAccountEnabled>
|
|
||||||
</Route>
|
|
||||||
<Route path={'/auth/register/verify'}>
|
<Route path={'/auth/register/verify'}>
|
||||||
<EnsureAuthenticated>
|
<EnsureAuthenticated>
|
||||||
<EnsureUserEmailNotVerified>
|
<EnsureUserEmailNotVerified>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useApplicationBoot } from '@/components';
|
import { useApplicationBoot } from '@/components';
|
||||||
|
import { useAuthMetadata } from '@/hooks/query/authentication';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private pages provider.
|
* Private pages provider.
|
||||||
@@ -9,7 +10,10 @@ export function PrivatePagesProvider({
|
|||||||
// #ownProps
|
// #ownProps
|
||||||
children,
|
children,
|
||||||
}) {
|
}) {
|
||||||
const { isLoading } = useApplicationBoot();
|
const { isLoading: isAppBootLoading } = useApplicationBoot();
|
||||||
|
const { isLoading: isAuthMetaLoading } = useAuthMetadata();
|
||||||
|
|
||||||
|
const isLoading = isAppBootLoading || isAuthMetaLoading;
|
||||||
|
|
||||||
return <React.Fragment>{!isLoading ? children : null}</React.Fragment>;
|
return <React.Fragment>{!isLoading ? children : null}</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
export const Config = {
|
|
||||||
oneClickDemo: {
|
|
||||||
enable: process.env.REACT_APP_ONE_CLICK_DEMO_ENABLE === 'true',
|
|
||||||
demoUrl: process.env.REACT_APP_DEMO_ACCOUNT_URL || '',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Redirect } from 'react-router-dom';
|
import { Redirect } from 'react-router-dom';
|
||||||
import { Config } from '@/config';
|
import { useOneClickDemoBoot } from './OneClickDemoBoot';
|
||||||
|
|
||||||
interface EnsureOneClickDemoAccountEnabledProps {
|
interface EnsureOneClickDemoAccountEnabledProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -11,9 +11,10 @@ export const EnsureOneClickDemoAccountEnabled = ({
|
|||||||
children,
|
children,
|
||||||
redirectTo = '/',
|
redirectTo = '/',
|
||||||
}: EnsureOneClickDemoAccountEnabledProps) => {
|
}: EnsureOneClickDemoAccountEnabledProps) => {
|
||||||
const enabeld = Config.oneClickDemo.enable || false;
|
const { authMeta } = useOneClickDemoBoot();
|
||||||
|
const enabled = authMeta?.meta?.one_click_demo?.enable || false;
|
||||||
|
|
||||||
if (!enabeld) {
|
if (!enabled) {
|
||||||
return <Redirect to={{ pathname: redirectTo }} />;
|
return <Redirect to={{ pathname: redirectTo }} />;
|
||||||
}
|
}
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import React, { createContext, useContext, ReactNode } from 'react';
|
||||||
|
import { useAuthMetadata } from '@/hooks/query/authentication';
|
||||||
|
|
||||||
|
interface OneClickDemoContextType {
|
||||||
|
authMeta: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OneClickDemoContext = createContext<OneClickDemoContextType>(
|
||||||
|
{} as OneClickDemoContextType,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const useOneClickDemoBoot = () => {
|
||||||
|
const context = useContext(OneClickDemoContext);
|
||||||
|
|
||||||
|
if (!context) {
|
||||||
|
throw new Error(
|
||||||
|
'useOneClickDemo must be used within a OneClickDemoProvider',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface OneClickDemoBootProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OneClickDemoBoot: React.FC<OneClickDemoBootProps> = ({
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const { isLoading: isAuthMetaLoading, data: authMeta } = useAuthMetadata();
|
||||||
|
|
||||||
|
const value = {
|
||||||
|
isAuthMetaLoading,
|
||||||
|
authMeta,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isAuthMetaLoading) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<OneClickDemoContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</OneClickDemoContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,97 +1,16 @@
|
|||||||
// @ts-nocheck
|
import { EnsureAuthNotAuthenticated } from '@/components/Guards/EnsureAuthNotAuthenticated';
|
||||||
import { Button, Intent, ProgressBar, Text } from '@blueprintjs/core';
|
import { EnsureOneClickDemoAccountEnabled } from './EnsureOneClickDemoAccountEnabled';
|
||||||
import { useEffect, useState } from 'react';
|
import { OneClickDemoBoot } from './OneClickDemoBoot';
|
||||||
import {
|
import { OneClickDemoPageContent } from './OneClickDemoPageContent';
|
||||||
useCreateOneClickDemo,
|
|
||||||
useOneClickDemoSignin,
|
|
||||||
} from '@/hooks/query/oneclick-demo';
|
|
||||||
import { Box, Icon, Stack } from '@/components';
|
|
||||||
import { useJob } from '@/hooks/query';
|
|
||||||
import style from './OneClickDemoPage.module.scss';
|
|
||||||
|
|
||||||
export default function OneClickDemoPage() {
|
export default function OneClickDemoPage() {
|
||||||
const {
|
|
||||||
mutateAsync: createOneClickDemo,
|
|
||||||
isLoading: isCreateOneClickLoading,
|
|
||||||
} = useCreateOneClickDemo();
|
|
||||||
const {
|
|
||||||
mutateAsync: oneClickDemoSignIn,
|
|
||||||
isLoading: isOneclickDemoSigningIn,
|
|
||||||
} = useOneClickDemoSignin();
|
|
||||||
|
|
||||||
// Job states.
|
|
||||||
const [demoId, setDemoId] = useState<string>('');
|
|
||||||
const [buildJobId, setBuildJobId] = useState<string>('');
|
|
||||||
const [isJobDone, setIsJobDone] = useState<boolean>(false);
|
|
||||||
|
|
||||||
const {
|
|
||||||
data: { running, completed },
|
|
||||||
} = useJob(buildJobId, {
|
|
||||||
refetchInterval: 2000,
|
|
||||||
enabled: !isJobDone && !!buildJobId,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (completed) {
|
|
||||||
setIsJobDone(true);
|
|
||||||
}
|
|
||||||
}, [completed, setIsJobDone]);
|
|
||||||
|
|
||||||
// One the job done request sign-in using the demo id.
|
|
||||||
useEffect(() => {
|
|
||||||
if (isJobDone) {
|
|
||||||
oneClickDemoSignIn({ demoId }).then((res) => {
|
|
||||||
debugger;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [isJobDone]);
|
|
||||||
|
|
||||||
const handleCreateAccountBtnClick = () => {
|
|
||||||
createOneClickDemo({})
|
|
||||||
.then(({ data: { data } }) => {
|
|
||||||
setBuildJobId(data?.build_job?.job_id);
|
|
||||||
setDemoId(data?.demo_id);
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
|
||||||
const isLoading = running || isOneclickDemoSigningIn;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box className={style.root}>
|
<EnsureAuthNotAuthenticated>
|
||||||
<Box className={style.inner}>
|
<OneClickDemoBoot>
|
||||||
<Stack align={'center'} spacing={40}>
|
<EnsureOneClickDemoAccountEnabled>
|
||||||
<Icon icon="bigcapital" height={37} width={228} />
|
<OneClickDemoPageContent />
|
||||||
|
</EnsureOneClickDemoAccountEnabled>
|
||||||
{isLoading && (
|
</OneClickDemoBoot>
|
||||||
<Stack align={'center'} spacing={15}>
|
</EnsureAuthNotAuthenticated>
|
||||||
<ProgressBar stripes value={null} className={style.progressBar} />
|
|
||||||
{isOneclickDemoSigningIn && (
|
|
||||||
<Text className={style.waitingText}>
|
|
||||||
It's signin-in to your demo account, Just a second!
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{running && (
|
|
||||||
<Text className={style.waitingText}>
|
|
||||||
We're preparing temporary environment for trial, It typically
|
|
||||||
take few seconds. Do not close or refresh the page.
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
|
|
||||||
{!isLoading && (
|
|
||||||
<Button
|
|
||||||
className={style.oneClickBtn}
|
|
||||||
intent={Intent.NONE}
|
|
||||||
onClick={handleCreateAccountBtnClick}
|
|
||||||
loading={isCreateOneClickLoading}
|
|
||||||
>
|
|
||||||
Create Demo Account
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import { Button, Intent, ProgressBar, Text } from '@blueprintjs/core';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
useCreateOneClickDemo,
|
||||||
|
useOneClickDemoSignin,
|
||||||
|
} from '@/hooks/query/oneclick-demo';
|
||||||
|
import { Box, Icon, Stack } from '@/components';
|
||||||
|
import { useJob } from '@/hooks/query';
|
||||||
|
import style from './OneClickDemoPage.module.scss';
|
||||||
|
|
||||||
|
export function OneClickDemoPageContent() {
|
||||||
|
const {
|
||||||
|
mutateAsync: createOneClickDemo,
|
||||||
|
isLoading: isCreateOneClickLoading,
|
||||||
|
} = useCreateOneClickDemo();
|
||||||
|
const {
|
||||||
|
mutateAsync: oneClickDemoSignIn,
|
||||||
|
isLoading: isOneclickDemoSigningIn,
|
||||||
|
} = useOneClickDemoSignin();
|
||||||
|
|
||||||
|
// Job states.
|
||||||
|
const [demoId, setDemoId] = useState<string>('');
|
||||||
|
const [buildJobId, setBuildJobId] = useState<string>('');
|
||||||
|
const [isJobDone, setIsJobDone] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { running, completed },
|
||||||
|
} = useJob(buildJobId, {
|
||||||
|
refetchInterval: 2000,
|
||||||
|
enabled: !isJobDone && !!buildJobId,
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (completed) {
|
||||||
|
setIsJobDone(true);
|
||||||
|
}
|
||||||
|
}, [completed, setIsJobDone]);
|
||||||
|
|
||||||
|
// One the job done request sign-in using the demo id.
|
||||||
|
useEffect(() => {
|
||||||
|
if (isJobDone) {
|
||||||
|
oneClickDemoSignIn({ demoId }).then((res) => {
|
||||||
|
debugger;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [isJobDone]);
|
||||||
|
|
||||||
|
const handleCreateAccountBtnClick = () => {
|
||||||
|
createOneClickDemo({})
|
||||||
|
.then(({ data: { data } }) => {
|
||||||
|
setBuildJobId(data?.build_job?.job_id);
|
||||||
|
setDemoId(data?.demo_id);
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
|
const isLoading = running || isOneclickDemoSigningIn;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box className={style.root}>
|
||||||
|
<Box className={style.inner}>
|
||||||
|
<Stack align={'center'} spacing={40}>
|
||||||
|
<Icon icon="bigcapital" height={37} width={228} />
|
||||||
|
|
||||||
|
{isLoading && (
|
||||||
|
<Stack align={'center'} spacing={15}>
|
||||||
|
<ProgressBar stripes value={null} className={style.progressBar} />
|
||||||
|
{isOneclickDemoSigningIn && (
|
||||||
|
<Text className={style.waitingText}>
|
||||||
|
It's signin-in to your demo account, Just a second!
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{running && (
|
||||||
|
<Text className={style.waitingText}>
|
||||||
|
We're preparing temporary environment for trial, It typically
|
||||||
|
take few seconds. Do not close or refresh the page.
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
{!isLoading && (
|
||||||
|
<Button
|
||||||
|
className={style.oneClickBtn}
|
||||||
|
intent={Intent.NONE}
|
||||||
|
onClick={handleCreateAccountBtnClick}
|
||||||
|
loading={isCreateOneClickLoading}
|
||||||
|
>
|
||||||
|
Create Demo Account
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import { Icon, For, FormattedMessage as T, Stack } from '@/components';
|
|||||||
import { getFooterLinks } from '@/constants/footerLinks';
|
import { getFooterLinks } from '@/constants/footerLinks';
|
||||||
import { useAuthActions } from '@/hooks/state';
|
import { useAuthActions } from '@/hooks/state';
|
||||||
import style from './SetupLeftSection.module.scss';
|
import style from './SetupLeftSection.module.scss';
|
||||||
import { Config } from '@/config';
|
import { useAuthMetadata } from '@/hooks/query';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Footer item link.
|
* Footer item link.
|
||||||
@@ -28,13 +28,16 @@ function SetupLeftSectionFooter() {
|
|||||||
// Retrieve the footer links.
|
// Retrieve the footer links.
|
||||||
const footerLinks = getFooterLinks();
|
const footerLinks = getFooterLinks();
|
||||||
|
|
||||||
|
const { data: authMeta } = useAuthMetadata();
|
||||||
|
const demoUrl = authMeta?.meta?.one_click_demo?.demo_url;
|
||||||
|
|
||||||
const handleDemoBtnClick = () => {
|
const handleDemoBtnClick = () => {
|
||||||
window.open(Config.oneClickDemo.demoUrl);
|
window.open(demoUrl);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'content__footer'}>
|
<div className={'content__footer'}>
|
||||||
{Config.oneClickDemo.demoUrl && (
|
{demoUrl && (
|
||||||
<Stack spacing={16}>
|
<Stack spacing={16}>
|
||||||
<Text className={style.demoButtonLabel}>Not Now?</Text>
|
<Text className={style.demoButtonLabel}>Not Now?</Text>
|
||||||
<button className={style.demoButton} onClick={handleDemoBtnClick}>
|
<button className={style.demoButton} onClick={handleDemoBtnClick}>
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
.container {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 1.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconText {
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 16px;
|
||||||
|
color: #00824d;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0; /* Remove the margin on the last item */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import styles from './SubscriptionPlansOfferChecks.module.scss';
|
||||||
|
|
||||||
|
export function SubscriptionPlansOfferChecks() {
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<span className={styles.iconText}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="18px"
|
||||||
|
width="18px"
|
||||||
|
viewBox="0 -960 960 960"
|
||||||
|
fill="rgb(0, 130, 77)"
|
||||||
|
className={styles.icon}
|
||||||
|
>
|
||||||
|
<path d="M378-225 133-470l66-66 179 180 382-382 66 65-448 448Z"></path>
|
||||||
|
</svg>
|
||||||
|
14-day free trial
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className={styles.iconText}>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
height="18px"
|
||||||
|
width="18px"
|
||||||
|
viewBox="0 -960 960 960"
|
||||||
|
fill="rgb(0, 130, 77)"
|
||||||
|
className={styles.icon}
|
||||||
|
>
|
||||||
|
<path d="M378-225 133-470l66-66 179 180 382-382 66 65-448 448Z"></path>
|
||||||
|
</svg>
|
||||||
|
24/7 online support
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ function SubscriptionPlansPeriodSwitcherRoot({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Group position={'center'} spacing={10} style={{ marginBottom: '1.2rem' }}>
|
<Group position={'center'} spacing={10} style={{ marginBottom: '1.6rem' }}>
|
||||||
<Text>Pay Monthly</Text>
|
<Text>Pay Monthly</Text>
|
||||||
<Switch
|
<Switch
|
||||||
large
|
large
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Callout } from '@blueprintjs/core';
|
import { Callout } from '@blueprintjs/core';
|
||||||
import { SubscriptionPlans } from './SubscriptionPlans';
|
import { SubscriptionPlans } from './SubscriptionPlans';
|
||||||
import { SubscriptionPlansPeriodSwitcher } from './SubscriptionPlansPeriodSwitcher';
|
import { SubscriptionPlansPeriodSwitcher } from './SubscriptionPlansPeriodSwitcher';
|
||||||
|
import { SubscriptionPlansOfferChecks } from './SubscriptionPlansOfferChecks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Billing plans.
|
* Billing plans.
|
||||||
@@ -14,6 +15,7 @@ export function SubscriptionPlansSection() {
|
|||||||
include applicable taxes.
|
include applicable taxes.
|
||||||
</Callout>
|
</Callout>
|
||||||
|
|
||||||
|
<SubscriptionPlansOfferChecks />
|
||||||
<SubscriptionPlansPeriodSwitcher />
|
<SubscriptionPlansPeriodSwitcher />
|
||||||
<SubscriptionPlans />
|
<SubscriptionPlans />
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export const useAuthResetPassword = (props) => {
|
|||||||
/**
|
/**
|
||||||
* Fetches the authentication page metadata.
|
* Fetches the authentication page metadata.
|
||||||
*/
|
*/
|
||||||
export const useAuthMetadata = (props) => {
|
export const useAuthMetadata = (props = {}) => {
|
||||||
return useRequestQuery(
|
return useRequestQuery(
|
||||||
[t.AUTH_METADATA_PAGE],
|
[t.AUTH_METADATA_PAGE],
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding-bottom: 40px;
|
padding-bottom: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__left-section {
|
&__left-section {
|
||||||
|
|||||||
Reference in New Issue
Block a user