barsa 0c904f7944 Refactor CardBadge and InternetPlanCard components for improved styling and functionality
- Updated CardBadge to support additional size options and enhanced styling for better visual consistency.
- Refactored InternetPlanCard to utilize the new CardBadge size options and improved layout for badge display.
- Enhanced state management in InternetPlanCard to utilize Zustand for better performance and maintainability.
- Streamlined rendering logic in InternetConfigureContainer for improved step transitions and user experience.
- Updated catalog utility functions to remove deprecated filtering and sorting methods, focusing on server-side handling.
2025-10-28 15:55:46 +09:00

285 lines
7.9 KiB
TypeScript

import type { AccessModeValue } from "./contract";
import type { OrderSelections } from "./schema";
import { normalizeOrderSelections } from "./helpers";
import type { ActivationType, MnpData, SimCardType } from "../sim";
/**
* Draft representation of Internet checkout configuration.
* Only includes business-relevant fields that should be transformed into selections.
*/
export interface InternetCheckoutDraft {
planSku?: string | null | undefined;
accessMode?: AccessModeValue | null | undefined;
installationSku?: string | null | undefined;
addonSkus?: readonly string[] | null | undefined;
}
/**
* Patch representation of Internet checkout state derived from persisted selections.
* Consumers can merge this object into their local UI state.
*/
export interface InternetCheckoutStatePatch {
planSku?: string | null;
accessMode?: AccessModeValue | null;
installationSku?: string | null;
addonSkus?: string[];
}
/**
* Draft representation of SIM checkout configuration.
*/
export interface SimCheckoutDraft {
planSku?: string | null | undefined;
simType?: SimCardType | null | undefined;
activationType?: ActivationType | null | undefined;
eid?: string | null | undefined;
scheduledActivationDate?: string | null | undefined;
wantsMnp?: boolean | null | undefined;
mnpData?: Partial<MnpData> | null | undefined;
addonSkus?: readonly string[] | null | undefined;
}
/**
* Patch representation of SIM checkout state derived from persisted selections.
*/
export interface SimCheckoutStatePatch {
planSku?: string | null;
simType?: SimCardType | null;
activationType?: ActivationType | null;
eid?: string;
scheduledActivationDate?: string;
wantsMnp?: boolean;
selectedAddons?: string[];
mnpData?: Partial<MnpData>;
}
const normalizeString = (value: unknown): string | undefined => {
if (typeof value !== "string") return undefined;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : undefined;
};
const normalizeSkuList = (values: readonly string[] | null | undefined): string | undefined => {
if (!Array.isArray(values)) return undefined;
const sanitized = values
.map(normalizeString)
.filter((entry): entry is string => Boolean(entry));
if (sanitized.length === 0) {
return undefined;
}
return sanitized.join(",");
};
const parseAddonList = (value: string | undefined): string[] => {
if (!value) return [];
return value
.split(",")
.map(entry => entry.trim())
.filter(Boolean);
};
const coalescePlanSku = (selections: OrderSelections): string | null => {
const planCandidates = [
selections.planSku,
selections.planIdSku,
selections.plan,
selections.planId,
];
for (const candidate of planCandidates) {
const normalized = normalizeString(candidate);
if (normalized) {
return normalized;
}
}
return null;
};
/**
* Build normalized order selections for Internet checkout from a UI draft.
* Ensures only business-relevant data is emitted.
*/
export function buildInternetCheckoutSelections(
draft: InternetCheckoutDraft
): OrderSelections {
const raw: Record<string, string> = {};
const planSku = normalizeString(draft.planSku);
if (planSku) {
raw.plan = planSku;
raw.planSku = planSku;
}
const accessMode = draft.accessMode ?? null;
if (accessMode) {
raw.accessMode = accessMode;
}
const installationSku = normalizeString(draft.installationSku);
if (installationSku) {
raw.installationSku = installationSku;
}
const addons = normalizeSkuList(draft.addonSkus);
if (addons) {
raw.addons = addons;
}
return normalizeOrderSelections(raw);
}
/**
* Derive Internet checkout UI state from normalized selections.
*/
export function deriveInternetCheckoutState(
selections: OrderSelections
): InternetCheckoutStatePatch {
const patch: InternetCheckoutStatePatch = {
addonSkus: parseAddonList(selections.addons),
};
const planSku = coalescePlanSku(selections);
if (planSku) {
patch.planSku = planSku;
}
if (selections.accessMode) {
patch.accessMode = selections.accessMode;
}
const installationSku = normalizeString(selections.installationSku);
if (installationSku) {
patch.installationSku = installationSku;
}
return patch;
}
/**
* Build normalized order selections for SIM checkout from a UI draft.
*/
export function buildSimCheckoutSelections(draft: SimCheckoutDraft): OrderSelections {
const raw: Record<string, string> = {};
const planSku = normalizeString(draft.planSku);
if (planSku) {
raw.plan = planSku;
raw.planSku = planSku;
}
if (draft.simType) {
raw.simType = draft.simType;
}
if (draft.activationType) {
raw.activationType = draft.activationType;
}
const eid = normalizeString(draft.eid);
if (draft.simType === "eSIM" && eid) {
raw.eid = eid;
}
const scheduledAt = normalizeString(draft.scheduledActivationDate);
if (draft.activationType === "Scheduled" && scheduledAt) {
raw.scheduledAt = scheduledAt;
}
const addons = normalizeSkuList(draft.addonSkus);
if (addons) {
raw.addons = addons;
}
const wantsMnp = Boolean(draft.wantsMnp);
if (wantsMnp) {
raw.isMnp = "true";
const mnpData = draft.mnpData ?? {};
const assignIfPresent = (key: keyof MnpData, targetKey: keyof typeof raw) => {
const normalized = normalizeString(mnpData[key]);
if (normalized) {
raw[targetKey] = normalized;
}
};
assignIfPresent("reservationNumber", "mnpNumber");
assignIfPresent("expiryDate", "mnpExpiry");
assignIfPresent("phoneNumber", "mnpPhone");
assignIfPresent("mvnoAccountNumber", "mvnoAccountNumber");
assignIfPresent("portingLastName", "portingLastName");
assignIfPresent("portingFirstName", "portingFirstName");
assignIfPresent("portingLastNameKatakana", "portingLastNameKatakana");
assignIfPresent("portingFirstNameKatakana", "portingFirstNameKatakana");
assignIfPresent("portingGender", "portingGender");
assignIfPresent("portingDateOfBirth", "portingDateOfBirth");
}
return normalizeOrderSelections(raw);
}
/**
* Derive SIM checkout UI state from normalized selections.
*/
export function deriveSimCheckoutState(selections: OrderSelections): SimCheckoutStatePatch {
const planSku = coalescePlanSku(selections);
const simType = selections.simType ?? null;
const activationType = selections.activationType ?? null;
const eid = normalizeString(selections.eid);
const scheduledActivationDate = normalizeString(selections.scheduledAt);
const addonSkus = parseAddonList(selections.addons);
const wantsMnp = Boolean(
selections.isMnp &&
typeof selections.isMnp === "string" &&
selections.isMnp.toLowerCase() === "true"
);
const mnpFields: Partial<MnpData> = {};
const assignField = (source: keyof OrderSelections, target: keyof MnpData) => {
const normalized = normalizeString(selections[source]);
if (normalized) {
mnpFields[target] = normalized;
}
};
if (wantsMnp) {
assignField("mnpNumber", "reservationNumber");
assignField("mnpExpiry", "expiryDate");
assignField("mnpPhone", "phoneNumber");
assignField("mvnoAccountNumber", "mvnoAccountNumber");
assignField("portingLastName", "portingLastName");
assignField("portingFirstName", "portingFirstName");
assignField("portingLastNameKatakana", "portingLastNameKatakana");
assignField("portingFirstNameKatakana", "portingFirstNameKatakana");
assignField("portingGender", "portingGender");
assignField("portingDateOfBirth", "portingDateOfBirth");
}
const patch: SimCheckoutStatePatch = {
selectedAddons: addonSkus,
wantsMnp,
};
if (planSku) {
patch.planSku = planSku;
}
if (simType) {
patch.simType = simType;
}
if (activationType) {
patch.activationType = activationType;
}
patch.eid = eid ?? "";
patch.scheduledActivationDate = scheduledActivationDate ?? "";
if (wantsMnp && Object.keys(mnpFields).length > 0) {
patch.mnpData = mnpFields;
}
return patch;
}