mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-22 03:33:06 +08:00
feat: add idempotent request support for payment apis (#4753)
This commit is contained in:
+25
-12
@@ -21,6 +21,7 @@ import { useMutation, useQuery } from '@affine/workspace/affine/gql';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||
import { Button, IconButton } from '@toeverything/components/button';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Suspense, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { openSettingModalAtom } from '../../../../../atoms';
|
||||
@@ -89,13 +90,19 @@ const SubscriptionSettings = () => {
|
||||
});
|
||||
const [openCancelModal, setOpenCancelModal] = useState(false);
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
trigger(null, {
|
||||
onSuccess: data => {
|
||||
mutateSubscription(data.cancelSubscription);
|
||||
},
|
||||
});
|
||||
}, [trigger, mutateSubscription]);
|
||||
trigger(
|
||||
{ idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
mutateSubscription(data.cancelSubscription);
|
||||
},
|
||||
}
|
||||
);
|
||||
}, [trigger, idempotencyKey, mutateSubscription]);
|
||||
|
||||
const { data: pricesQueryResult } = useQuery({
|
||||
query: pricesQuery,
|
||||
@@ -288,13 +295,19 @@ const ResumeSubscription = ({
|
||||
mutation: resumeSubscriptionMutation,
|
||||
});
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const resume = useCallback(() => {
|
||||
trigger(null, {
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.resumeSubscription);
|
||||
},
|
||||
});
|
||||
}, [trigger, onSubscriptionUpdate]);
|
||||
trigger(
|
||||
{ idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.resumeSubscription);
|
||||
},
|
||||
}
|
||||
);
|
||||
}, [trigger, idempotencyKey, onSubscriptionUpdate]);
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
+36
-16
@@ -18,10 +18,12 @@ import { Button } from '@toeverything/components/button';
|
||||
import { Tooltip } from '@toeverything/components/tooltip';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
import {
|
||||
type PropsWithChildren,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
@@ -303,13 +305,19 @@ const Downgrade = ({
|
||||
mutation: cancelSubscriptionMutation,
|
||||
});
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const downgrade = useCallback(() => {
|
||||
trigger(null, {
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.cancelSubscription);
|
||||
},
|
||||
});
|
||||
}, [trigger, onSubscriptionUpdate]);
|
||||
trigger(
|
||||
{ idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.cancelSubscription);
|
||||
},
|
||||
}
|
||||
);
|
||||
}, [trigger, idempotencyKey, onSubscriptionUpdate]);
|
||||
|
||||
const tooltipContent = disabled
|
||||
? t['com.affine.payment.downgraded-tooltip']()
|
||||
@@ -365,6 +373,9 @@ const Upgrade = ({
|
||||
|
||||
const newTabRef = useRef<Window | null>(null);
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
newTabRef.current = null;
|
||||
onSubscriptionUpdate();
|
||||
@@ -381,7 +392,7 @@ const Upgrade = ({
|
||||
newTabRef.current.focus();
|
||||
} else {
|
||||
trigger(
|
||||
{ recurring },
|
||||
{ recurring, idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
// FIXME: safari prevents from opening new tab by window api
|
||||
@@ -401,7 +412,7 @@ const Upgrade = ({
|
||||
}
|
||||
);
|
||||
}
|
||||
}, [trigger, recurring, onClose, openPaymentDisableModal]);
|
||||
}, [openPaymentDisableModal, trigger, recurring, idempotencyKey, onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@@ -446,16 +457,19 @@ const ChangeRecurring = ({
|
||||
mutation: updateSubscriptionMutation,
|
||||
});
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const change = useCallback(() => {
|
||||
trigger(
|
||||
{ recurring: to },
|
||||
{ recurring: to, idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.updateSubscriptionRecurring);
|
||||
},
|
||||
}
|
||||
);
|
||||
}, [trigger, onSubscriptionUpdate, to]);
|
||||
}, [trigger, to, idempotencyKey, onSubscriptionUpdate]);
|
||||
|
||||
const changeCurringContent = (
|
||||
<Trans values={{ from, to, due }} className={styles.downgradeContent}>
|
||||
@@ -523,13 +537,19 @@ const ResumeAction = ({
|
||||
mutation: resumeSubscriptionMutation,
|
||||
});
|
||||
|
||||
// allow replay request on network error until component unmount
|
||||
const idempotencyKey = useMemo(() => nanoid(), []);
|
||||
|
||||
const resume = useCallback(() => {
|
||||
trigger(null, {
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.resumeSubscription);
|
||||
},
|
||||
});
|
||||
}, [trigger, onSubscriptionUpdate]);
|
||||
trigger(
|
||||
{ idempotencyKey },
|
||||
{
|
||||
onSuccess: data => {
|
||||
onSubscriptionUpdate(data.resumeSubscription);
|
||||
},
|
||||
}
|
||||
);
|
||||
}, [trigger, idempotencyKey, onSubscriptionUpdate]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mutation cancelSubscription {
|
||||
cancelSubscription {
|
||||
mutation cancelSubscription($idempotencyKey: String!) {
|
||||
cancelSubscription(idempotencyKey: $idempotencyKey) {
|
||||
id
|
||||
status
|
||||
nextBillAt
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
mutation checkout($recurring: SubscriptionRecurring!) {
|
||||
checkout(recurring: $recurring)
|
||||
mutation checkout(
|
||||
$recurring: SubscriptionRecurring!
|
||||
$idempotencyKey: String!
|
||||
) {
|
||||
checkout(recurring: $recurring, idempotencyKey: $idempotencyKey)
|
||||
}
|
||||
|
||||
@@ -85,8 +85,8 @@ export const cancelSubscriptionMutation = {
|
||||
definitionName: 'cancelSubscription',
|
||||
containsFile: false,
|
||||
query: `
|
||||
mutation cancelSubscription {
|
||||
cancelSubscription {
|
||||
mutation cancelSubscription($idempotencyKey: String!) {
|
||||
cancelSubscription(idempotencyKey: $idempotencyKey) {
|
||||
id
|
||||
status
|
||||
nextBillAt
|
||||
@@ -133,8 +133,8 @@ export const checkoutMutation = {
|
||||
definitionName: 'checkout',
|
||||
containsFile: false,
|
||||
query: `
|
||||
mutation checkout($recurring: SubscriptionRecurring!) {
|
||||
checkout(recurring: $recurring)
|
||||
mutation checkout($recurring: SubscriptionRecurring!, $idempotencyKey: String!) {
|
||||
checkout(recurring: $recurring, idempotencyKey: $idempotencyKey)
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -434,8 +434,8 @@ export const resumeSubscriptionMutation = {
|
||||
definitionName: 'resumeSubscription',
|
||||
containsFile: false,
|
||||
query: `
|
||||
mutation resumeSubscription {
|
||||
resumeSubscription {
|
||||
mutation resumeSubscription($idempotencyKey: String!) {
|
||||
resumeSubscription(idempotencyKey: $idempotencyKey) {
|
||||
id
|
||||
status
|
||||
nextBillAt
|
||||
@@ -593,8 +593,11 @@ export const updateSubscriptionMutation = {
|
||||
definitionName: 'updateSubscriptionRecurring',
|
||||
containsFile: false,
|
||||
query: `
|
||||
mutation updateSubscription($recurring: SubscriptionRecurring!) {
|
||||
updateSubscriptionRecurring(recurring: $recurring) {
|
||||
mutation updateSubscription($recurring: SubscriptionRecurring!, $idempotencyKey: String!) {
|
||||
updateSubscriptionRecurring(
|
||||
recurring: $recurring
|
||||
idempotencyKey: $idempotencyKey
|
||||
) {
|
||||
id
|
||||
plan
|
||||
recurring
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mutation resumeSubscription {
|
||||
resumeSubscription {
|
||||
mutation resumeSubscription($idempotencyKey: String!) {
|
||||
resumeSubscription(idempotencyKey: $idempotencyKey) {
|
||||
id
|
||||
status
|
||||
nextBillAt
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
mutation updateSubscription($recurring: SubscriptionRecurring!) {
|
||||
updateSubscriptionRecurring(recurring: $recurring) {
|
||||
mutation updateSubscription(
|
||||
$recurring: SubscriptionRecurring!
|
||||
$idempotencyKey: String!
|
||||
) {
|
||||
updateSubscriptionRecurring(
|
||||
recurring: $recurring
|
||||
idempotencyKey: $idempotencyKey
|
||||
) {
|
||||
id
|
||||
plan
|
||||
recurring
|
||||
|
||||
@@ -131,7 +131,7 @@ export type AllBlobSizesQuery = {
|
||||
};
|
||||
|
||||
export type CancelSubscriptionMutationVariables = Exact<{
|
||||
[key: string]: never;
|
||||
idempotencyKey: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type CancelSubscriptionMutation = {
|
||||
@@ -178,6 +178,7 @@ export type ChangePasswordMutation = {
|
||||
|
||||
export type CheckoutMutationVariables = Exact<{
|
||||
recurring: SubscriptionRecurring;
|
||||
idempotencyKey: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type CheckoutMutation = { __typename?: 'Mutation'; checkout: string };
|
||||
@@ -416,7 +417,7 @@ export type RemoveAvatarMutation = {
|
||||
};
|
||||
|
||||
export type ResumeSubscriptionMutationVariables = Exact<{
|
||||
[key: string]: never;
|
||||
idempotencyKey: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type ResumeSubscriptionMutation = {
|
||||
@@ -558,6 +559,7 @@ export type SubscriptionQuery = {
|
||||
|
||||
export type UpdateSubscriptionMutationVariables = Exact<{
|
||||
recurring: SubscriptionRecurring;
|
||||
idempotencyKey: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
export type UpdateSubscriptionMutation = {
|
||||
|
||||
Reference in New Issue
Block a user