[as] feat: 설치인가 신청 시 업무구분 선택 팝업 추가
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
import { InstlRegistPage } from "@/pages/instl-sncn";
|
||||
|
||||
export default InstlRegistPage;
|
||||
interface InstlSncnRegistRouteProps {
|
||||
searchParams: Promise<{ taskSeComCd?: string }>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: InstlSncnRegistRouteProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = params.taskSeComCd
|
||||
? params.taskSeComCd.split(",").filter(Boolean)
|
||||
: undefined;
|
||||
|
||||
return <InstlRegistPage taskSeComCd={taskSeComCd} />;
|
||||
}
|
||||
|
||||
@@ -89,14 +89,17 @@ export function mapDetailToFormData(data: InstlSncnMngDetResponse): CnfmRegistFo
|
||||
};
|
||||
}
|
||||
|
||||
export function getCreateDefaultValues(userInfo: IUserInfo | null): CnfmRegistFormData {
|
||||
export function getCreateDefaultValues(
|
||||
userInfo: IUserInfo | null,
|
||||
taskSeComCd?: string[],
|
||||
): CnfmRegistFormData {
|
||||
return {
|
||||
instlSncnMng: {
|
||||
bizNm: "",
|
||||
bizBgngYr: "",
|
||||
bizEndYr: "",
|
||||
bizCn: "",
|
||||
taskSeComCd: [],
|
||||
taskSeComCd: taskSeComCd ?? [],
|
||||
sncnSeComCd: "",
|
||||
dsgnrNm: "",
|
||||
dsgnrTelno: "",
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { Field, FieldGroup, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { useCodeList } from "@/entities/code";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Skeleton,
|
||||
Table,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
|
||||
interface TaskSePickerDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onConfirm: (selectedCodes: string[]) => void;
|
||||
}
|
||||
|
||||
function TaskSePickerDialog({ open, onOpenChange, onConfirm }: TaskSePickerDialogProps) {
|
||||
const [selectedCodes, setSelectedCodes] = useState<string[]>([]);
|
||||
const { data: taskOptions, isPending } = useCodeList("INSTL");
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setSelectedCodes([]);
|
||||
}, [open]);
|
||||
|
||||
function handleCheckedChange(code: string, checked: boolean) {
|
||||
setSelectedCodes((prev) =>
|
||||
checked ? [...prev, code] : prev.filter((value) => value !== code),
|
||||
);
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
onConfirm(selectedCodes);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>설치인가 신청</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{isPending ? (
|
||||
<Skeleton className="h-[16rem] w-full" />
|
||||
) : (
|
||||
<Table variant="secondary">
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>업무구분</TableHead>
|
||||
<TableCell>
|
||||
<FieldSet className="px-2">
|
||||
<FieldGroup data-slot="checkbox-group" className="flex-row flex-wrap">
|
||||
{taskOptions?.map((option) => (
|
||||
<Field key={option.lwpoCd} orientation="horizontal" className="w-auto">
|
||||
<Checkbox
|
||||
id={`task-se-picker-${option.lwpoCd}`}
|
||||
checked={selectedCodes.includes(option.lwpoCd)}
|
||||
onCheckedChange={(checked) =>
|
||||
handleCheckedChange(option.lwpoCd, checked === true)
|
||||
}
|
||||
/>
|
||||
<FieldLabel
|
||||
htmlFor={`task-se-picker-${option.lwpoCd}`}
|
||||
className="font-normal"
|
||||
>
|
||||
{option.lwpoCdNm}
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
))}
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
</Table>
|
||||
)}
|
||||
|
||||
<DialogFooter>
|
||||
<Button type="button" color="white" onClick={() => onOpenChange(false)}>
|
||||
취소
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleConfirm}
|
||||
disabled={isPending || selectedCodes.length === 0}
|
||||
>
|
||||
확인
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export { TaskSePickerDialog };
|
||||
@@ -28,9 +28,10 @@ import { PrivacyConsentSection } from "./sections/privacy-consent-section";
|
||||
interface InstlFormPageProps {
|
||||
mode: "create" | "edit";
|
||||
initialData?: InstlSncnMngDetResponse;
|
||||
taskSeComCd?: string[];
|
||||
}
|
||||
|
||||
function InstlFormPage({ mode, initialData }: InstlFormPageProps) {
|
||||
function InstlFormPage({ mode, initialData, taskSeComCd }: InstlFormPageProps) {
|
||||
const router = useRouter();
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
@@ -43,7 +44,7 @@ function InstlFormPage({ mode, initialData }: InstlFormPageProps) {
|
||||
defaultValues:
|
||||
isEditMode && initialData
|
||||
? mapDetailToFormData(initialData)
|
||||
: getCreateDefaultValues(userInfo),
|
||||
: getCreateDefaultValues(userInfo, taskSeComCd),
|
||||
});
|
||||
|
||||
async function onSave(data: CnfmRegistFormData) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { getCoreRowModel, type PaginationState } from "@tanstack/react-table";
|
||||
@@ -11,6 +11,8 @@ import { Button } from "@common/components";
|
||||
|
||||
import { createInstlSncnColumns } from "../model/columns";
|
||||
|
||||
import { TaskSePickerDialog } from "./components/task-se-picker-dialog";
|
||||
|
||||
interface InstlListProps {
|
||||
searchParams: InstlSncnMngSearchParams;
|
||||
pagination: PaginationState;
|
||||
@@ -19,6 +21,7 @@ interface InstlListProps {
|
||||
|
||||
function InstlList({ searchParams, pagination, onPaginationChange }: InstlListProps) {
|
||||
const router = useRouter();
|
||||
const [isTaskSeDialogOpen, setIsTaskSeDialogOpen] = useState(false);
|
||||
|
||||
const queryParams = useMemo(
|
||||
() => ({
|
||||
@@ -55,19 +58,32 @@ function InstlList({ searchParams, pagination, onPaginationChange }: InstlListPr
|
||||
});
|
||||
|
||||
const handleRegisterClick = () => {
|
||||
router.push("/instl-sncn/regist");
|
||||
setIsTaskSeDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmTaskSe = (selectedCodes: string[]) => {
|
||||
setIsTaskSeDialogOpen(false);
|
||||
const query = selectedCodes.join(",");
|
||||
router.push(`/instl-sncn/regist?taskSeComCd=${query}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="card card-border mx-0 bg-background pb-8 pt-0">
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="text-2xl font-semibold">설치인가 목록</h3>
|
||||
<Button type="button" color="green" onClick={handleRegisterClick}>
|
||||
신청
|
||||
</Button>
|
||||
</div>
|
||||
{tableComponent}
|
||||
</section>
|
||||
<>
|
||||
<section className="card card-border mx-0 bg-background pb-8 pt-0">
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="text-2xl font-semibold">설치인가 목록</h3>
|
||||
<Button type="button" color="green" onClick={handleRegisterClick}>
|
||||
신청
|
||||
</Button>
|
||||
</div>
|
||||
{tableComponent}
|
||||
</section>
|
||||
<TaskSePickerDialog
|
||||
open={isTaskSeDialogOpen}
|
||||
onOpenChange={setIsTaskSeDialogOpen}
|
||||
onConfirm={handleConfirmTaskSe}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { InstlFormPage } from "./instl-form-page";
|
||||
|
||||
function InstlRegistPage() {
|
||||
return <InstlFormPage mode="create" />;
|
||||
interface InstlRegistPageProps {
|
||||
taskSeComCd?: string[];
|
||||
}
|
||||
|
||||
function InstlRegistPage({ taskSeComCd }: InstlRegistPageProps) {
|
||||
return <InstlFormPage mode="create" taskSeComCd={taskSeComCd} />;
|
||||
}
|
||||
|
||||
export { InstlRegistPage };
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { useCodeList } from "@/entities/code";
|
||||
import { findCodeLabel, useCodeList } from "@/entities/code";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
@@ -41,6 +41,12 @@ function BasicInfoFormSection() {
|
||||
const { data: rtlztnFcltOptions } = useCodeList("RTLZTNFCLTSE");
|
||||
const { data: rtlztnUsgOptions } = useCodeList("RTLZTNUSGSE");
|
||||
|
||||
const taskSeComCdLabel =
|
||||
taskSeComCd
|
||||
.map((code) => findCodeLabel(taskOptions, code))
|
||||
.filter(Boolean)
|
||||
.join(", ") || "-";
|
||||
|
||||
return (
|
||||
<SectionCollapsible title="기본 정보">
|
||||
<Table variant="secondary">
|
||||
@@ -139,36 +145,11 @@ function BasicInfoFormSection() {
|
||||
<Controller
|
||||
name="instlSncnMng.taskSeComCd"
|
||||
control={control}
|
||||
render={({ field, fieldState }) => (
|
||||
<FieldSet>
|
||||
<FieldGroup data-slot="checkbox-group" className="flex-row">
|
||||
{taskOptions?.map((option) => (
|
||||
<Field
|
||||
key={option.lwpoCd}
|
||||
orientation="horizontal"
|
||||
data-invalid={fieldState.invalid}
|
||||
className="w-auto"
|
||||
>
|
||||
<Checkbox
|
||||
id={`task-${option.lwpoCd}`}
|
||||
name={field.name}
|
||||
aria-invalid={fieldState.invalid}
|
||||
checked={field.value.includes(option.lwpoCd)}
|
||||
onCheckedChange={(checked) => {
|
||||
const newValue = checked
|
||||
? [...field.value, option.lwpoCd]
|
||||
: field.value.filter((value) => value !== option.lwpoCd);
|
||||
field.onChange(newValue);
|
||||
}}
|
||||
/>
|
||||
<FieldLabel htmlFor={`task-${option.lwpoCd}`} className="font-normal">
|
||||
{option.lwpoCdNm}
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
))}
|
||||
</FieldGroup>
|
||||
render={({ fieldState }) => (
|
||||
<Field data-invalid={fieldState.invalid}>
|
||||
<span>{taskSeComCdLabel}</span>
|
||||
<FieldError errors={[fieldState.error]} />
|
||||
</FieldSet>
|
||||
</Field>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
Reference in New Issue
Block a user