feat(converter): add shareable conversion links via query parameters
This commit is contained in:
84
lib/share-link.ts
Normal file
84
lib/share-link.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { validateAmount } from "@/lib/validation";
|
||||
|
||||
interface QueryParamReader {
|
||||
get(name: string): string | null;
|
||||
}
|
||||
|
||||
interface ConversionShareParams {
|
||||
amount?: string;
|
||||
fromCode?: string;
|
||||
toCode?: string;
|
||||
}
|
||||
|
||||
const CODE_PATTERN = /^[A-Z0-9]{2,12}$/;
|
||||
|
||||
function normalizeCurrencyCode(value: string | null): string | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const normalized = value.trim().toUpperCase();
|
||||
|
||||
if (!CODE_PATTERN.test(normalized)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function normalizeAmount(value: string | null): string | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const trimmed = value.trim().replace(/\s+/g, "");
|
||||
|
||||
if (!trimmed || trimmed.length > 64) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return validateAmount(trimmed).ok ? trimmed : undefined;
|
||||
}
|
||||
|
||||
export function parseConversionShareParams(
|
||||
searchParams: QueryParamReader,
|
||||
): ConversionShareParams {
|
||||
const amount = normalizeAmount(searchParams.get("amount"));
|
||||
const fromCode = normalizeCurrencyCode(searchParams.get("from"));
|
||||
let toCode = normalizeCurrencyCode(searchParams.get("to"));
|
||||
|
||||
if (fromCode && toCode && fromCode === toCode) {
|
||||
toCode = undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
amount,
|
||||
fromCode,
|
||||
toCode,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildConversionShareUrl(input: {
|
||||
origin: string;
|
||||
pathname: string;
|
||||
amount: string;
|
||||
fromCode: string;
|
||||
toCode: string;
|
||||
}): string {
|
||||
const url = new URL(input.pathname, input.origin);
|
||||
const amount = normalizeAmount(input.amount) ?? "1";
|
||||
const fromCode = normalizeCurrencyCode(input.fromCode);
|
||||
const toCode = normalizeCurrencyCode(input.toCode);
|
||||
|
||||
url.searchParams.set("amount", amount);
|
||||
|
||||
if (fromCode) {
|
||||
url.searchParams.set("from", fromCode);
|
||||
}
|
||||
|
||||
if (toCode && toCode !== fromCode) {
|
||||
url.searchParams.set("to", toCode);
|
||||
}
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
Reference in New Issue
Block a user