[as] feat: 행정지원 업무 신청 시 시도/구군 선택 로직 추가
This commit is contained in:
@@ -2,11 +2,26 @@ import { DesignRegistPage } from "@/pages/design-cnstn";
|
||||
import { parseTaskSeComCdFromApi } from "@/pages/design-cnstn/lib/design-cnstn-regist-schema";
|
||||
|
||||
interface PageProps {
|
||||
searchParams: Promise<{ taskSeComCd?: string }>;
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = parseTaskSeComCdFromApi(params.taskSeComCd);
|
||||
return <DesignRegistPage taskSeComCd={taskSeComCd.length ? taskSeComCd : undefined} />;
|
||||
|
||||
return (
|
||||
<DesignRegistPage
|
||||
defaults={{
|
||||
taskSeComCd: taskSeComCd.length ? taskSeComCd : undefined,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,26 @@ import { FnrsRegistPage } from "@/pages/fnrs-cnsltn";
|
||||
import { parseTaskSeComCdFromApi } from "@/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema";
|
||||
|
||||
interface PageProps {
|
||||
searchParams: Promise<{ taskSeComCd?: string }>;
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: PageProps) {
|
||||
const params = await searchParams;
|
||||
const taskSeComCd = parseTaskSeComCdFromApi(params.taskSeComCd);
|
||||
return <FnrsRegistPage taskSeComCd={taskSeComCd.length ? taskSeComCd : undefined} />;
|
||||
|
||||
return (
|
||||
<FnrsRegistPage
|
||||
defaults={{
|
||||
taskSeComCd: taskSeComCd.length ? taskSeComCd : undefined,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { InstlRegistPage } from "@/pages/instl-sncn";
|
||||
|
||||
interface InstlSncnRegistRouteProps {
|
||||
searchParams: Promise<{ taskSeComCd?: string }>;
|
||||
searchParams: Promise<{
|
||||
taskSeComCd?: string;
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: InstlSncnRegistRouteProps) {
|
||||
@@ -10,5 +15,14 @@ export default async function Page({ searchParams }: InstlSncnRegistRouteProps)
|
||||
? params.taskSeComCd.split(",").filter(Boolean)
|
||||
: undefined;
|
||||
|
||||
return <InstlRegistPage taskSeComCd={taskSeComCd} />;
|
||||
return (
|
||||
<InstlRegistPage
|
||||
defaults={{
|
||||
taskSeComCd,
|
||||
admdstCd: params.admdstCd,
|
||||
sido: params.sido,
|
||||
gugun: params.gugun,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ async function findSidoCombo(): Promise<CmCdAdstDstrComboResponseDto[]> {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function findUserSidoCombo(): Promise<CmCdAdstDstrComboResponseDto[]> {
|
||||
const response = await client.get<CmCdAdstDstrComboResponseDto[]>(`${BASE}/user/sido`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function findGugunCombo(sido: string): Promise<CmCdAdstDstrComboResponseDto[]> {
|
||||
const response = await client.get<CmCdAdstDstrComboResponseDto[]>(`${BASE}/gugun`, {
|
||||
params: { sido },
|
||||
@@ -20,7 +25,16 @@ async function findGugunCombo(sido: string): Promise<CmCdAdstDstrComboResponseDt
|
||||
return response.data;
|
||||
}
|
||||
|
||||
async function findUserGugunCombo(sido: string): Promise<CmCdAdstDstrComboResponseDto[]> {
|
||||
const response = await client.get<CmCdAdstDstrComboResponseDto[]>(`${BASE}/user/gugun`, {
|
||||
params: { sido },
|
||||
});
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export const cmCdAdstDstrService = {
|
||||
findSidoCombo,
|
||||
findUserSidoCombo,
|
||||
findGugunCombo,
|
||||
findUserGugunCombo,
|
||||
} satisfies CmCdAdstDstrService;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { IUserInfo } from "@/shared/store";
|
||||
|
||||
import { cmCdAdstDstrService } from "./adstdstr-service";
|
||||
|
||||
@@ -13,6 +14,16 @@ export function useFindSidoCombo() {
|
||||
});
|
||||
}
|
||||
|
||||
export function useFindUserSidoCombo(userInfo?: IUserInfo | null) {
|
||||
const adstDstrCdByUser = userInfo?.laeSeCd?.substring(2, 4);
|
||||
return useQuery({
|
||||
queryKey: [...cmCdAdstDstrBaseKey, "findUserSidoCombo", adstDstrCdByUser ?? "all"],
|
||||
queryFn: () => cmCdAdstDstrService.findUserSidoCombo(),
|
||||
select: (data) =>
|
||||
adstDstrCdByUser ? data.filter((item) => item.adstDstrCd === adstDstrCdByUser) : data,
|
||||
});
|
||||
}
|
||||
|
||||
export function useFindGugunCombo(sido: string) {
|
||||
return useQuery({
|
||||
queryKey: [...cmCdAdstDstrBaseKey, "findGugunCombo", sido],
|
||||
@@ -20,3 +31,11 @@ export function useFindGugunCombo(sido: string) {
|
||||
enabled: Boolean(sido),
|
||||
});
|
||||
}
|
||||
|
||||
export function useFindUserGugunCombo(sido: string) {
|
||||
return useQuery({
|
||||
queryKey: [...cmCdAdstDstrBaseKey, "findUserGugunCombo", sido],
|
||||
queryFn: () => cmCdAdstDstrService.findUserGugunCombo(sido),
|
||||
enabled: Boolean(sido),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
export { cmCdAdstDstrService } from "./api/adstdstr-service";
|
||||
export { useFindGugunCombo, useFindSidoCombo } from "./api/queries";
|
||||
export {
|
||||
useFindGugunCombo,
|
||||
useFindSidoCombo,
|
||||
useFindUserGugunCombo,
|
||||
useFindUserSidoCombo,
|
||||
} from "./api/queries";
|
||||
export type {
|
||||
CmCdAdstDstrComboResponseDto,
|
||||
CmCdAdstDstrService,
|
||||
|
||||
@@ -7,5 +7,7 @@ export interface CmCdAdstDstrComboResponseDto {
|
||||
/** Controller public 메서드명·시그니처와 동일 */
|
||||
export interface CmCdAdstDstrService {
|
||||
findSidoCombo(): Promise<CmCdAdstDstrComboResponseDto[]>;
|
||||
findUserSidoCombo(): Promise<CmCdAdstDstrComboResponseDto[]>;
|
||||
findGugunCombo(sido: string): Promise<CmCdAdstDstrComboResponseDto[]>;
|
||||
findUserGugunCombo(sido: string): Promise<CmCdAdstDstrComboResponseDto[]>;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,12 @@ export function mapDetailToFormData(data: DesignCnstnMngDetResponseDto): DesignC
|
||||
|
||||
export function getCreateDefaultValues(
|
||||
userInfo: IUserInfo | null,
|
||||
taskSeComCd?: string[],
|
||||
options?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
},
|
||||
): DesignCnstnRegistFormData {
|
||||
return {
|
||||
designCnstnMng: {
|
||||
@@ -78,7 +83,7 @@ export function getCreateDefaultValues(
|
||||
bizBgngYr: "",
|
||||
bizEndYr: "",
|
||||
bizCn: "",
|
||||
taskSeComCd: taskSeComCd ?? [],
|
||||
taskSeComCd: options?.taskSeComCd ?? [],
|
||||
dsgnrNm: "",
|
||||
dsgnrTelno: "",
|
||||
dsgnrOgdpNm: "",
|
||||
@@ -87,6 +92,9 @@ export function getCreateDefaultValues(
|
||||
aplcntMblTelno: userInfo?.mphn ?? "",
|
||||
aplcntOgdpNm: userInfo?.ogdpSeNm ?? "",
|
||||
aplcntEmlAddr: userInfo?.email ?? "",
|
||||
admdstCd: options?.admdstCd ?? "",
|
||||
sido: options?.sido ?? "",
|
||||
gugun: options?.gugun ?? "",
|
||||
prgrsSttsComCd: "CV",
|
||||
atchFileGroupId: "",
|
||||
},
|
||||
|
||||
@@ -36,10 +36,15 @@ interface DesignFormPageProps {
|
||||
id?: string;
|
||||
mode: "create" | "edit";
|
||||
initialData?: DesignCnstnMngDetResponseDto;
|
||||
taskSeComCd?: string[];
|
||||
createDefaults?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function DesignFormPage({ id, mode, initialData, taskSeComCd }: DesignFormPageProps) {
|
||||
function DesignFormPage({ id, mode, initialData, createDefaults }: DesignFormPageProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
@@ -54,7 +59,7 @@ function DesignFormPage({ id, mode, initialData, taskSeComCd }: DesignFormPagePr
|
||||
defaultValues:
|
||||
isEditMode && initialData
|
||||
? mapDetailToFormData(initialData)
|
||||
: getCreateDefaultValues(userInfo, taskSeComCd),
|
||||
: getCreateDefaultValues(userInfo, createDefaults),
|
||||
});
|
||||
|
||||
function buildFormPayload(
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type DesignCnstnMngSearchDto,
|
||||
useDesignCnstnMngPage,
|
||||
} from "@/entities/design-cnstn";
|
||||
import { TaskSePickerDialog } from "@/widgets/pbadms-sprt";
|
||||
import { PbadmsTaskApplyDialog, type PbadmsTaskApplySelection } from "@/widgets/pbadms-sprt";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { formatTaskSeComCdForApi } from "../lib/design-cnstn-regist-schema";
|
||||
@@ -71,9 +71,15 @@ function DesignList({ searchParams, pagination, onPaginationChange }: DesignList
|
||||
},
|
||||
});
|
||||
|
||||
const handleConfirmTaskSe = (selectedCodes: string[]) => {
|
||||
const handleConfirm = (selection: PbadmsTaskApplySelection) => {
|
||||
setIsTaskSeDialogOpen(false);
|
||||
router.push(`/design-cnstn/regist?taskSeComCd=${formatTaskSeComCdForApi(selectedCodes)}`);
|
||||
const qs = new URLSearchParams({
|
||||
taskSeComCd: formatTaskSeComCdForApi(selection.selectedCodes),
|
||||
admdstCd: selection.admdstCd,
|
||||
sido: selection.sido,
|
||||
gugun: selection.gugun,
|
||||
});
|
||||
router.push(`/design-cnstn/regist?${qs}`);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -87,10 +93,10 @@ function DesignList({ searchParams, pagination, onPaginationChange }: DesignList
|
||||
</div>
|
||||
{tableComponent}
|
||||
</section>
|
||||
<TaskSePickerDialog
|
||||
<PbadmsTaskApplyDialog
|
||||
open={isTaskSeDialogOpen}
|
||||
onOpenChange={setIsTaskSeDialogOpen}
|
||||
onConfirm={handleConfirmTaskSe}
|
||||
onConfirm={handleConfirm}
|
||||
title="설계자문 신청"
|
||||
codeUpCd="CNFM"
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { DesignFormPage } from "./design-form-page";
|
||||
|
||||
interface DesignRegistPageProps {
|
||||
interface DesignRegistDefaults {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}
|
||||
|
||||
function DesignRegistPage({ taskSeComCd }: DesignRegistPageProps) {
|
||||
return <DesignFormPage mode="create" taskSeComCd={taskSeComCd} />;
|
||||
interface DesignRegistPageProps {
|
||||
defaults?: DesignRegistDefaults;
|
||||
}
|
||||
|
||||
function DesignRegistPage({ defaults }: DesignRegistPageProps) {
|
||||
return <DesignFormPage mode="create" createDefaults={defaults} />;
|
||||
}
|
||||
|
||||
export { DesignRegistPage };
|
||||
export type { DesignRegistDefaults };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
import { Field, FieldError, FieldGroup } from "@/shared/ui/field";
|
||||
import { findCodeLabel, useCodeList } from "@/entities/code";
|
||||
import { type BnsApplyData, BnsPickerDialog } from "@/widgets/bns-picker";
|
||||
@@ -21,10 +20,12 @@ import {
|
||||
import type { DesignCnstnRegistFormData } from "../../lib/design-cnstn-regist-schema";
|
||||
|
||||
function BasicInfoFormSection() {
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const { control, watch, setValue } = useFormContext<DesignCnstnRegistFormData>();
|
||||
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
||||
const taskSeComCd = watch("designCnstnMng.taskSeComCd");
|
||||
const localGovLabel = [watch("designCnstnMng.sido"), watch("designCnstnMng.gugun")]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
const { data: taskOptions } = useCodeList("CNFM");
|
||||
|
||||
function handleBnsSelect(data: BnsApplyData) {
|
||||
@@ -142,7 +143,7 @@ function BasicInfoFormSection() {
|
||||
<TableHead data-required>구분</TableHead>
|
||||
<TableCell>{taskSeComCdLabel}</TableCell>
|
||||
<TableHead>신청 지자체</TableHead>
|
||||
<TableCell>{userInfo?.instSeNm}</TableCell>
|
||||
<TableCell>{localGovLabel}</TableCell>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
</Table>
|
||||
|
||||
@@ -118,7 +118,12 @@ export function mapDetailToFormData(data: FnrsCnsltnMngDetResponseDto): FnrsCnsl
|
||||
|
||||
export function getCreateDefaultValues(
|
||||
userInfo: IUserInfo | null,
|
||||
taskSeComCd?: string[],
|
||||
options?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
},
|
||||
): FnrsCnsltnRegistFormData {
|
||||
return {
|
||||
fnrsCnsltnMng: {
|
||||
@@ -126,7 +131,7 @@ export function getCreateDefaultValues(
|
||||
bizBgngYr: "",
|
||||
bizEndYr: "",
|
||||
bizCn: "",
|
||||
taskSeComCd: taskSeComCd ?? [],
|
||||
taskSeComCd: options?.taskSeComCd ?? [],
|
||||
cfmtnBgtBizNo: "",
|
||||
bgtAplyYr: "",
|
||||
dsgnrNm: "",
|
||||
@@ -137,6 +142,9 @@ export function getCreateDefaultValues(
|
||||
aplcntMblTelno: userInfo?.mphn ?? "",
|
||||
aplcntOgdpNm: userInfo?.ogdpSeNm ?? "",
|
||||
aplcntEmlAddr: userInfo?.email ?? "",
|
||||
admdstCd: options?.admdstCd ?? "",
|
||||
sido: options?.sido ?? "",
|
||||
gugun: options?.gugun ?? "",
|
||||
prgrsSttsComCd: "SV",
|
||||
atchFileGroupId: "",
|
||||
sharAtchFileGroupId: "",
|
||||
|
||||
@@ -47,10 +47,15 @@ interface FnrsFormPageProps {
|
||||
id?: string;
|
||||
mode: "create" | "edit";
|
||||
initialData?: FnrsCnsltnMngDetResponseDto;
|
||||
taskSeComCd?: string[];
|
||||
createDefaults?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function FnrsFormPage({ id, mode, initialData, taskSeComCd }: FnrsFormPageProps) {
|
||||
function FnrsFormPage({ id, mode, initialData, createDefaults }: FnrsFormPageProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
@@ -73,7 +78,7 @@ function FnrsFormPage({ id, mode, initialData, taskSeComCd }: FnrsFormPageProps)
|
||||
defaultValues:
|
||||
isEditMode && initialData
|
||||
? mapDetailToFormData(initialData)
|
||||
: getCreateDefaultValues(userInfo, taskSeComCd),
|
||||
: getCreateDefaultValues(userInfo, createDefaults),
|
||||
});
|
||||
|
||||
function buildFormPayload(
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type FnrsCnsltnMngSearchDto,
|
||||
useFnrsCnsltnMngPage,
|
||||
} from "@/entities/fnrs-cnsltn";
|
||||
import { TaskSePickerDialog } from "@/widgets/pbadms-sprt";
|
||||
import { PbadmsTaskApplyDialog, type PbadmsTaskApplySelection } from "@/widgets/pbadms-sprt";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { formatTaskSeComCdForApi } from "../lib/fnrs-cnsltn-regist-schema";
|
||||
@@ -71,9 +71,15 @@ function FnrsList({ searchParams, pagination, onPaginationChange }: FnrsListProp
|
||||
},
|
||||
});
|
||||
|
||||
const handleConfirmTaskSe = (selectedCodes: string[]) => {
|
||||
const handleConfirm = (selection: PbadmsTaskApplySelection) => {
|
||||
setIsTaskSeDialogOpen(false);
|
||||
router.push(`/fnrs-cnsltn/regist?taskSeComCd=${formatTaskSeComCdForApi(selectedCodes)}`);
|
||||
const qs = new URLSearchParams({
|
||||
taskSeComCd: formatTaskSeComCdForApi(selection.selectedCodes),
|
||||
admdstCd: selection.admdstCd,
|
||||
sido: selection.sido,
|
||||
gugun: selection.gugun,
|
||||
});
|
||||
router.push(`/fnrs-cnsltn/regist?${qs}`);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -87,10 +93,10 @@ function FnrsList({ searchParams, pagination, onPaginationChange }: FnrsListProp
|
||||
</div>
|
||||
{tableComponent}
|
||||
</section>
|
||||
<TaskSePickerDialog
|
||||
<PbadmsTaskApplyDialog
|
||||
open={isTaskSeDialogOpen}
|
||||
onOpenChange={setIsTaskSeDialogOpen}
|
||||
onConfirm={handleConfirmTaskSe}
|
||||
onConfirm={handleConfirm}
|
||||
title="재원협의 신청"
|
||||
codeUpCd="FNRS"
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { FnrsFormPage } from "./fnrs-form-page";
|
||||
|
||||
interface FnrsRegistPageProps {
|
||||
interface FnrsRegistDefaults {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}
|
||||
|
||||
function FnrsRegistPage({ taskSeComCd }: FnrsRegistPageProps) {
|
||||
return <FnrsFormPage mode="create" taskSeComCd={taskSeComCd} />;
|
||||
interface FnrsRegistPageProps {
|
||||
defaults?: FnrsRegistDefaults;
|
||||
}
|
||||
|
||||
function FnrsRegistPage({ defaults }: FnrsRegistPageProps) {
|
||||
return <FnrsFormPage mode="create" createDefaults={defaults} />;
|
||||
}
|
||||
|
||||
export { FnrsRegistPage };
|
||||
export type { FnrsRegistDefaults };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { findCodeLabel, useCodeList } from "@/entities/code";
|
||||
import { type BnsApplyData, BnsPickerDialog } from "@/widgets/bns-picker";
|
||||
@@ -24,10 +23,12 @@ import {
|
||||
import type { FnrsCnsltnRegistFormData } from "../../lib/fnrs-cnsltn-regist-schema";
|
||||
|
||||
function BasicInfoFormSection() {
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const { control, watch, setValue } = useFormContext<FnrsCnsltnRegistFormData>();
|
||||
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
||||
const taskSeComCd = watch("fnrsCnsltnMng.taskSeComCd");
|
||||
const localGovLabel = [watch("fnrsCnsltnMng.sido"), watch("fnrsCnsltnMng.gugun")]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
const { data: taskOptions } = useCodeList("FNRS");
|
||||
const { data: rtlztnFcltOptions } = useCodeList("RTLZTNFCLTSE");
|
||||
const { data: rtlztnUsgOptions } = useCodeList("RTLZTNUSGSE");
|
||||
@@ -48,6 +49,12 @@ function BasicInfoFormSection() {
|
||||
return (
|
||||
<SectionCollapsible title="기본 정보">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[20rem]" data-required>
|
||||
@@ -141,7 +148,7 @@ function BasicInfoFormSection() {
|
||||
<TableHead data-required>구분</TableHead>
|
||||
<TableCell>{taskSeComCdLabel}</TableCell>
|
||||
<TableHead>신청 지자체</TableHead>
|
||||
<TableCell>{userInfo?.instSeNm}</TableCell>
|
||||
<TableCell>{localGovLabel}</TableCell>
|
||||
</TableRow>
|
||||
{taskSeComCd.includes("RE") && (
|
||||
<>
|
||||
|
||||
@@ -108,7 +108,12 @@ export function mapDetailToFormData(data: InstlSncnMngDetResponse): InstlSncnReg
|
||||
|
||||
export function getCreateDefaultValues(
|
||||
userInfo: IUserInfo | null,
|
||||
taskSeComCd?: string[],
|
||||
options?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
},
|
||||
): InstlSncnRegistFormData {
|
||||
return {
|
||||
instlSncnMng: {
|
||||
@@ -116,7 +121,7 @@ export function getCreateDefaultValues(
|
||||
bizBgngYr: "",
|
||||
bizEndYr: "",
|
||||
bizCn: "",
|
||||
taskSeComCd: taskSeComCd ?? [],
|
||||
taskSeComCd: options?.taskSeComCd ?? [],
|
||||
sncnSeComCd: "",
|
||||
dsgnrNm: "",
|
||||
dsgnrTelno: "",
|
||||
@@ -126,6 +131,9 @@ export function getCreateDefaultValues(
|
||||
aplcntMblTelno: userInfo?.mphn ?? "",
|
||||
aplcntOgdpNm: userInfo?.ogdpSeNm ?? "",
|
||||
aplcntEmlAddr: userInfo?.email ?? "",
|
||||
admdstCd: options?.admdstCd ?? "",
|
||||
sido: options?.sido ?? "",
|
||||
gugun: options?.gugun ?? "",
|
||||
prgrsSttsComCd: "SV",
|
||||
atchFileGroupId: "",
|
||||
},
|
||||
|
||||
@@ -39,10 +39,15 @@ interface InstlFormPageProps {
|
||||
id?: string;
|
||||
mode: "create" | "edit";
|
||||
initialData?: InstlSncnMngDetResponse;
|
||||
taskSeComCd?: string[];
|
||||
createDefaults?: {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
};
|
||||
}
|
||||
|
||||
function InstlFormPage({ id, mode, initialData, taskSeComCd }: InstlFormPageProps) {
|
||||
function InstlFormPage({ id, mode, initialData, createDefaults }: InstlFormPageProps) {
|
||||
const queryClient = useQueryClient();
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
@@ -58,7 +63,7 @@ function InstlFormPage({ id, mode, initialData, taskSeComCd }: InstlFormPageProp
|
||||
defaultValues:
|
||||
isEditMode && initialData
|
||||
? mapDetailToFormData(initialData)
|
||||
: getCreateDefaultValues(userInfo, taskSeComCd),
|
||||
: getCreateDefaultValues(userInfo, createDefaults),
|
||||
});
|
||||
|
||||
function buildFormPayload(
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
type InstlSncnMngSearchParams,
|
||||
useInstlSncnList,
|
||||
} from "@/entities/instl-sncn";
|
||||
import { TaskSePickerDialog } from "@/widgets/pbadms-sprt";
|
||||
import { PbadmsTaskApplyDialog, type PbadmsTaskApplySelection } from "@/widgets/pbadms-sprt";
|
||||
import { Button } from "@common/components";
|
||||
|
||||
import { formatTaskSeComCdForApi } from "../lib/instl-sncn-regist-schema";
|
||||
@@ -75,9 +75,15 @@ function InstlList({ searchParams, pagination, onPaginationChange }: InstlListPr
|
||||
setIsTaskSeDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmTaskSe = (selectedCodes: string[]) => {
|
||||
const handleConfirm = (selection: PbadmsTaskApplySelection) => {
|
||||
setIsTaskSeDialogOpen(false);
|
||||
router.push(`/instl-sncn/regist?taskSeComCd=${formatTaskSeComCdForApi(selectedCodes)}`);
|
||||
const qs = new URLSearchParams({
|
||||
taskSeComCd: formatTaskSeComCdForApi(selection.selectedCodes),
|
||||
admdstCd: selection.admdstCd,
|
||||
sido: selection.sido,
|
||||
gugun: selection.gugun,
|
||||
});
|
||||
router.push(`/instl-sncn/regist?${qs}`);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -91,10 +97,10 @@ function InstlList({ searchParams, pagination, onPaginationChange }: InstlListPr
|
||||
</div>
|
||||
{tableComponent}
|
||||
</section>
|
||||
<TaskSePickerDialog
|
||||
<PbadmsTaskApplyDialog
|
||||
open={isTaskSeDialogOpen}
|
||||
onOpenChange={setIsTaskSeDialogOpen}
|
||||
onConfirm={handleConfirmTaskSe}
|
||||
onConfirm={handleConfirm}
|
||||
title="설치인가 신청"
|
||||
codeUpCd="INSTL"
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { InstlFormPage } from "./instl-form-page";
|
||||
|
||||
interface InstlRegistPageProps {
|
||||
interface InstlRegistDefaults {
|
||||
taskSeComCd?: string[];
|
||||
admdstCd?: string;
|
||||
sido?: string;
|
||||
gugun?: string;
|
||||
}
|
||||
|
||||
function InstlRegistPage({ taskSeComCd }: InstlRegistPageProps) {
|
||||
return <InstlFormPage mode="create" taskSeComCd={taskSeComCd} />;
|
||||
interface InstlRegistPageProps {
|
||||
defaults?: InstlRegistDefaults;
|
||||
}
|
||||
|
||||
function InstlRegistPage({ defaults }: InstlRegistPageProps) {
|
||||
return <InstlFormPage mode="create" createDefaults={defaults} />;
|
||||
}
|
||||
|
||||
export { InstlRegistPage };
|
||||
export type { InstlRegistDefaults };
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import { useState } from "react";
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import { findCodeLabel, useCodeList } from "@/entities/code";
|
||||
import { type BnsApplyData, BnsPickerDialog } from "@/widgets/bns-picker";
|
||||
@@ -24,10 +23,12 @@ import {
|
||||
import type { InstlSncnRegistFormData } from "../../lib/instl-sncn-regist-schema";
|
||||
|
||||
function BasicInfoFormSection() {
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const { control, watch, setValue } = useFormContext<InstlSncnRegistFormData>();
|
||||
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
||||
const taskSeComCd = watch("instlSncnMng.taskSeComCd");
|
||||
const localGovLabel = [watch("instlSncnMng.sido"), watch("instlSncnMng.gugun")]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
function handleBnsSelect(data: BnsApplyData) {
|
||||
setValue("instlSncnMng.bizNm", data.bizNm);
|
||||
@@ -52,6 +53,12 @@ function BasicInfoFormSection() {
|
||||
return (
|
||||
<SectionCollapsible title="기본 정보">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[20rem]" data-required>
|
||||
@@ -145,7 +152,7 @@ function BasicInfoFormSection() {
|
||||
<TableHead data-required>구분</TableHead>
|
||||
<TableCell>{taskSeComCdLabel}</TableCell>
|
||||
<TableHead>신청 지자체</TableHead>
|
||||
<TableCell>{userInfo?.instSeNm}</TableCell>
|
||||
<TableCell>{localGovLabel}</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead data-required>사업구분</TableHead>
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import {
|
||||
type CmCdAdstDstrComboResponseDto,
|
||||
useFindGugunCombo,
|
||||
useFindSidoCombo,
|
||||
useFindUserGugunCombo,
|
||||
useFindUserSidoCombo,
|
||||
} from "@/entities/adstdstr";
|
||||
import { useCodeList } from "@/entities/code";
|
||||
import {
|
||||
@@ -50,13 +51,19 @@ interface SewerBscPlanApplyDialogProps {
|
||||
const EMPTY_ADST_LIST: CmCdAdstDstrComboResponseDto[] = [];
|
||||
|
||||
function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlanApplyDialogProps) {
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const [sidoComCd, setSidoComCd] = useState("");
|
||||
const [sggComCd, setSggComCd] = useState("");
|
||||
const [sewerBscPlanSeComCd, setSewerBscPlanSeComCd] = useState("");
|
||||
const [taskSeComCd, setTaskSeComCd] = useState("");
|
||||
|
||||
const { data: sidoData, isPending: isSidoPending } = useFindSidoCombo();
|
||||
const { data: gugunData, isPending: isGugunPending } = useFindGugunCombo(sidoComCd);
|
||||
const sidoFilterUserInfo =
|
||||
userInfo?.dtlInstCd === "ROLE_USER04" || userInfo?.dtlInstCd === "ROLE_USER05"
|
||||
? userInfo
|
||||
: undefined;
|
||||
|
||||
const { data: sidoData, isPending: isSidoPending } = useFindUserSidoCombo(sidoFilterUserInfo);
|
||||
const { data: gugunData, isPending: isGugunPending } = useFindUserGugunCombo(sidoComCd);
|
||||
const { data: planSeOptions, isPending: isPlanSePending } = useCodeList("SEWERBSCPLANSE");
|
||||
const { data: taskSeOptions, isPending: isTaskSePending } = useCodeList("SEWER");
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ export { BusinessScaleFormSection } from "./ui/business-scale-form-section";
|
||||
export { ChecklistFormSection } from "./ui/checklist-form-section";
|
||||
export { ContactInfoFormSection } from "./ui/contact-info-form-section";
|
||||
export { FnrsSharFormSection } from "./ui/fnrs-shar-form-section";
|
||||
export {
|
||||
PbadmsTaskApplyDialog,
|
||||
type PbadmsTaskApplySelection,
|
||||
} from "./ui/pbadms-task-apply-dialog";
|
||||
export { PrivacyConsentSection } from "./ui/privacy-consent-section";
|
||||
export { SectionCollapsible } from "./ui/section-collapsible";
|
||||
export {
|
||||
@@ -42,4 +46,3 @@ export {
|
||||
} from "./ui/splmnt-dmnd-dialog";
|
||||
export { type SplmntDmndFormItem, SplmntDmndFormSection } from "./ui/splmnt-dmnd-form-section";
|
||||
export { SupplementDemandSection } from "./ui/supplement-demand-section";
|
||||
export { TaskSePickerDialog } from "./ui/task-se-picker-dialog";
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { useUserStore } from "@/shared/lib";
|
||||
import { Field, FieldGroup, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||
import {
|
||||
type CmCdAdstDstrComboResponseDto,
|
||||
useFindUserGugunCombo,
|
||||
useFindUserSidoCombo,
|
||||
} from "@/entities/adstdstr";
|
||||
import { useCodeList } from "@/entities/code";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Skeleton,
|
||||
Table,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
|
||||
interface PbadmsTaskApplySelection {
|
||||
admdstCd: string;
|
||||
sido: string;
|
||||
gugun: string;
|
||||
selectedCodes: string[];
|
||||
}
|
||||
|
||||
interface PbadmsTaskApplyDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onConfirm: (selection: PbadmsTaskApplySelection) => void;
|
||||
title: string;
|
||||
codeUpCd?: string;
|
||||
}
|
||||
|
||||
const EMPTY_ADST_LIST: CmCdAdstDstrComboResponseDto[] = [];
|
||||
|
||||
function PbadmsTaskApplyDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
onConfirm,
|
||||
title,
|
||||
codeUpCd,
|
||||
}: PbadmsTaskApplyDialogProps) {
|
||||
const userInfo = useUserStore((state) => state.userInfo);
|
||||
const [sidoComCd, setSidoComCd] = useState("");
|
||||
const [sggComCd, setSggComCd] = useState("");
|
||||
const [selectedCodes, setSelectedCodes] = useState<string[]>([]);
|
||||
|
||||
const sidoFilterUserInfo =
|
||||
userInfo?.dtlInstCd === "ROLE_USER04" || userInfo?.dtlInstCd === "ROLE_USER05"
|
||||
? userInfo
|
||||
: undefined;
|
||||
|
||||
const { data: sidoData, isPending: isSidoPending } = useFindUserSidoCombo(sidoFilterUserInfo);
|
||||
const { data: gugunData, isPending: isGugunPending } = useFindUserGugunCombo(sidoComCd);
|
||||
const { data: taskOptions, isPending: isTaskSePending } = useCodeList(codeUpCd);
|
||||
|
||||
const sidoOptions = sidoData ?? EMPTY_ADST_LIST;
|
||||
const gugunOptions = gugunData ?? EMPTY_ADST_LIST;
|
||||
const isPending = isSidoPending || isTaskSePending;
|
||||
const canConfirm = Boolean(sidoComCd && selectedCodes.length > 0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setSidoComCd("");
|
||||
setSggComCd("");
|
||||
setSelectedCodes([]);
|
||||
}, [open]);
|
||||
|
||||
function handleCheckedChange(code: string, checked: boolean) {
|
||||
setSelectedCodes((prev) => {
|
||||
if (!checked) return prev.filter((value) => value !== code);
|
||||
if (code.includes("RE")) return [code];
|
||||
return [...prev.filter((value) => !value.includes("RE")), code];
|
||||
});
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
if (!canConfirm) return;
|
||||
|
||||
const sidoOption = sidoOptions.find((option) => option.adstDstrCd === sidoComCd);
|
||||
const gugunOption = gugunOptions.find((option) => option.adstDstrCd === sggComCd);
|
||||
|
||||
onConfirm({
|
||||
admdstCd: sggComCd || sidoComCd,
|
||||
sido: sidoOption?.adstDstrNm ?? "",
|
||||
gugun: gugunOption?.adstDstrNm ?? "",
|
||||
selectedCodes,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
{isPending ? (
|
||||
<Skeleton className="h-[16rem] w-full" />
|
||||
) : (
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
<col width="15%" />
|
||||
<col width="35%" />
|
||||
</colgroup>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead data-required>시도</TableHead>
|
||||
<TableCell>
|
||||
<Select
|
||||
value={sidoComCd || undefined}
|
||||
onValueChange={(value) => {
|
||||
setSidoComCd(value);
|
||||
setSggComCd("");
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{sidoOptions.map((option) => (
|
||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||
{option.adstDstrNm}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableHead>시군구</TableHead>
|
||||
<TableCell>
|
||||
<Select
|
||||
value={sggComCd || undefined}
|
||||
onValueChange={setSggComCd}
|
||||
disabled={!sidoComCd || isGugunPending}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{gugunOptions.map((option) => (
|
||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||
{option.adstDstrNm}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead data-required>업무구분</TableHead>
|
||||
<TableCell colSpan={3}>
|
||||
<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={`pbadms-task-apply-${option.lwpoCd}`}
|
||||
checked={selectedCodes.includes(option.lwpoCd)}
|
||||
onCheckedChange={(checked) =>
|
||||
handleCheckedChange(option.lwpoCd, checked === true)
|
||||
}
|
||||
/>
|
||||
<FieldLabel
|
||||
htmlFor={`pbadms-task-apply-${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 || !canConfirm}>
|
||||
확인
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export { PbadmsTaskApplyDialog };
|
||||
export type { PbadmsTaskApplySelection };
|
||||
@@ -1,117 +0,0 @@
|
||||
"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;
|
||||
title: string;
|
||||
codeUpCd?: string;
|
||||
}
|
||||
|
||||
function TaskSePickerDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
onConfirm,
|
||||
title,
|
||||
codeUpCd,
|
||||
}: TaskSePickerDialogProps) {
|
||||
const [selectedCodes, setSelectedCodes] = useState<string[]>([]);
|
||||
const { data: taskOptions, isPending } = useCodeList(codeUpCd);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
setSelectedCodes([]);
|
||||
}, [open]);
|
||||
|
||||
function handleCheckedChange(code: string, checked: boolean) {
|
||||
setSelectedCodes((prev) => {
|
||||
if (!checked) return prev.filter((value) => value !== code);
|
||||
if (code.includes("RE")) return [code];
|
||||
return [...prev.filter((value) => !value.includes("RE")), code];
|
||||
});
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
onConfirm(selectedCodes);
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{title}</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 };
|
||||
Reference in New Issue
Block a user