File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
export const MERCHANTS_PATH = '/system/merchants';
/** 엑셀 다운로드 — 파일 응답이라 라우트 핸들러가 받는다(기획 MCH_001 ②). */
export const MERCHANTS_EXCEL_PATH = `${MERCHANTS_PATH}/excel`;
/** 필터 셀렉트의 "전체" 값 — URL에서는 생략된다. */
export const FILTER_ALL = '';
export type MerchantSearchField = 'name' | 'businessNumber' | 'address';
export const MERCHANT_SEARCH_FIELD_OPTIONS: ReadonlyArray<{
value: MerchantSearchField;
label: string;
}> = [
{ value: 'name', label: '가맹점명' },
{ value: 'businessNumber', label: '사업자번호' },
{ value: 'address', label: '주소' },
];
export const MERCHANT_VISIBILITY_OPTIONS = [
{ value: 'visible', label: '노출' },
{ value: 'hidden', label: '미노출' },
] as const;
export const MERCHANT_PAGE_SIZE_OPTIONS = [10, 30, 50] as const;
export type MerchantPageSize = (typeof MERCHANT_PAGE_SIZE_OPTIONS)[number];
export const DEFAULT_MERCHANT_SEARCH_FIELD: MerchantSearchField = 'name';
export const DEFAULT_MERCHANT_PAGE_SIZE: MerchantPageSize = 10;
const DEFAULT_PAGE = 1;
const MAX_KEYWORD_LENGTH = 100;
export type MerchantQuery = {
visibility: string;
searchField: MerchantSearchField;
keyword: string;
page: number;
pageSize: MerchantPageSize;
};
type RawSearchParams = Record<string, string | string[] | undefined>;
function readParam(params: RawSearchParams, key: string): string {
const value = params[key];
return (Array.isArray(value) ? value[0] : value) ?? '';
}
function readOneOf(
params: RawSearchParams,
key: string,
allowed: readonly { value: string }[]
): string {
const raw = readParam(params, key);
return allowed.some((option) => option.value === raw) ? raw : FILTER_ALL;
}
function isSearchField(value: string): value is MerchantSearchField {
return MERCHANT_SEARCH_FIELD_OPTIONS.some((option) => option.value === value);
}
function isPageSize(value: number): value is MerchantPageSize {
return (MERCHANT_PAGE_SIZE_OPTIONS as readonly number[]).includes(value);
}
export function parseMerchantQuery(searchParams: RawSearchParams): MerchantQuery {
const searchField = readParam(searchParams, 'searchField');
const page = Number(readParam(searchParams, 'page'));
const pageSize = Number(readParam(searchParams, 'pageSize'));
return {
visibility: readOneOf(
searchParams,
'visibility',
MERCHANT_VISIBILITY_OPTIONS
),
searchField: isSearchField(searchField)
? searchField
: DEFAULT_MERCHANT_SEARCH_FIELD,
keyword: readParam(searchParams, 'keyword').trim().slice(0, MAX_KEYWORD_LENGTH),
page: Number.isInteger(page) && page > 0 ? page : DEFAULT_PAGE,
pageSize: isPageSize(pageSize) ? pageSize : DEFAULT_MERCHANT_PAGE_SIZE,
};
}
export function buildMerchantHref(
query: MerchantQuery,
overrides: Partial<MerchantQuery> = {}
): string {
const merged = { ...query, ...overrides };
const params = new URLSearchParams();
if (merged.visibility) {
params.set('visibility', merged.visibility);
}
if (merged.searchField !== DEFAULT_MERCHANT_SEARCH_FIELD) {
params.set('searchField', merged.searchField);
}
if (merged.keyword) {
params.set('keyword', merged.keyword);
}
if (merged.pageSize !== DEFAULT_MERCHANT_PAGE_SIZE) {
params.set('pageSize', String(merged.pageSize));
}
if (merged.page !== DEFAULT_PAGE) {
params.set('page', String(merged.page));
}
const queryString = params.toString();
return queryString ? `${MERCHANTS_PATH}?${queryString}` : MERCHANTS_PATH;
}