mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-08 13:58:40 +00:00
87 lines
2.9 KiB
TypeScript
87 lines
2.9 KiB
TypeScript
import { oneOf } from "./parse.js";
|
|
|
|
export const STEPS = ["tier", "months", "checkout"] as const;
|
|
export const THEMES = ["light", "dark", "system"] as const;
|
|
const ORDER_STATUSES = ["open", "paid", "expired"] as const;
|
|
const METHODS = ["card", "btc", "xmr"] as const;
|
|
const CHAINS = ["btc", "xmr"] as const;
|
|
const APPS = ["mobile", "desktop"] as const;
|
|
|
|
export type Step = (typeof STEPS)[number];
|
|
export type Theme = (typeof THEMES)[number];
|
|
export type OrderStatus = (typeof ORDER_STATUSES)[number];
|
|
export type Method = (typeof METHODS)[number];
|
|
export type Chain = (typeof CHAINS)[number];
|
|
/** The SimpleX app that opened the page, which decides how the code is handed over at the end. */
|
|
export type App = (typeof APPS)[number];
|
|
|
|
export const readStep = oneOf(STEPS);
|
|
export const readTheme = oneOf(THEMES);
|
|
export const readStatus = oneOf(ORDER_STATUSES);
|
|
export const readMethod = oneOf(METHODS);
|
|
export const readChain = oneOf(CHAINS);
|
|
export const readApp = oneOf(APPS);
|
|
|
|
/** The optional fields are written `| undefined` so a patch can set one back to undefined to clear it. */
|
|
export interface SessionRecord {
|
|
step: Step;
|
|
priceId?: string | undefined;
|
|
offerId?: string | undefined;
|
|
method?: Method | undefined;
|
|
app?: App | undefined;
|
|
}
|
|
|
|
export interface OrderIdentity {
|
|
orderId: string;
|
|
badgeType: string;
|
|
months: number;
|
|
createdAt: string;
|
|
}
|
|
|
|
/** The service never sends these fields back, so nothing it returns can clear them. */
|
|
export interface OrderLocalState {
|
|
code: string | undefined;
|
|
submitted: boolean | undefined;
|
|
canceled: boolean | undefined;
|
|
method: Method | undefined;
|
|
app: App | undefined;
|
|
}
|
|
|
|
/** Every field is a required key even when undefined, so a withdrawn field cannot survive in the stored record. */
|
|
export interface OrderServerState {
|
|
status: OrderStatus;
|
|
amount: number | undefined;
|
|
currency: string | undefined;
|
|
amountPaid: number | undefined;
|
|
cryptoAmountPaid: string | undefined;
|
|
cryptoAmountDue: string | undefined;
|
|
paidInFull: boolean | undefined;
|
|
address: string | undefined;
|
|
cryptoAmount: string | undefined;
|
|
cryptoCurrency: Chain | undefined;
|
|
expiresAt: string | undefined;
|
|
}
|
|
|
|
type OrderLocalFields = Partial<OrderLocalState>;
|
|
type OrderServerFields = Partial<OrderServerState> & { status: OrderStatus };
|
|
|
|
export type OrderRecord = OrderIdentity & OrderLocalFields & OrderServerFields;
|
|
|
|
function identityOf(o: OrderIdentity): OrderIdentity {
|
|
const { orderId, badgeType, months, createdAt } = o;
|
|
return { orderId, badgeType, months, createdAt };
|
|
}
|
|
|
|
export function definedOnly<Complete extends object, Sparse>(all: Complete): Sparse {
|
|
const present = Object.entries(all).filter(([, v]) => v !== undefined);
|
|
return Object.fromEntries(present) as unknown as Sparse;
|
|
}
|
|
|
|
export function composeOrder(
|
|
identity: OrderIdentity,
|
|
local: OrderLocalState,
|
|
server: OrderServerState,
|
|
): OrderRecord {
|
|
return definedOnly({ ...identityOf(identity), ...local, ...server });
|
|
}
|