mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(console): support open stripe payment management page from console (#4213)
This commit is contained in:
parent
46eafc9881
commit
d90d81688e
6 changed files with 38 additions and 9 deletions
|
@ -26,7 +26,7 @@
|
||||||
"@fontsource/roboto-mono": "^5.0.0",
|
"@fontsource/roboto-mono": "^5.0.0",
|
||||||
"@jest/types": "^29.5.0",
|
"@jest/types": "^29.5.0",
|
||||||
"@logto/app-insights": "workspace:^1.3.1",
|
"@logto/app-insights": "workspace:^1.3.1",
|
||||||
"@logto/cloud": "0.2.5-70aa370",
|
"@logto/cloud": "0.2.5-8065345",
|
||||||
"@logto/connector-kit": "workspace:^1.1.1",
|
"@logto/connector-kit": "workspace:^1.1.1",
|
||||||
"@logto/core-kit": "workspace:^2.0.1",
|
"@logto/core-kit": "workspace:^2.0.1",
|
||||||
"@logto/language-kit": "workspace:^1.0.0",
|
"@logto/language-kit": "workspace:^1.0.0",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
import { useContext } from 'react';
|
||||||
import { Trans, useTranslation } from 'react-i18next';
|
import { Trans, useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Tip from '@/assets/icons/tip.svg';
|
import Tip from '@/assets/icons/tip.svg';
|
||||||
|
import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||||
import Button from '@/ds-components/Button';
|
import Button from '@/ds-components/Button';
|
||||||
import DynamicT from '@/ds-components/DynamicT';
|
import DynamicT from '@/ds-components/DynamicT';
|
||||||
import IconButton from '@/ds-components/IconButton';
|
import IconButton from '@/ds-components/IconButton';
|
||||||
import TextLink from '@/ds-components/TextLink';
|
import TextLink from '@/ds-components/TextLink';
|
||||||
import { ToggleTip } from '@/ds-components/Tip';
|
import { ToggleTip } from '@/ds-components/Tip';
|
||||||
|
import useSubscribe from '@/hooks/use-subscribe';
|
||||||
|
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
|
@ -15,6 +18,9 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function BillInfo({ cost, isManagePaymentVisible }: Props) {
|
function BillInfo({ cost, isManagePaymentVisible }: Props) {
|
||||||
|
const { currentTenantId } = useContext(TenantsContext);
|
||||||
|
const { visitManagePaymentPage } = useSubscribe();
|
||||||
|
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -50,7 +56,7 @@ function BillInfo({ cost, isManagePaymentVisible }: Props) {
|
||||||
<Button
|
<Button
|
||||||
title="subscription.manage_payment"
|
title="subscription.manage_payment"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Todo @xiaoyijun Management payment
|
void visitManagePaymentPage(currentTenantId);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import FormField from '@/ds-components/FormField';
|
||||||
import InlineNotification from '@/ds-components/InlineNotification';
|
import InlineNotification from '@/ds-components/InlineNotification';
|
||||||
import ModalLayout from '@/ds-components/ModalLayout';
|
import ModalLayout from '@/ds-components/ModalLayout';
|
||||||
import useInvoices from '@/hooks/use-invoices';
|
import useInvoices from '@/hooks/use-invoices';
|
||||||
|
import useSubscribe from '@/hooks/use-subscribe';
|
||||||
import * as modalStyles from '@/scss/modal.module.scss';
|
import * as modalStyles from '@/scss/modal.module.scss';
|
||||||
import { getLatestUnpaidInvoice } from '@/utils/subscription';
|
import { getLatestUnpaidInvoice } from '@/utils/subscription';
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ function PaymentOverdueModal() {
|
||||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||||
const { currentTenant, currentTenantId } = useContext(TenantsContext);
|
const { currentTenant, currentTenantId } = useContext(TenantsContext);
|
||||||
const { data: invoices, error } = useInvoices(currentTenantId);
|
const { data: invoices, error } = useInvoices(currentTenantId);
|
||||||
|
const { visitManagePaymentPage } = useSubscribe();
|
||||||
const isLoadingInvoices = !invoices && !error;
|
const isLoadingInvoices = !invoices && !error;
|
||||||
|
|
||||||
const latestUnpaidInvoice = useMemo(() => {
|
const latestUnpaidInvoice = useMemo(() => {
|
||||||
|
@ -68,7 +70,7 @@ function PaymentOverdueModal() {
|
||||||
type="primary"
|
type="primary"
|
||||||
title="upsell.payment_overdue_modal.update_payment"
|
title="upsell.payment_overdue_modal.update_payment"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Todo: @xiaoyijun Update payment
|
void visitManagePaymentPage(currentTenantId);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { nanoid } from 'nanoid';
|
||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
|
import { toastResponseError, useCloudApi } from '@/cloud/hooks/use-cloud-api';
|
||||||
import { type CreateTenantData } from '@/components/CreateTenantModal/type';
|
import { type CreateTenantData } from '@/components/CreateTenantModal/type';
|
||||||
import { checkoutStateQueryKey, checkoutSuccessCallbackPath } from '@/consts/subscriptions';
|
import { checkoutStateQueryKey, checkoutSuccessCallbackPath } from '@/consts/subscriptions';
|
||||||
import { createLocalCheckoutSession } from '@/utils/checkout';
|
import { createLocalCheckoutSession } from '@/utils/checkout';
|
||||||
|
@ -72,9 +72,27 @@ const useSubscribe = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const visitManagePaymentPage = async (tenantId: string) => {
|
||||||
|
try {
|
||||||
|
const { redirectUri } = await cloudApi.post('/api/tenants/:tenantId/stripe-customer-portal', {
|
||||||
|
params: {
|
||||||
|
tenantId,
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
callbackUrl: window.location.href,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.location.assign(redirectUri);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
void toastResponseError(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
cancelSubscription,
|
cancelSubscription,
|
||||||
|
visitManagePaymentPage,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { TenantsContext } from '@/contexts/TenantsProvider';
|
||||||
import DynamicT from '@/ds-components/DynamicT';
|
import DynamicT from '@/ds-components/DynamicT';
|
||||||
import InlineNotification from '@/ds-components/InlineNotification';
|
import InlineNotification from '@/ds-components/InlineNotification';
|
||||||
import useInvoices from '@/hooks/use-invoices';
|
import useInvoices from '@/hooks/use-invoices';
|
||||||
|
import useSubscribe from '@/hooks/use-subscribe';
|
||||||
import { getLatestUnpaidInvoice } from '@/utils/subscription';
|
import { getLatestUnpaidInvoice } from '@/utils/subscription';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -13,6 +14,7 @@ type Props = {
|
||||||
|
|
||||||
function PaymentOverdueNotification({ className }: Props) {
|
function PaymentOverdueNotification({ className }: Props) {
|
||||||
const { currentTenantId } = useContext(TenantsContext);
|
const { currentTenantId } = useContext(TenantsContext);
|
||||||
|
const { visitManagePaymentPage } = useSubscribe();
|
||||||
const { data: invoices, error } = useInvoices(currentTenantId);
|
const { data: invoices, error } = useInvoices(currentTenantId);
|
||||||
const isLoadingInvoices = !invoices && !error;
|
const isLoadingInvoices = !invoices && !error;
|
||||||
const latestUnpaidInvoice = useMemo(
|
const latestUnpaidInvoice = useMemo(
|
||||||
|
@ -30,7 +32,7 @@ function PaymentOverdueNotification({ className }: Props) {
|
||||||
action="subscription.update_payment"
|
action="subscription.update_payment"
|
||||||
className={className}
|
className={className}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Todo @xiaoyijun manage payment
|
void visitManagePaymentPage(currentTenantId);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DynamicT
|
<DynamicT
|
||||||
|
|
|
@ -2755,8 +2755,8 @@ importers:
|
||||||
specifier: workspace:^1.3.1
|
specifier: workspace:^1.3.1
|
||||||
version: link:../app-insights
|
version: link:../app-insights
|
||||||
'@logto/cloud':
|
'@logto/cloud':
|
||||||
specifier: 0.2.5-70aa370
|
specifier: 0.2.5-8065345
|
||||||
version: 0.2.5-70aa370(zod@3.20.2)
|
version: 0.2.5-8065345(zod@3.20.2)
|
||||||
'@logto/connector-kit':
|
'@logto/connector-kit':
|
||||||
specifier: workspace:^1.1.1
|
specifier: workspace:^1.1.1
|
||||||
version: link:../toolkit/connector-kit
|
version: link:../toolkit/connector-kit
|
||||||
|
@ -7220,8 +7220,8 @@ packages:
|
||||||
- zod
|
- zod
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@logto/cloud@0.2.5-70aa370(zod@3.20.2):
|
/@logto/cloud@0.2.5-8065345(zod@3.20.2):
|
||||||
resolution: {integrity: sha512-V5fIsbotJ8+L6Q+R9PnLjspvuccDKpukpLz/uHRUv4SYDo8U5MAcC680T2TGiROtMjWqnb0vd6WHuqXZ9XWTcw==}
|
resolution: {integrity: sha512-qZWtGd2InkSddNPt3lKO0Ti/UZtQvzul5R7uJbnZgl0xiIpoMYEiHVI9gXQ8O+V47qtPpkS3ykTb2zj4K4Sk+w==}
|
||||||
engines: {node: ^18.12.0}
|
engines: {node: ^18.12.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@silverhand/essentials': 2.7.0
|
'@silverhand/essentials': 2.7.0
|
||||||
|
@ -16235,6 +16235,7 @@ packages:
|
||||||
/node-gyp-build-optional-packages@5.0.7:
|
/node-gyp-build-optional-packages@5.0.7:
|
||||||
resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
|
resolution: {integrity: sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
requiresBuild: true
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue