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:
@@ -33,7 +33,6 @@ import { useDeleteDialog } from '@/hooks/useDeleteDialog';
|
||||
import { CommentSection } from '../CommentSection';
|
||||
import { deletePost } from '../actions';
|
||||
import type { Post, Comment } from '../types';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import { sanitizeHTML } from '@/lib/sanitize';
|
||||
|
||||
|
||||
@@ -13,13 +13,11 @@
|
||||
import { useState, useCallback, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { format } from 'date-fns';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { FileDropzone } from '@/components/ui/file-dropzone';
|
||||
import { FileList, type NewFile, type ExistingFile } from '@/components/ui/file-list';
|
||||
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
|
||||
import { boardCreateConfig, boardEditConfig } from './boardFormConfig';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
|
||||
@@ -40,7 +38,6 @@ import {
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
@@ -50,7 +47,7 @@ import {
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const RichTextEditor = dynamic(() => import('../RichTextEditor'), { ssr: false });
|
||||
import type { Post, Attachment } from '../types';
|
||||
import type { Post } from '../types';
|
||||
import { createPost, updatePost } from '../actions';
|
||||
import { getBoards } from '../BoardManagement/actions';
|
||||
import type { Board } from '../BoardManagement/types';
|
||||
@@ -107,7 +104,7 @@ export function BoardForm({ mode, initialData }: BoardFormProps) {
|
||||
// 게시판 목록 상태
|
||||
const [boards, setBoards] = useState<Board[]>([]);
|
||||
const [isBoardsLoading, setIsBoardsLoading] = useState(true);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [, setIsSubmitting] = useState(false);
|
||||
|
||||
// ===== 게시판 목록 조회 =====
|
||||
useEffect(() => {
|
||||
|
||||
@@ -29,7 +29,6 @@ import type { Post } from '../types';
|
||||
import { getBoards } from '../BoardManagement/actions';
|
||||
import { getPosts, getMyPosts, deletePost } from '../actions';
|
||||
import type { Board } from '../BoardManagement/types';
|
||||
import { toast } from 'sonner';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
|
||||
export function BoardListUnified() {
|
||||
@@ -133,7 +132,7 @@ export function BoardListUnified() {
|
||||
totalCount: 0,
|
||||
};
|
||||
},
|
||||
deleteItem: async (id: string) => {
|
||||
deleteItem: async (_id: string) => {
|
||||
// 게시글 삭제는 boardCode가 필요하므로 별도 처리
|
||||
// UniversalListPage에서는 사용하지 않고 커스텀 삭제 처리
|
||||
return { success: false, error: 'Use custom delete handler' };
|
||||
@@ -143,10 +142,10 @@ export function BoardListUnified() {
|
||||
// ===== 테이블 컬럼 =====
|
||||
columns: [
|
||||
{ key: 'no', label: 'No.', className: 'w-[60px] text-center' },
|
||||
{ key: 'title', label: '제목', className: 'min-w-[300px]' },
|
||||
{ key: 'author', label: '작성자', className: 'w-[120px]' },
|
||||
{ key: 'createdAt', label: '등록일', className: 'w-[120px]' },
|
||||
{ key: 'viewCount', label: '조회수', className: 'w-[80px] text-center' },
|
||||
{ key: 'title', label: '제목', className: 'min-w-[300px]', copyable: true },
|
||||
{ key: 'author', label: '작성자', className: 'w-[120px]', copyable: true },
|
||||
{ key: 'createdAt', label: '등록일', className: 'w-[120px]', copyable: true },
|
||||
{ key: 'viewCount', label: '조회수', className: 'w-[80px] text-center', copyable: true },
|
||||
{ key: 'actions', label: '작업', className: 'w-[100px] text-center' },
|
||||
],
|
||||
|
||||
@@ -161,7 +160,7 @@ export function BoardListUnified() {
|
||||
detailMode: 'none', // 커스텀 라우팅 사용 (boardCode 포함)
|
||||
|
||||
// ===== 헤더 액션 =====
|
||||
headerActions: ({ onCreate }) => (
|
||||
headerActions: ({ onCreate: _onCreate }) => (
|
||||
<>
|
||||
<DateRangeSelector
|
||||
startDate={startDate}
|
||||
|
||||
@@ -132,7 +132,7 @@ export function BoardList() {
|
||||
}, []);
|
||||
|
||||
// ===== 액션 핸들러 =====
|
||||
const handleRowClick = useCallback(
|
||||
const _handleRowClick = useCallback(
|
||||
(item: Post) => {
|
||||
router.push(`/ko/board/${item.boardCode}/${item.id}?mode=view`);
|
||||
},
|
||||
@@ -224,10 +224,10 @@ export function BoardList() {
|
||||
|
||||
columns: [
|
||||
{ key: 'no', label: 'No.', className: 'w-[60px] text-center' },
|
||||
{ key: 'title', label: '제목', className: 'min-w-[300px]', sortable: true },
|
||||
{ key: 'author', label: '작성자', className: 'w-[120px]', sortable: true },
|
||||
{ key: 'createdAt', label: '등록일', className: 'w-[120px]', sortable: true },
|
||||
{ key: 'viewCount', label: '조회수', className: 'w-[80px] text-center', sortable: true },
|
||||
{ key: 'title', label: '제목', className: 'min-w-[300px]', sortable: true, copyable: true },
|
||||
{ key: 'author', label: '작성자', className: 'w-[120px]', sortable: true, copyable: true },
|
||||
{ key: 'createdAt', label: '등록일', className: 'w-[120px]', sortable: true, copyable: true },
|
||||
{ key: 'viewCount', label: '조회수', className: 'w-[80px] text-center', sortable: true, copyable: true },
|
||||
{ key: 'actions', label: '작업', className: 'w-[100px] text-center' },
|
||||
],
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 기존 BoardDetail, BoardForm 컴포넌트 활용
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { BoardDetail } from './BoardDetail';
|
||||
@@ -17,7 +17,6 @@ import { forceRefreshMenus } from '@/lib/utils/menuRefresh';
|
||||
import type { Board, BoardFormData } from './types';
|
||||
import { DetailPageSkeleton } from '@/components/ui/skeleton';
|
||||
import { ErrorCard } from '@/components/ui/error-card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DeleteConfirmDialog } from '@/components/ui/confirm-dialog';
|
||||
import { useDeleteDialog } from '@/hooks/useDeleteDialog';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { ClipboardList, ArrowLeft, Save, X } from 'lucide-react';
|
||||
import { ClipboardList, Save, X } from 'lucide-react';
|
||||
import { useMenuStore } from '@/stores/menuStore';
|
||||
import type { Board, BoardFormData, BoardTarget, BoardStatus } from './types';
|
||||
import { BOARD_TARGETS, BOARD_STATUS_LABELS } from './types';
|
||||
|
||||
@@ -39,7 +39,7 @@ const getTargetDisplay = (board: Board) => {
|
||||
};
|
||||
|
||||
// 탭 옵션 계산
|
||||
const computeTabs = (data: Board[]): TabOption[] => {
|
||||
const _computeTabs = (data: Board[]): TabOption[] => {
|
||||
const activeCount = data.filter((b) => b.status === 'active').length;
|
||||
const inactiveCount = data.filter((b) => b.status === 'inactive').length;
|
||||
|
||||
@@ -82,11 +82,11 @@ const createBoardManagementConfig = (router: ReturnType<typeof useRouter>): Univ
|
||||
// 테이블 컬럼
|
||||
columns: [
|
||||
{ key: 'rowNumber', label: 'No.', className: 'w-[60px] text-center' },
|
||||
{ key: 'target', label: '대상', className: 'min-w-[100px]' },
|
||||
{ key: 'boardName', label: '게시판명', className: 'min-w-[150px]' },
|
||||
{ key: 'target', label: '대상', className: 'min-w-[100px]', copyable: true },
|
||||
{ key: 'boardName', label: '게시판명', className: 'min-w-[150px]', copyable: true },
|
||||
{ key: 'status', label: '상태', className: 'min-w-[80px]' },
|
||||
{ key: 'authorName', label: '작성자', className: 'min-w-[100px]' },
|
||||
{ key: 'createdAt', label: '등록일시', className: 'min-w-[120px]' },
|
||||
{ key: 'authorName', label: '작성자', className: 'min-w-[100px]', copyable: true },
|
||||
{ key: 'createdAt', label: '등록일시', className: 'min-w-[120px]', copyable: true },
|
||||
],
|
||||
|
||||
// 탭 설정 (클라이언트 사이드 계산)
|
||||
@@ -135,7 +135,7 @@ const createBoardManagementConfig = (router: ReturnType<typeof useRouter>): Univ
|
||||
|
||||
// 테이블 행 렌더링
|
||||
renderTableRow: (item, index, globalIndex, handlers) => {
|
||||
const { isSelected, onToggle, onRowClick, onEdit, onDelete } = handlers;
|
||||
const { isSelected, onToggle, onRowClick, onEdit: _onEdit, onDelete: _onDelete } = handlers;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
@@ -164,7 +164,7 @@ const createBoardManagementConfig = (router: ReturnType<typeof useRouter>): Univ
|
||||
|
||||
// 모바일 카드 렌더링
|
||||
renderMobileCard: (item, index, globalIndex, handlers) => {
|
||||
const { isSelected, onToggle, onRowClick, onEdit, onDelete } = handlers;
|
||||
const { isSelected, onToggle, onRowClick, onEdit: _onEdit, onDelete: _onDelete } = handlers;
|
||||
|
||||
return (
|
||||
<ListMobileCard
|
||||
|
||||
@@ -25,7 +25,7 @@ interface CommentSectionProps {
|
||||
}
|
||||
|
||||
export function CommentSection({
|
||||
postId,
|
||||
postId: _postId,
|
||||
comments,
|
||||
currentUserId,
|
||||
onAddComment,
|
||||
|
||||
Reference in New Issue
Block a user