feat: ESLint 정리 및 전체 코드 품질 개선

- eslint.config.mjs 규칙 강화 및 정리
- 전역 unused import/변수 제거 (312개 파일)
- next.config.ts, middleware, proxy route 개선
- CopyableCell molecule 추가
- 회계/결재/HR/생산/건설/품질/영업 등 전 도메인 lint 정리
- IntegratedListTemplateV2, DataTable, MobileCard 등 공통 컴포넌트 개선
- execute-server-action 에러 핸들링 보강
This commit is contained in:
유병철
2026-03-11 10:27:10 +09:00
parent 924726cba1
commit 81affdc441
315 changed files with 1977 additions and 1344 deletions

View File

@@ -0,0 +1,61 @@
'use client';
import { ReactNode, useCallback, useState } from 'react';
import { Check, Copy } from 'lucide-react';
import { cn } from '@/lib/utils';
interface CopyableCellProps {
/** 복사할 텍스트 값 */
value: string;
/** 셀에 표시할 내용 (기본: value) */
children?: ReactNode;
/** 추가 클래스 */
className?: string;
}
/**
* 테이블 셀 내 텍스트에 hover 시 복사 버튼을 표시하는 래퍼
*
* 사용법:
* ```tsx
* <TableCell>
* <CopyableCell value={item.itemCode}>{item.itemCode}</CopyableCell>
* </TableCell>
* ```
*/
export function CopyableCell({ value, children, className }: CopyableCellProps) {
const [copied, setCopied] = useState(false);
const handleCopy = useCallback((e: React.MouseEvent) => {
e.stopPropagation();
e.preventDefault();
navigator.clipboard.writeText(value).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 1500);
});
}, [value]);
return (
<span className={cn('group/copy relative block max-w-full overflow-hidden', className)}>
<span className="block truncate">{children ?? value}</span>
<button
type="button"
onClick={handleCopy}
className={cn(
'absolute right-0 top-1/2 -translate-y-1/2',
'opacity-0 group-hover/copy:opacity-100 transition-opacity',
'pl-4 pr-0.5 py-0.5',
'bg-gradient-to-l from-background via-background to-transparent',
copied && 'opacity-100',
)}
title="복사"
>
{copied ? (
<Check className="h-3.5 w-3.5 text-green-500" />
) : (
<Copy className="h-3.5 w-3.5 text-muted-foreground hover:text-foreground" />
)}
</button>
</span>
);
}

View File

@@ -90,7 +90,7 @@ export function DateRangeSelector({
extraActions,
hidePresets = false,
hideDateInputs = false,
dateInputWidth = 'w-[140px]',
dateInputWidth: _dateInputWidth = 'w-[140px]',
presetsPosition = 'inline',
variant = 'combined',
}: DateRangeSelectorProps) {

View File

@@ -11,7 +11,6 @@ import { AlertCircle } from "lucide-react";
import { PhoneInput } from "../ui/phone-input";
import { BusinessNumberInput } from "../ui/business-number-input";
import { PersonalNumberInput } from "../ui/personal-number-input";
import { NumberInput } from "../ui/number-input";
import { CurrencyInput } from "../ui/currency-input";
import { QuantityInput } from "../ui/quantity-input";
import { DatePicker } from "../ui/date-picker";
@@ -104,9 +103,9 @@ export function FormField({
// 새 입력 타입 전용 옵션
showValidation,
maskBack,
allowDecimal,
decimalPlaces,
useComma,
allowDecimal: _allowDecimal,
decimalPlaces: _decimalPlaces,
useComma: _useComma,
suffix,
showButtons,
maxLength,

View File

@@ -96,7 +96,7 @@ function countActiveFilters(
/**
* 필터 필드 요약 텍스트 생성
*/
function getFieldSummary(
function _getFieldSummary(
field: FilterFieldConfig,
value: string | string[] | undefined
): string {

View File

@@ -64,7 +64,7 @@ export function StandardDialog({
children,
footer,
size = "md",
showClose = true,
showClose: _showClose = true,
className,
}: StandardDialogProps) {
return (

View File

@@ -3,7 +3,6 @@
import { Badge } from "@/components/ui/badge";
import { BadgeSm } from "@/components/atoms/BadgeSm";
import { LucideIcon } from "lucide-react";
import { BADGE_STYLE_PRESETS, type StatusStylePreset } from "@/lib/utils/status-config";
/**
* 상태 뱃지 컴포넌트
@@ -61,7 +60,7 @@ export function StatusBadge({
icon: Icon,
className = "",
size = "md",
showDot
showDot: _showDot
}: StatusBadgeProps) {
// variant에 따른 기본 스타일
const variantStyles: Record<string, string> = {

View File

@@ -15,4 +15,6 @@ export type { Quarter } from "./YearQuarterFilter";
export { GenericCRUDDialog } from "./GenericCRUDDialog";
export type { GenericCRUDDialogProps, CRUDFieldDefinition } from "./GenericCRUDDialog";
export { ReorderButtons } from "./ReorderButtons";
export { ReorderButtons } from "./ReorderButtons";
export { CopyableCell } from "./CopyableCell";