refactor(payment): centralize route lifecycle

This commit is contained in:
2026-07-15 18:47:01 +08:00
parent 7dce1b5d4c
commit 590dee417b
9 changed files with 203 additions and 144 deletions
@@ -0,0 +1,38 @@
import { describe, expect, it } from "vitest";
import {
getFirstPaymentSearchParam,
parsePaymentPayChannel,
parsePaymentReturnSearchParams,
} from "../payment_search_params";
describe("payment search params", () => {
it("takes the first value from repeated query parameters", () => {
expect(getFirstPaymentSearchParam(["first", "second"])).toBe("first");
expect(getFirstPaymentSearchParam([])).toBeNull();
});
it("accepts only supported payment channels", () => {
expect(parsePaymentPayChannel("stripe")).toBe("stripe");
expect(parsePaymentPayChannel(["ezpay", "stripe"])).toBe("ezpay");
expect(parsePaymentPayChannel("paypal")).toBeNull();
expect(parsePaymentPayChannel(undefined)).toBeNull();
});
it("parses the shared payment return context", () => {
expect(
parsePaymentReturnSearchParams({
payChannel: ["ezpay", "stripe"],
paymentReturn: "1",
}),
).toEqual({
initialPayChannel: "ezpay",
shouldResumePendingOrder: true,
});
expect(parsePaymentReturnSearchParams({ paymentReturn: "0" })).toEqual({
initialPayChannel: null,
shouldResumePendingOrder: false,
});
});
});
+32
View File
@@ -0,0 +1,32 @@
import type { PayChannel } from "@/data/dto/payment";
export type PaymentSearchParamValue = string | string[] | undefined;
export type PaymentSearchParams = Record<string, PaymentSearchParamValue>;
export interface PaymentReturnSearchParams {
initialPayChannel: PayChannel | null;
shouldResumePendingOrder: boolean;
}
export function getFirstPaymentSearchParam(
value: PaymentSearchParamValue,
): string | null {
return Array.isArray(value) ? (value[0] ?? null) : (value ?? null);
}
export function parsePaymentPayChannel(
value: PaymentSearchParamValue,
): PayChannel | null {
const channel = getFirstPaymentSearchParam(value);
return channel === "ezpay" || channel === "stripe" ? channel : null;
}
export function parsePaymentReturnSearchParams(
searchParams: PaymentSearchParams,
): PaymentReturnSearchParams {
return {
initialPayChannel: parsePaymentPayChannel(searchParams.payChannel),
shouldResumePendingOrder:
getFirstPaymentSearchParam(searchParams.paymentReturn) === "1",
};
}