barsa bb4be98444 feat: Enhance About Us page with animations and updated styles
- Updated typography for headings and paragraphs in AboutUsView.
- Added animation effects for header and sections to improve user experience.
- Refactored section headers to use new display styles.

feat: Implement bilingual address handling in AddressConfirmation

- Integrated JapanAddressForm for ZIP code lookup and bilingual address input.
- Updated state management to handle bilingual addresses and validation.
- Enhanced save functionality to support dual-write to WHMCS and Salesforce.

fix: Adjust Japan Post address mapping to handle nullish values

- Updated address mapping to use nullish coalescing for optional fields.
- Ensured compatibility with API responses that may return null for certain fields.

feat: Add ServiceCard component for displaying services

- Created a flexible ServiceCard component with multiple variants (default, featured, minimal, bento).
- Implemented accent color options and responsive design for better UI.
- Added detailed props documentation and usage examples.

chore: Clean up development scripts

- Removed unnecessary build steps for validation package in manage.sh.
2026-01-14 16:25:06 +09:00

58 lines
1.7 KiB
TypeScript

/**
* Japan Post API - Mapper
*
* Transforms Japan Post API responses to domain types.
* Single transformation point: Raw API -> Domain type
*/
import type { JapanPostAddressRecord, JapanPostSearchResponse } from "./raw.types.js";
import { japanPostSearchResponseSchema } from "./raw.types.js";
import type { JapanPostAddress, AddressLookupResult } from "../../schema.js";
/**
* Transform a single Japan Post address record to domain type
*/
export function transformJapanPostAddress(raw: JapanPostAddressRecord): JapanPostAddress {
// Get ZIP code from either field name
const zipCode = raw.zipcode || raw.zip_code || "";
return {
zipCode,
// Japanese
prefecture: raw.pref_name || "",
prefectureKana: raw.pref_kana ?? undefined,
city: raw.city_name || "",
cityKana: raw.city_kana ?? undefined,
town: raw.town_name || "",
townKana: raw.town_kana ?? undefined,
// Romanized
prefectureRoma: raw.pref_roma || "",
cityRoma: raw.city_roma || "",
townRoma: raw.town_roma || "",
};
}
/**
* Transform Japan Post search response to domain AddressLookupResult
*/
export function transformJapanPostSearchResponse(raw: unknown): AddressLookupResult {
const parsed = japanPostSearchResponseSchema.parse(raw);
// Get ZIP code from first address or empty string
const firstAddress = parsed.addresses[0];
const zipCode = firstAddress?.zipcode || firstAddress?.zip_code || "";
return {
zipCode,
addresses: parsed.addresses.map(transformJapanPostAddress),
count: parsed.count,
};
}
/**
* Parse and validate raw Japan Post API response
*/
export function parseJapanPostSearchResponse(raw: unknown): JapanPostSearchResponse {
return japanPostSearchResponseSchema.parse(raw);
}