feat: add idempotent request support for payment apis (#4753)

This commit is contained in:
DarkSky
2023-10-30 05:54:09 +00:00
committed by GitHub
parent 3798293d3e
commit de9e7f97a4
12 changed files with 244 additions and 138 deletions
@@ -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
@@ -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)
}
+11 -8
View File
@@ -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
+4 -2
View File
@@ -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 = {