feat(tip): support dynamic gift products
This commit is contained in:
@@ -1,50 +1,76 @@
|
||||
import type { DoneActorEvent, ErrorActorEvent } from "xstate";
|
||||
|
||||
import type { PaymentPlansResponse } from "@/data/schemas/payment";
|
||||
import type {
|
||||
GiftProductsResponse,
|
||||
PaymentPlansResponse,
|
||||
} from "@/data/schemas/payment";
|
||||
|
||||
import {
|
||||
consumeFirstRechargeState,
|
||||
hydrateGiftProductsState,
|
||||
hydratePlansResponseState,
|
||||
refreshPlansResponseState,
|
||||
selectPlanState,
|
||||
} from "../helper/catalog";
|
||||
import {
|
||||
resetOrderState,
|
||||
toPaymentErrorMessage,
|
||||
} from "../helper/order";
|
||||
} from "../helper";
|
||||
import { resetOrderState, toPaymentErrorMessage } from "../helper/order";
|
||||
import type { PaymentEvent } from "../payment-events";
|
||||
import type { PaymentState } from "../payment-state";
|
||||
import {
|
||||
basePaymentMachineSetup,
|
||||
createPaymentActorActionSetup,
|
||||
} from "./setup";
|
||||
|
||||
function initializeCatalogState(
|
||||
context: PaymentState,
|
||||
event: Extract<PaymentEvent, { type: "PaymentInit" }>,
|
||||
): Partial<PaymentState> {
|
||||
const planCatalog = event.catalog ?? context.planCatalog;
|
||||
const giftCharacterId =
|
||||
planCatalog === "tip"
|
||||
? (event.characterId ?? context.giftCharacterId)
|
||||
: null;
|
||||
const catalogChanged = planCatalog !== context.planCatalog;
|
||||
const characterChanged = giftCharacterId !== context.giftCharacterId;
|
||||
const selectionChanged =
|
||||
planCatalog === "tip" &&
|
||||
((event.category ?? null) !== context.selectedGiftCategory ||
|
||||
(event.planId ?? null) !== (context.selectedPlanId || null));
|
||||
|
||||
return {
|
||||
planCatalog,
|
||||
...(event.payChannel ? { payChannel: event.payChannel } : {}),
|
||||
giftCharacterId,
|
||||
requestedGiftCategory:
|
||||
planCatalog === "tip" ? (event.category ?? null) : null,
|
||||
requestedGiftPlanId:
|
||||
planCatalog === "tip" ? (event.planId ?? null) : null,
|
||||
...(catalogChanged || characterChanged || selectionChanged
|
||||
? {
|
||||
...resetOrderState(),
|
||||
plans: [],
|
||||
giftCategories: [],
|
||||
giftProducts: [],
|
||||
selectedGiftCategory: null,
|
||||
selectedPlanId: "",
|
||||
isFirstRecharge: false,
|
||||
autoRenew: planCatalog !== "tip",
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
const initializeCatalogAction = basePaymentMachineSetup.assign(
|
||||
({ context, event }) => {
|
||||
if (event.type !== "PaymentInit") return {};
|
||||
return {
|
||||
planCatalog: event.catalog ?? context.planCatalog,
|
||||
...(event.payChannel ? { payChannel: event.payChannel } : {}),
|
||||
};
|
||||
},
|
||||
({ context, event }) =>
|
||||
event.type === "PaymentInit"
|
||||
? initializeCatalogState(context, event)
|
||||
: {},
|
||||
);
|
||||
|
||||
const refreshCatalogAction = basePaymentMachineSetup.assign(
|
||||
({ context, event }) => {
|
||||
if (event.type !== "PaymentInit") return {};
|
||||
const planCatalog = event.catalog ?? context.planCatalog;
|
||||
const catalogChanged = planCatalog !== context.planCatalog;
|
||||
return {
|
||||
planCatalog,
|
||||
...(event.payChannel ? { payChannel: event.payChannel } : {}),
|
||||
...(catalogChanged
|
||||
? {
|
||||
plans: [],
|
||||
selectedPlanId: "",
|
||||
isFirstRecharge: false,
|
||||
autoRenew: planCatalog !== "tip",
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
},
|
||||
({ context, event }) =>
|
||||
event.type === "PaymentInit"
|
||||
? initializeCatalogState(context, event)
|
||||
: {},
|
||||
);
|
||||
|
||||
const selectPlanAction = basePaymentMachineSetup.assign(
|
||||
@@ -105,6 +131,12 @@ export const catalogMachineSetup = basePaymentMachineSetup.extend({
|
||||
resetOrder: resetOrderAction,
|
||||
consumeFirstRecharge: consumeFirstRechargeAction,
|
||||
},
|
||||
guards: {
|
||||
isTipInit: ({ context, event }) =>
|
||||
event.type === "PaymentInit" &&
|
||||
(event.catalog ?? context.planCatalog) === "tip",
|
||||
isTipCatalog: ({ context }) => context.planCatalog === "tip",
|
||||
},
|
||||
});
|
||||
|
||||
const cachedPlansDoneSetup =
|
||||
@@ -113,6 +145,8 @@ const cachedPlansDoneSetup =
|
||||
>();
|
||||
const plansDoneSetup =
|
||||
createPaymentActorActionSetup<DoneActorEvent<PaymentPlansResponse>>();
|
||||
const giftProductsDoneSetup =
|
||||
createPaymentActorActionSetup<DoneActorEvent<GiftProductsResponse>>();
|
||||
const plansErrorSetup = createPaymentActorActionSetup<ErrorActorEvent>();
|
||||
|
||||
const hydrateCachedPlansAction = cachedPlansDoneSetup.assign(
|
||||
@@ -130,16 +164,42 @@ const refreshPlansAction = plansDoneSetup.assign(({ context, event }) =>
|
||||
refreshPlansResponseState(event.output, context.selectedPlanId),
|
||||
);
|
||||
|
||||
const hydrateGiftProductsAction = giftProductsDoneSetup.assign(
|
||||
({ context, event }) =>
|
||||
hydrateGiftProductsState(
|
||||
event.output,
|
||||
context.giftCharacterId ?? "",
|
||||
context.requestedGiftCategory ?? context.selectedGiftCategory,
|
||||
context.requestedGiftPlanId ?? context.selectedPlanId,
|
||||
),
|
||||
);
|
||||
|
||||
const applyPlansErrorAction = plansErrorSetup.assign(({ event }) => ({
|
||||
errorMessage: toPaymentErrorMessage(event.error),
|
||||
}));
|
||||
|
||||
const applyGiftProductsErrorAction = plansErrorSetup.assign(({ event }) => ({
|
||||
plans: [],
|
||||
giftCategories: [],
|
||||
giftProducts: [],
|
||||
selectedGiftCategory: null,
|
||||
selectedPlanId: "",
|
||||
errorMessage: toPaymentErrorMessage(event.error),
|
||||
}));
|
||||
|
||||
export const idleState = catalogMachineSetup.createStateConfig({
|
||||
on: {
|
||||
PaymentInit: {
|
||||
target: "loadingCachedPlans",
|
||||
actions: "initializeCatalog",
|
||||
},
|
||||
PaymentInit: [
|
||||
{
|
||||
guard: "isTipInit",
|
||||
target: "loadingGiftProducts",
|
||||
actions: "initializeCatalog",
|
||||
},
|
||||
{
|
||||
target: "loadingCachedPlans",
|
||||
actions: "initializeCatalog",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -190,12 +250,44 @@ export const refreshingPlansState = catalogMachineSetup.createStateConfig({
|
||||
},
|
||||
});
|
||||
|
||||
export const loadingGiftProductsState =
|
||||
catalogMachineSetup.createStateConfig({
|
||||
invoke: {
|
||||
src: "loadGiftProducts",
|
||||
input: ({ context }) => ({
|
||||
characterId: context.giftCharacterId ?? "",
|
||||
}),
|
||||
onDone: {
|
||||
target: "ready",
|
||||
actions: hydrateGiftProductsAction,
|
||||
},
|
||||
onError: {
|
||||
target: "ready",
|
||||
actions: applyGiftProductsErrorAction,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const readyState = catalogMachineSetup.createStateConfig({
|
||||
on: {
|
||||
PaymentInit: {
|
||||
target: "refreshingPlans",
|
||||
actions: "refreshCatalog",
|
||||
},
|
||||
PaymentInit: [
|
||||
{
|
||||
guard: "isTipInit",
|
||||
target: "loadingGiftProducts",
|
||||
actions: "refreshCatalog",
|
||||
},
|
||||
{
|
||||
target: "refreshingPlans",
|
||||
actions: "refreshCatalog",
|
||||
},
|
||||
],
|
||||
PaymentCatalogRetryRequested: [
|
||||
{
|
||||
guard: "isTipCatalog",
|
||||
target: "loadingGiftProducts",
|
||||
},
|
||||
{ target: "refreshingPlans" },
|
||||
],
|
||||
PaymentPlanSelected: { actions: "selectPlan" },
|
||||
PaymentPayChannelChanged: { actions: "changePayChannel" },
|
||||
PaymentAutoRenewChanged: { actions: "changeAutoRenew" },
|
||||
|
||||
Reference in New Issue
Block a user