Skip to content
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Slope } from '../../../../apis/slopeMap';
import SlopeForm from './SlopeForm';
import { slopeManageAPI } from '../../../../apis/slopeManage';

interface AddSlopeProps {
isOpen: boolean;
onClose: () => void;
}
import { AddSlopeProps } from '../../interface';

const AddSlope = ({ isOpen, onClose }: AddSlopeProps) => {
const onSubmit = async (newSlopeData: Slope) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import styled from 'styled-components';
import { Table } from '@tanstack/react-table';
import { Slope } from '../../../../apis/slopeMap';

interface FilterModalProps {
isOpen: boolean;
onClose: () => void;
table: Table<Slope>;
}
import { FilterModalProps } from '../../interface';

const FilterModal = ({ isOpen, onClose, table }: FilterModalProps) => {
return (
Expand Down
43 changes: 31 additions & 12 deletions src/pages/ManagePage/StepSlope/components/DeleteModal.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import styled from 'styled-components';
import { Slope } from '../../../../apis/slopeMap';

interface DeleteConfirmModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
selectedRow: Slope | null;
}
import { useEffect, useState } from 'react';
import { DeleteConfirmModalProps } from '../../interface';

const DeleteConfirmModal = ({
isOpen,
onClose,
onConfirm,
selectedRow,
selectedRows = [],
}: DeleteConfirmModalProps) => {
const [count, setCount] = useState(0);
const [isMulti, setIsMulti] = useState(false);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
onConfirm();
onClose();
};

useEffect(() => {
if (isOpen) {
const selectedCount = selectedRows.length;
setCount(selectedCount);
setIsMulti(selectedCount > 1);
console.log('Modal opened with:', {
selectedCount,
isMulti: selectedCount > 1,
selectedRows,
});
}
}, [isOpen, selectedRows]);
return (
<ModalOverlay $isOpen={isOpen}>
<ModalContent>
Expand All @@ -29,8 +37,20 @@ const DeleteConfirmModal = ({
</ModalHeader>
<form onSubmit={handleSubmit}>
<DeleteMessage>
<BoldName>{selectedRow?.name}</BoldName>를 삭제하시려면 입력창에
<BoldText>삭제</BoldText>라고 입력해 주세요.
{isMulti ? (
// 다중 선택 시 메시지
<>
선택한 <BoldName>{count}개</BoldName>의 항목을 삭제하시려면
입력창에
<BoldText>삭제</BoldText>라고 입력해 주세요.
</>
) : (
// 단일 선택 시 메시지
<>
<BoldName>{selectedRow?.name}</BoldName>를 삭제하시려면 입력창에
<BoldText>삭제</BoldText>라고 입력해 주세요.
</>
)}
</DeleteMessage>
<FormGroup>
<input
Expand Down Expand Up @@ -59,7 +79,6 @@ const DeleteConfirmModal = ({
</ModalOverlay>
);
};

const ModalOverlay = styled.div<{ $isOpen: boolean }>`
display: ${(props) => (props.$isOpen ? 'flex' : 'none')};
position: fixed;
Expand Down
8 changes: 1 addition & 7 deletions src/pages/ManagePage/StepSlope/components/EditModal.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { Slope } from '../../../../apis/slopeMap';
import { useState, useEffect } from 'react';
import SlopeForm from './SlopeForm';

interface EditModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (updatedSlope: Slope) => void;
selectedRow: Slope | null;
}
import { EditModalProps } from '../../interface';

const EditModal = ({
isOpen,
Expand Down
15 changes: 7 additions & 8 deletions src/pages/ManagePage/StepSlope/components/RegionFilterModal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import styled from 'styled-components';
import { useState } from 'react';
import { CityOptions, CountyOptions } from './regionData';
import { RegionFilterModalProps } from '../../interface';

interface FilterModalProps {
isOpen: boolean;
onClose: () => void;
onRegionSelect: (city: string, county: string) => void;
}

const FilterModal = ({ isOpen, onClose, onRegionSelect }: FilterModalProps) => {
const RegionFilterModal = ({
isOpen,
onClose,
onRegionSelect,
}: RegionFilterModalProps) => {
const [selectedCity, setSelectedCity] = useState<string>('지역');
const [selectedCounty, setSelectedCounty] = useState<string>('모두');

Expand Down Expand Up @@ -60,7 +59,7 @@ const FilterModal = ({ isOpen, onClose, onRegionSelect }: FilterModalProps) => {
);
};

export default FilterModal;
export default RegionFilterModal;

const ModalOverlay = styled.div<{ $isOpen: boolean }>`
display: ${(props) => (props.$isOpen ? 'flex' : 'none')};
Expand Down
10 changes: 1 addition & 9 deletions src/pages/ManagePage/StepSlope/components/SlopeForm.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import styled from 'styled-components';
import { Slope } from '../../../../apis/slopeMap';
import { useState, useEffect } from 'react';

interface SlopeFormProps {
titleText: string;
initialData: Slope;
isOpen: boolean;
onClose: () => void;
onSubmit: (data: Slope) => void;
submitButtonText: string;
}
import { SlopeFormProps } from '../../interface';

const SlopeForm = ({
titleText,
Expand Down
66 changes: 40 additions & 26 deletions src/pages/ManagePage/StepSlope/components/table/DataTable.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
import React from 'react';
import styled from 'styled-components';
import {
Table as TableInstance,
Row as RowInstance,
} from '@tanstack/react-table';

import { Virtualizer } from '@tanstack/react-virtual';
import { Slope } from '../../../../../apis/slopeMap';

interface DataTableProps {
tableContainerRef: React.RefObject<HTMLDivElement>;
handleScroll: () => void;
table: TableInstance<any>;
rows: RowInstance<any>[];
rowVirtualizer: Virtualizer<HTMLDivElement, Element>;
selectedRow: Slope | null;
setSelectedRow: (row: Slope | null) => void;
}
import { DataTableProps } from '../../../interface';

const DataTable: React.FC<DataTableProps> = ({
tableContainerRef,
Expand All @@ -32,14 +16,37 @@ const DataTable: React.FC<DataTableProps> = ({
rowVirtualizer.getTotalSize() -
(paddingTop + rowVirtualizer.getVirtualItems().length * 40);

// 셀 렌더링 함수
const renderCell = (cell: any) => {
// 체크박스 열인 경우 별도 처리
if (cell.column.id === 'select') {
// 컬럼 정의에서 cell 함수를 호출
const cellContent = (cell.column.columnDef as any).cell;
if (typeof cellContent === 'function') {
return cellContent({ row: cell.row, table, column: cell.column });
}
return cellContent;
}

// 일반 셀
return cell.getValue() as string;
};

return (
<TableContainer ref={tableContainerRef} onScroll={handleScroll}>
<Table>
<TableHeader>
<tr>
{table.getHeaderGroups()[0].headers.map((header) => (
<HeaderCell key={header.id} width={header.getSize()}>
{header.column.columnDef.header as string}
{header.column.id === 'select'
? typeof (header.column.columnDef as any).header ===
'function'
? ((header.column.columnDef as any).header as any)({
table,
})
: (header.column.columnDef as any).header
: (header.column.columnDef.header as string)}
<ResizeHandle
onMouseDown={header.getResizeHandler()}
onTouchStart={header.getResizeHandler()}
Expand All @@ -62,20 +69,27 @@ const DataTable: React.FC<DataTableProps> = ({
return (
<TableRow
key={virtualRow.index}
onClick={() => {
setSelectedRow(
selectedRow?.managementNo === row.original.managementNo
? null
: row.original
);
onClick={(e) => {
// 체크박스 열이 아닌 부분을 클릭했을 때만 기존 선택 동작 수행
if (
!(e.target as HTMLElement).closest('input[type="checkbox"]')
) {
setSelectedRow(
selectedRow?.managementNo === row.original.managementNo
? null
: row.original
);
}
}}
$selected={
selectedRow?.managementNo === row.original.managementNo
selectedRow?.managementNo === row.original.managementNo ||
row.getIsSelected?.() ||
false
}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id} width={cell.column.getSize()}>
{cell.getValue() as string}
{renderCell(cell)}
</TableCell>
))}
</TableRow>
Expand Down
27 changes: 16 additions & 11 deletions src/pages/ManagePage/StepSlope/components/table/TableAction.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import styled from 'styled-components';
import React from 'react';
import { Slope } from '../../../../../apis/slopeMap';
import LoadingMessage from '../../../components/LoadingMessage';
interface TableActionProps {
isLoading: boolean;
selectedRow: Slope | null;
openEditModal: () => void;
openDeleteModal: () => void;
}
import { TableActionProps } from '../../../interface';

const TableAction: React.FC<TableActionProps> = ({
isLoading,
selectedRow,
selectedRows,
openEditModal,
openDeleteModal,
}) => {
// 선택된 행 수
const selectedCount = selectedRows?.length || 0;

return (
<>
{isLoading && <LoadingMessage text="데이터를 불러오는 중" />}
{/* 하단 버튼 컨테이너 */}
{selectedRow && (

{/* 하단 버튼 컨테이너 - 단일 선택 또는 다중 선택 시 표시 */}
{(selectedRow || selectedCount > 0) && (
<BottomButtonContainer>
<ActionButton onClick={openEditModal}>수정</ActionButton>
{/* 단일 선택일 때만 수정 버튼 표시 */}
{selectedCount <= 1 && selectedRow && (
<ActionButton onClick={openEditModal}>수정</ActionButton>
)}

{/* 삭제 버튼은 항상 표시, 다중 선택 시 개수 표시 */}
<ActionButton onClick={openDeleteModal} className="delete">
삭제
{selectedCount > 1 ? `${selectedCount}개 항목 삭제` : '삭제'}
</ActionButton>
</BottomButtonContainer>
)}
Expand Down
47 changes: 47 additions & 0 deletions src/pages/ManagePage/StepSlope/components/table/TableCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useRef, useEffect } from 'react';
import styled from 'styled-components';
import { TableCheckboxProps } from '../../../interface';

const TableCheckbox: React.FC<TableCheckboxProps> = ({
indeterminate = false,
checked = false,
disabled = false,
onChange,
...rest
}) => {
const ref = useRef<HTMLInputElement>(null);

useEffect(() => {
if (ref.current) {
ref.current.indeterminate = indeterminate;
}
}, [indeterminate]);

return (
<CheckboxContainer>
<StyledCheckbox
type="checkbox"
ref={ref}
checked={checked}
disabled={disabled}
onChange={onChange}
{...rest}
/>
</CheckboxContainer>
);
};

export default TableCheckbox;

const CheckboxContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 100%;
`;

const StyledCheckbox = styled.input`
cursor: pointer;
width: 16px;
height: 16px;
`;
21 changes: 3 additions & 18 deletions src/pages/ManagePage/StepSlope/components/table/TableModals.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,9 @@
import React from 'react';
import { Slope } from '../../../../../apis/slopeMap';
import FilterModal from '../ColumnFilterModal';
import DeleteConfirmModal from '../DeleteModal';
import EditModal from '../EditModal';
import RegionFilterModal from '../RegionFilterModal';
import { Table as TableInstance } from '@tanstack/react-table';

interface TableModalProps {
isModalOpen: boolean;
closeModal: () => void;
table: TableInstance<any>;
isRegionModalOpen: boolean;
closeRegionModal: () => void;
handleRegionSelect: (city: string, county: string) => void;
isDeleteModalOpen: boolean;
closeDeleteModal: () => void;
handleDelete: () => void;
selectedRow: Slope | null;
isEditModalOpen: boolean;
closeEditModal: () => void;
handleEdit: (updatedSlope: Slope) => void;
}
import { TableModalProps } from '../../../interface';

const TableModals: React.FC<TableModalProps> = ({
isModalOpen,
Expand All @@ -33,6 +16,7 @@ const TableModals: React.FC<TableModalProps> = ({
closeDeleteModal,
handleDelete,
selectedRow,
selectedRows,
isEditModalOpen,
closeEditModal,
handleEdit,
Expand All @@ -49,6 +33,7 @@ const TableModals: React.FC<TableModalProps> = ({
isOpen={isDeleteModalOpen}
onClose={closeDeleteModal}
onConfirm={handleDelete}
selectedRows={selectedRows}
selectedRow={selectedRow}
/>
<EditModal
Expand Down
Loading
Loading