- 백엔드: quotation 목록 search 파라미터(name/number ILIKE) 추가; card 목록 is_wildcard 탭 필터 + total_nego/total_wild 탭 카운트 추가; status/type 코드 int 비교 보정 - 프론트: cards/quotation 검색·상태·유형 필터·페이지네이션을 useServerList 기반 서버사이드로 전환; 엔터 즉시검색 + 디바운스 500ms·최소 2글자; 죽은 client 필터 훅(useCardFilters/useQuotationFilters) 제거 - generated 파라미터/응답 타입 손보강(listCardsParams.is_wildcard, listQuotationsParams.search, resCardList.total_nego/total_wild) — orval 재생성 시 동일 - 견적 상세 Drawer→Sheet 분리, useOverlayParams→useOverlayRouter, CreateQuotationWizard→QuotationCreateModal Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
905 B
TypeScript
36 lines
905 B
TypeScript
import type { ReactNode } from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
type InfoFieldProps = {
|
|
label: string;
|
|
/** 단순 텍스트 값. 커스텀 마크업이 필요하면 value 대신 children 을 쓴다. */
|
|
value?: ReactNode;
|
|
children?: ReactNode;
|
|
className?: string;
|
|
labelClassName?: string;
|
|
valueClassName?: string;
|
|
title?: string;
|
|
};
|
|
|
|
/** 헤더 카드의 `라벨 / 값` 한 칸. (드로어 곳곳에서 ~20회 반복되던 패턴) */
|
|
export function InfoField({
|
|
label,
|
|
value,
|
|
children,
|
|
className,
|
|
labelClassName,
|
|
valueClassName,
|
|
title,
|
|
}: InfoFieldProps) {
|
|
return (
|
|
<div className={className}>
|
|
<span className={cn('text-[10px] block opacity-70', labelClassName)}>{label}</span>
|
|
{children ?? (
|
|
<span className={cn('text-foreground font-semibold', valueClassName)} title={title}>
|
|
{value}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|