iipbs_cs #1

Merged
chanii8 merged 5 commits from iipbs_cs into main 2025-03-06 11:56:33 +09:00
6 changed files with 180 additions and 4 deletions
Showing only changes of commit cea526d7ce - Show all commits
+2 -1
View File
@@ -12,7 +12,8 @@
"@common/assets": "workspace:*",
"@common/components": "workspace:*",
"@tanstack/react-table": "^8.21.2",
"next": "15.1.7"
"next": "15.1.7",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
@@ -0,0 +1,164 @@
"use client";
import { useState } from "react";
import {
Dialog,
DialogTrigger,
Button,
DialogContent,
DialogHeader,
DialogTitle,
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
Input,
RadioGroup,
RadioGroupItem,
Checkbox,
} from "@common/components";
type IP = {
id: number;
ipAddress: string;
allowed: boolean;
};
function IPManagementDialog() {
const [rows, setRows] = useState<IP[]>([]);
const [rowSelection, setRowSelection] = useState<IP["id"][]>([]);
const handleSave = () => {};
const handleAddIP = () => {
const newIP: IP = {
id: Date.now(),
ipAddress: "",
allowed: true,
};
setRows([...rows, newIP]);
};
const handleDeleteIP = () => {
const filteredRows = rows.filter((row) => !rowSelection.includes(row.id));
setRows(filteredRows);
setRowSelection([]);
};
const handleIPAddressChange = (id: number, value: string) => {
setRows(
rows.map((row) => (row.id === id ? { ...row, ipAddress: value } : row)),
);
};
const handleAllowedChange = (id: number, value: boolean) => {
setRows(
rows.map((row) => (row.id === id ? { ...row, allowed: value } : row)),
);
};
const toggleRowSelection = (id: number) => {
setRowSelection((prev) => {
if (prev.includes(id)) {
return prev.filter((item) => item !== id);
} else {
return [...prev, id];
}
});
};
return (
<Dialog>
<DialogTrigger asChild>
<Button>IP 관리</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[600px]">
<DialogHeader>
<DialogTitle>IP 관리</DialogTitle>
</DialogHeader>
<div className="mb-4 flex justify-end gap-2">
<Button size="sm" color="green">
엑셀 업로드
</Button>
<Button size="sm" onClick={handleSave}>
저장
</Button>
<Button size="sm" color="white" onClick={handleAddIP}>
항목 추가
</Button>
<Button
size="sm"
color="red"
onClick={handleDeleteIP}
disabled={rowSelection.length === 0}
>
항목 삭제
</Button>
</div>
<div className="card card-border">
<Table>
<colgroup>
<col width="10%" />
<col width="10%" />
<col width="55%" />
<col width="25%" />
</colgroup>
<TableHeader>
<TableRow>
<TableHead>NO</TableHead>
<TableHead>선택</TableHead>
<TableHead>IP 주소</TableHead>
<TableHead>허용여부</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rows.map((row, idx) => (
<TableRow key={row.id}>
<TableCell align="center">{idx + 1}</TableCell>
<TableCell align="center">
<Checkbox
checked={rowSelection.includes(row.id)}
onCheckedChange={() => toggleRowSelection(row.id)}
className="cursor-pointer"
/>
</TableCell>
<TableCell align="center">
<Input
value={row.ipAddress}
onChange={(e) =>
handleIPAddressChange(row.id, e.target.value)
}
className="!text-[1.3rem]"
/>
</TableCell>
<TableCell align="center">
<RadioGroup
value={row.allowed ? "true" : "false"}
onValueChange={(value) =>
handleAllowedChange(row.id, value === "true")
}
className="flex justify-center"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="true" id={`allow-${row.id}`} />
<label htmlFor={`allow-${row.id}`}>예</label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="false" id={`deny-${row.id}`} />
<label htmlFor={`deny-${row.id}`}>아니오</label>
</div>
</RadioGroup>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</DialogContent>
</Dialog>
);
}
export { IPManagementDialog };
+2 -2
View File
@@ -15,7 +15,7 @@ import {
TableRow,
} from "@common/components";
import { SitePageLayout } from "./layout";
import { IPManagementDialog } from "./ip-management-dialog";
function RegisterPage() {
return (
<SitePageLayout>
@@ -57,7 +57,7 @@ function RegisterPage() {
</DropdownMenuContent>
</DropdownMenu>
</DropdownMenu>
<Button>IP 관리</Button>
<IPManagementDialog />
</div>
</TableCell>
</TableRow>
+7 -1
View File
@@ -3,12 +3,18 @@
import "@common/assets/styles/grid.css";
import { useRouter } from "next/navigation";
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
import { Button, Input, DataTable } from "@common/components";
import { data, columns } from "../model/__mocks__";
import { SitePageLayout } from "./layout";
function SitePage() {
const router = useRouter();
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<SitePageLayout>
@@ -28,7 +34,7 @@ function SitePage() {
<Button onClick={() => router.push("/site/register")}>등록</Button>
</div>
<div className="card !m-[1.2rem] h-[49rem] overflow-auto !p-0">
<DataTable data={data} columns={columns} />
<DataTable table={table} />
</div>
</div>
</div>
+2
View File
@@ -1,4 +1,5 @@
import type { Config } from "tailwindcss";
import tailwindcssAnimate from "tailwindcss-animate";
import presetConfig from "../../tailwind.config.preset";
export default {
@@ -15,4 +16,5 @@ export default {
},
},
},
plugins: [tailwindcssAnimate],
} satisfies Config;
+3
View File
@@ -45,6 +45,9 @@ importers:
next:
specifier: 15.1.7
version: 15.1.7(react-dom@18.3.1)(react@18.3.1)
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.17)
devDependencies:
'@eslint/eslintrc':
specifier: ^3