iipbs_cs #6
@@ -0,0 +1,2 @@
|
||||
import { RegisterPage } from "@/pages/site";
|
||||
export default RegisterPage;
|
||||
@@ -5,7 +5,7 @@
|
||||
@apply relative m-[0.6rem] box-border min-h-[2rem] rounded-[0.5rem] p-[0.6rem] text-[1.3rem] text-[#666];
|
||||
}
|
||||
.card-border {
|
||||
@apply shadow-blur border border-[#dbe2e6] bg-[rgba(255,255,255,0.6)];
|
||||
@apply border border-[#dbe2e6] bg-[rgba(255,255,255,0.6)] shadow-blur;
|
||||
}
|
||||
.card-header {
|
||||
@apply -mx-[0.6rem] flex items-center justify-between border-b border-b-[#e1e7eb] p-4;
|
||||
@@ -13,4 +13,13 @@
|
||||
.card-footer {
|
||||
@apply -mx-[0.6rem] mt-2 flex items-center justify-center border-t border-t-[#e1e7eb] py-4;
|
||||
}
|
||||
|
||||
[data-mode="dark"] {
|
||||
.card-border {
|
||||
@apply border-[#3f4042] bg-[rgba(255,255,255,0.065)];
|
||||
}
|
||||
.card-header {
|
||||
@apply border-b-[#3f4042];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ function CodeSelect({ upCd, defaultValue, ...props }: CodeSelectProps) {
|
||||
|
||||
return (
|
||||
<Select {...props}>
|
||||
<SelectTrigger className="w-[12rem] text-[1.3rem] text-label">
|
||||
<SelectTrigger className="w-[12rem]">
|
||||
<SelectValue placeholder={defaultValueText} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
Button,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
Input,
|
||||
Checkbox,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
DialogFooter,
|
||||
DialogClose,
|
||||
} from "@common/components";
|
||||
|
||||
export type Domain = {
|
||||
id: number;
|
||||
domainUrl: string;
|
||||
isRepresentative: boolean;
|
||||
isActive: "true" | "false";
|
||||
};
|
||||
|
||||
type DomainManagementDialogProps = {
|
||||
triggerDisabled?: boolean;
|
||||
handleSave: (rows: Domain[]) => void;
|
||||
};
|
||||
|
||||
function DomainManagementDialog({
|
||||
triggerDisabled,
|
||||
handleSave,
|
||||
}: DomainManagementDialogProps) {
|
||||
const [rows, setRows] = useState<Domain[]>([]);
|
||||
const [rowSelection, setRowSelection] = useState<Domain["id"][]>([]);
|
||||
|
||||
const onSave = () => {
|
||||
handleSave(rows);
|
||||
};
|
||||
|
||||
const handleAddDomain = () => {
|
||||
const newDomain: Domain = {
|
||||
id: Date.now(),
|
||||
domainUrl: "",
|
||||
isRepresentative: rows.length === 0,
|
||||
isActive: "true",
|
||||
};
|
||||
setRows([...rows, newDomain]);
|
||||
};
|
||||
|
||||
const handleDeleteDomain = () => {
|
||||
const filteredRows = rows.filter((row) => !rowSelection.includes(row.id));
|
||||
const hasRepresentative = filteredRows.some((row) => row.isRepresentative);
|
||||
|
||||
let updatedRows = filteredRows;
|
||||
if (!hasRepresentative && filteredRows.length > 0) {
|
||||
updatedRows = filteredRows.map((row, index) =>
|
||||
index === 0 ? { ...row, isRepresentative: true } : row,
|
||||
);
|
||||
}
|
||||
|
||||
setRows(updatedRows);
|
||||
setRowSelection([]);
|
||||
};
|
||||
|
||||
const handleDomainUrlChange = (id: number, value: string) => {
|
||||
setRows(
|
||||
rows.map((row) => (row.id === id ? { ...row, domainUrl: value } : row)),
|
||||
);
|
||||
};
|
||||
|
||||
const handleRepresentativeChange = (id: number) => {
|
||||
setRows(
|
||||
rows.map((row) => ({
|
||||
...row,
|
||||
isRepresentative: row.id === id,
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
const handleActiveChange = (id: number, value: "true" | "false") => {
|
||||
setRows(
|
||||
rows.map((row) => (row.id === id ? { ...row, isActive: 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 disabled={triggerDisabled}>도메인 관리</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[600px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>도메인 관리</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="mb-4 flex justify-end gap-2">
|
||||
<Button size="sm" color="white" onClick={handleAddDomain}>
|
||||
항목 추가
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteDomain}
|
||||
disabled={rowSelection.length === 0}
|
||||
>
|
||||
항목 삭제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="8%" />
|
||||
<col width="12%" />
|
||||
<col width="40%" />
|
||||
<col width="20%" />
|
||||
<col width="20%" />
|
||||
</colgroup>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>NO</TableHead>
|
||||
<TableHead>선택</TableHead>
|
||||
<TableHead>도메인URL</TableHead>
|
||||
<TableHead>대표URL</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.domainUrl}
|
||||
onChange={(e) =>
|
||||
handleDomainUrlChange(row.id, e.target.value)
|
||||
}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<Checkbox
|
||||
checked={row.isRepresentative}
|
||||
onCheckedChange={() => handleRepresentativeChange(row.id)}
|
||||
className="cursor-pointer"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<Select
|
||||
value={row.isActive}
|
||||
onValueChange={(value: "true" | "false") =>
|
||||
handleActiveChange(row.id, value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="mx-auto w-[100px]">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="true">예</SelectItem>
|
||||
<SelectItem value="false">아니오</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button size="lg" onClick={onSave}>
|
||||
저장
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export { DomainManagementDialog };
|
||||
@@ -18,6 +18,8 @@ import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
Checkbox,
|
||||
DialogFooter,
|
||||
DialogClose,
|
||||
} from "@common/components";
|
||||
|
||||
type IP = {
|
||||
@@ -34,7 +36,7 @@ function IPManagementDialog({ triggerDisabled }: IPManagementDialogProps) {
|
||||
const [rows, setRows] = useState<IP[]>([]);
|
||||
const [rowSelection, setRowSelection] = useState<IP["id"][]>([]);
|
||||
|
||||
const handleSave = () => {};
|
||||
const onSave = () => {};
|
||||
|
||||
const handleAddIP = () => {
|
||||
const newIP: IP = {
|
||||
@@ -86,9 +88,6 @@ function IPManagementDialog({ triggerDisabled }: IPManagementDialogProps) {
|
||||
<Button size="sm" color="green">
|
||||
엑셀 업로드
|
||||
</Button>
|
||||
<Button size="sm" onClick={handleSave}>
|
||||
저장
|
||||
</Button>
|
||||
<Button size="sm" color="white" onClick={handleAddIP}>
|
||||
항목 추가
|
||||
</Button>
|
||||
@@ -102,7 +101,7 @@ function IPManagementDialog({ triggerDisabled }: IPManagementDialogProps) {
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border">
|
||||
<Table>
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="10%" />
|
||||
<col width="10%" />
|
||||
@@ -160,6 +159,18 @@ function IPManagementDialog({ triggerDisabled }: IPManagementDialogProps) {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button size="lg" onClick={onSave}>
|
||||
저장
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -3,8 +3,8 @@ import { BaseLayout } from "@common/components";
|
||||
function SitePageLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<BaseLayout>
|
||||
<div className="h-auto min-h-full bg-[#f1f6f9]">
|
||||
<h2 className="px-[1.8rem] pt-[2rem] text-[2.4rem] font-semibold text-[#4c5e6f]">
|
||||
<div className="bg-container h-auto min-h-full">
|
||||
<h2 className="text-title px-[1.8rem] pt-[2rem] text-[2.4rem] font-semibold">
|
||||
사이트 관리
|
||||
</h2>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { SiteApi } from "@/entities/site";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import {
|
||||
@@ -19,25 +20,45 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { SitePageLayout } from "./layout";
|
||||
import { IPManagementDialog } from "./ip-management-dialog";
|
||||
import {
|
||||
DomainManagementDialog,
|
||||
type Domain,
|
||||
} from "./domain-management-dialog";
|
||||
import type { ISiteDetail } from "@/entities/site/model/site-interface";
|
||||
|
||||
type ViewState = Partial<ISiteDetail>;
|
||||
|
||||
function RegisterPage({ siteId }: { siteId: string }) {
|
||||
const router = useRouter();
|
||||
const { data: siteDetail } = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.SITES, siteId],
|
||||
queryFn: () => SiteApi.siteDetail(siteId),
|
||||
select: (data) => {
|
||||
setSiteKndCd(data.siteKndCd);
|
||||
handleViewStateChange("siteKndCd")(data.siteKndCd);
|
||||
handleViewStateChange("siteSkn")(data.siteSkn);
|
||||
return data;
|
||||
},
|
||||
enabled: !!siteId,
|
||||
});
|
||||
const [siteKndCd, setSiteKndCd] = useState<string>("");
|
||||
const [, setSiteSkinCd] = useState<string>("");
|
||||
|
||||
const [viewState, setViewState] = useState<ViewState>({});
|
||||
const [representativeDomain, setRepresentativeDomain] = useState<string>("");
|
||||
|
||||
const handleViewStateChange = (key: keyof ISiteDetail) => (value: string) => {
|
||||
setViewState({ ...viewState, [key]: value });
|
||||
};
|
||||
|
||||
const handleDomainSave = (rows: Domain[]) => {
|
||||
setRepresentativeDomain(
|
||||
rows.find((row) => row.isRepresentative)?.domainUrl || "",
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SitePageLayout>
|
||||
<div className="card card-border !mt-6">
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium text-[#666]">사이트 등록/수정</h3>
|
||||
<h3 className="text-2xl font-medium text-label">사이트 등록/수정</h3>
|
||||
</div>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
@@ -53,6 +74,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="w-[12rem] !text-[1.3rem]"
|
||||
defaultValue={siteDetail?.siteId}
|
||||
disabled={!!siteId}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("siteId")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -63,11 +87,13 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
<CodeSelect
|
||||
upCd="SITEKNDCD"
|
||||
defaultValue={siteDetail?.siteKndCd}
|
||||
onValueChange={(value) => {
|
||||
setSiteKndCd(value);
|
||||
}}
|
||||
onValueChange={handleViewStateChange("siteKndCd")}
|
||||
/>
|
||||
<IPManagementDialog triggerDisabled={siteKndCd === "O"} />
|
||||
{siteId && (
|
||||
<IPManagementDialog
|
||||
triggerDisabled={viewState.siteKndCd === "O"}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -77,9 +103,7 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
<CodeSelect
|
||||
upCd="SITESKINCD"
|
||||
defaultValue={siteDetail?.siteSkn}
|
||||
onValueChange={(value) => {
|
||||
setSiteSkinCd(value);
|
||||
}}
|
||||
onValueChange={handleViewStateChange("siteSkn")}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -90,6 +114,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트명을 입력하십시오."
|
||||
defaultValue={siteDetail?.siteNm}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("siteNm")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -100,9 +127,23 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 설명을 입력하십시오."
|
||||
defaultValue={siteDetail?.siteExpln}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("siteExpln")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow className={`${!siteId ? "hidden" : ""}`}>
|
||||
<TableHead>사이트 도메인</TableHead>
|
||||
<TableCell className="border">
|
||||
<div className="flex gap-2">
|
||||
<div className="bg-form h-[3.2rem] w-[21.5rem] cursor-not-allowed rounded-md border border-input px-3 py-2 text-[1.3rem] opacity-50">
|
||||
{representativeDomain}
|
||||
</div>
|
||||
<DomainManagementDialog handleSave={handleDomainSave} />
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 주소</TableHead>
|
||||
<TableCell className="border">
|
||||
@@ -110,6 +151,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 주소를 입력하십시오."
|
||||
defaultValue={siteDetail?.siteAddr}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("siteAddr")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -120,6 +164,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 전화번호를 입력하십시오."
|
||||
defaultValue={siteDetail?.telNo}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("telNo")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -130,6 +177,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 팩스번호를 입력하십시오."
|
||||
defaultValue={siteDetail?.faxNumber}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("faxNumber")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -140,6 +190,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 표기 내용을 입력하십시오. (ex. COPYRIGHT c 2013 KECO. ALL RIGHTS RESERVED.)"
|
||||
defaultValue={siteDetail?.lwndCn}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("lwndCn")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -150,6 +203,9 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="아이콘 파일 경로 및 파일명을 입력하여 주십시오."
|
||||
defaultValue={siteDetail?.bkmkIcon}
|
||||
onChange={(e) =>
|
||||
handleViewStateChange("bkmkIcon")(e.target.value)
|
||||
}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -157,18 +213,17 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
<TableHead>기본 사이트 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<RadioGroup
|
||||
name="basicSiteYn"
|
||||
defaultValue={siteDetail?.basicSiteYn}
|
||||
onValueChange={(value) => {
|
||||
console.log(value);
|
||||
}}
|
||||
onValueChange={handleViewStateChange("basicSiteYn")}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="default" id="r1" />
|
||||
<Label htmlFor="r1">예</Label>
|
||||
<RadioGroupItem value="Y" id="basicSiteY" />
|
||||
<Label htmlFor="basicSiteY">예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="comfortable" id="r2" />
|
||||
<Label htmlFor="r2">아니오</Label>
|
||||
<RadioGroupItem value="N" id="basicSiteN" />
|
||||
<Label htmlFor="basicSiteN">아니오</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</TableCell>
|
||||
@@ -177,18 +232,17 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
<TableHead>사용 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<RadioGroup
|
||||
name="useYn"
|
||||
defaultValue={siteDetail?.useYn}
|
||||
onValueChange={(value) => {
|
||||
console.log(value);
|
||||
}}
|
||||
onValueChange={handleViewStateChange("useYn")}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="default" id="r1" />
|
||||
<Label htmlFor="r1">사용</Label>
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="comfortable" id="r2" />
|
||||
<Label htmlFor="r2">사용안함</Label>
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">사용안함</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</TableCell>
|
||||
@@ -199,7 +253,7 @@ function RegisterPage({ siteId }: { siteId: string }) {
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button size="lg">저장</Button>
|
||||
<Button size="lg" color="white">
|
||||
<Button size="lg" color="white" onClick={() => router.back()}>
|
||||
취소
|
||||
</Button>
|
||||
<Button size="lg" color="red">
|
||||
|
||||
Reference in New Issue
Block a user