iipbs_cs #1
@@ -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 };
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Generated
+3
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user