diff --git a/apps/as/app/(with-base-layout)/design-cnstn/regist/page.tsx b/apps/as/app/(with-base-layout)/design-cnstn/regist/page.tsx index 567b634d5..4b57da09a 100644 --- a/apps/as/app/(with-base-layout)/design-cnstn/regist/page.tsx +++ b/apps/as/app/(with-base-layout)/design-cnstn/regist/page.tsx @@ -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 ; + + return ( + + ); } diff --git a/apps/as/app/(with-base-layout)/fnrs-cnsltn/regist/page.tsx b/apps/as/app/(with-base-layout)/fnrs-cnsltn/regist/page.tsx index 4360a6979..6af4150ed 100644 --- a/apps/as/app/(with-base-layout)/fnrs-cnsltn/regist/page.tsx +++ b/apps/as/app/(with-base-layout)/fnrs-cnsltn/regist/page.tsx @@ -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 ; + + return ( + + ); } diff --git a/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx b/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx index 476d0b7c2..ff047fd96 100644 --- a/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx +++ b/apps/as/app/(with-base-layout)/instl-sncn/regist/page.tsx @@ -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 ; + return ( + + ); } diff --git a/apps/as/src/entities/adstdstr/api/adstdstr-service.ts b/apps/as/src/entities/adstdstr/api/adstdstr-service.ts index b4bb11fae..f282ea67b 100644 --- a/apps/as/src/entities/adstdstr/api/adstdstr-service.ts +++ b/apps/as/src/entities/adstdstr/api/adstdstr-service.ts @@ -13,6 +13,11 @@ async function findSidoCombo(): Promise { return response.data; } +async function findUserSidoCombo(): Promise { + const response = await client.get(`${BASE}/user/sido`); + return response.data; +} + async function findGugunCombo(sido: string): Promise { const response = await client.get(`${BASE}/gugun`, { params: { sido }, @@ -20,7 +25,16 @@ async function findGugunCombo(sido: string): Promise { + const response = await client.get(`${BASE}/user/gugun`, { + params: { sido }, + }); + return response.data; +} + export const cmCdAdstDstrService = { findSidoCombo, + findUserSidoCombo, findGugunCombo, + findUserGugunCombo, } satisfies CmCdAdstDstrService; diff --git a/apps/as/src/entities/adstdstr/api/queries.ts b/apps/as/src/entities/adstdstr/api/queries.ts index 353e25cfe..2556ec6db 100644 --- a/apps/as/src/entities/adstdstr/api/queries.ts +++ b/apps/as/src/entities/adstdstr/api/queries.ts @@ -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), + }); +} diff --git a/apps/as/src/entities/adstdstr/index.ts b/apps/as/src/entities/adstdstr/index.ts index da1dbd132..2fffe5a79 100644 --- a/apps/as/src/entities/adstdstr/index.ts +++ b/apps/as/src/entities/adstdstr/index.ts @@ -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, diff --git a/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts b/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts index 72cb673dc..1eaa14bff 100644 --- a/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts +++ b/apps/as/src/entities/adstdstr/model/adstdstr-interface.ts @@ -7,5 +7,7 @@ export interface CmCdAdstDstrComboResponseDto { /** Controller public 메서드명·시그니처와 동일 */ export interface CmCdAdstDstrService { findSidoCombo(): Promise; + findUserSidoCombo(): Promise; findGugunCombo(sido: string): Promise; + findUserGugunCombo(sido: string): Promise; } diff --git a/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts b/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts index a34888317..9ba03d856 100644 --- a/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/design-cnstn/lib/form-data-mapper.ts @@ -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: "", }, diff --git a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx index 6c09a5320..63d4eda75 100644 --- a/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx +++ b/apps/as/src/pages/design-cnstn/ui/design-form-page.tsx @@ -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( diff --git a/apps/as/src/pages/design-cnstn/ui/design-list.tsx b/apps/as/src/pages/design-cnstn/ui/design-list.tsx index 8a0986379..a23f2e9ea 100644 --- a/apps/as/src/pages/design-cnstn/ui/design-list.tsx +++ b/apps/as/src/pages/design-cnstn/ui/design-list.tsx @@ -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 {tableComponent} - diff --git a/apps/as/src/pages/design-cnstn/ui/design-regist-page.tsx b/apps/as/src/pages/design-cnstn/ui/design-regist-page.tsx index fa8130898..54f1738d1 100644 --- a/apps/as/src/pages/design-cnstn/ui/design-regist-page.tsx +++ b/apps/as/src/pages/design-cnstn/ui/design-regist-page.tsx @@ -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 ; +interface DesignRegistPageProps { + defaults?: DesignRegistDefaults; +} + +function DesignRegistPage({ defaults }: DesignRegistPageProps) { + return ; } export { DesignRegistPage }; +export type { DesignRegistDefaults }; diff --git a/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx b/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx index 124370ddc..ded247b41 100644 --- a/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx +++ b/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx @@ -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(); 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() { 구분 {taskSeComCdLabel} 신청 지자체 - {userInfo?.instSeNm} + {localGovLabel} diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts b/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts index 82707757d..d30765961 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/form-data-mapper.ts @@ -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: "", diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx index 76c42f38f..e85efd562 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-form-page.tsx @@ -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( diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-list.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-list.tsx index dd9c2292e..6f584074d 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-list.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-list.tsx @@ -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 {tableComponent} - diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-regist-page.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-regist-page.tsx index 20c5f48b7..c2ea5b819 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-regist-page.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/fnrs-regist-page.tsx @@ -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 ; +interface FnrsRegistPageProps { + defaults?: FnrsRegistDefaults; +} + +function FnrsRegistPage({ defaults }: FnrsRegistPageProps) { + return ; } export { FnrsRegistPage }; +export type { FnrsRegistDefaults }; diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx index 4b85c4f93..751312ac6 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx @@ -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(); 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 ( + + + + + + @@ -141,7 +148,7 @@ function BasicInfoFormSection() { 구분 {taskSeComCdLabel} 신청 지자체 - {userInfo?.instSeNm} + {localGovLabel} {taskSeComCd.includes("RE") && ( <> diff --git a/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts b/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts index a0a36a298..a1e1242c5 100644 --- a/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts +++ b/apps/as/src/pages/instl-sncn/lib/form-data-mapper.ts @@ -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: "", }, diff --git a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx index 6cfd0f488..766712e35 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-form-page.tsx @@ -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( diff --git a/apps/as/src/pages/instl-sncn/ui/instl-list.tsx b/apps/as/src/pages/instl-sncn/ui/instl-list.tsx index c42978db3..e54b41578 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-list.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-list.tsx @@ -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 {tableComponent} - diff --git a/apps/as/src/pages/instl-sncn/ui/instl-regist-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-regist-page.tsx index 0b9472a15..509e9a7c5 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-regist-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-regist-page.tsx @@ -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 ; +interface InstlRegistPageProps { + defaults?: InstlRegistDefaults; +} + +function InstlRegistPage({ defaults }: InstlRegistPageProps) { + return ; } export { InstlRegistPage }; +export type { InstlRegistDefaults }; diff --git a/apps/as/src/pages/instl-sncn/ui/sections/basic-info-form-section.tsx b/apps/as/src/pages/instl-sncn/ui/sections/basic-info-form-section.tsx index 199ff6444..e9c8aa8b2 100644 --- a/apps/as/src/pages/instl-sncn/ui/sections/basic-info-form-section.tsx +++ b/apps/as/src/pages/instl-sncn/ui/sections/basic-info-form-section.tsx @@ -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(); 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 (
+ + + + + + @@ -145,7 +152,7 @@ function BasicInfoFormSection() { 구분 {taskSeComCdLabel} 신청 지자체 - {userInfo?.instSeNm} + {localGovLabel} 사업구분 diff --git a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-apply-dialog.tsx b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-apply-dialog.tsx index 38a8e85bf..9f64c25ac 100644 --- a/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-apply-dialog.tsx +++ b/apps/as/src/pages/sewer-bsc-plan/ui/sewer-bsc-plan-apply-dialog.tsx @@ -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"); diff --git a/apps/as/src/widgets/pbadms-sprt/index.ts b/apps/as/src/widgets/pbadms-sprt/index.ts index 9ace89ed1..ec019ee63 100644 --- a/apps/as/src/widgets/pbadms-sprt/index.ts +++ b/apps/as/src/widgets/pbadms-sprt/index.ts @@ -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"; diff --git a/apps/as/src/widgets/pbadms-sprt/ui/pbadms-task-apply-dialog.tsx b/apps/as/src/widgets/pbadms-sprt/ui/pbadms-task-apply-dialog.tsx new file mode 100644 index 000000000..9d753b276 --- /dev/null +++ b/apps/as/src/widgets/pbadms-sprt/ui/pbadms-task-apply-dialog.tsx @@ -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([]); + + 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 ( + + + + {title} + + + {isPending ? ( + + ) : ( +
+ + + + + + + + + 시도 + + + + 시군구 + + + + + + 업무구분 + +
+ + {taskOptions?.map((option) => ( + + + handleCheckedChange(option.lwpoCd, checked === true) + } + /> + + {option.lwpoCdNm} + + + ))} + +
+
+
+
+
+ )} + + + + + + + + ); +} + +export { PbadmsTaskApplyDialog }; +export type { PbadmsTaskApplySelection }; diff --git a/apps/as/src/widgets/pbadms-sprt/ui/task-se-picker-dialog.tsx b/apps/as/src/widgets/pbadms-sprt/ui/task-se-picker-dialog.tsx deleted file mode 100644 index 5e3998bdc..000000000 --- a/apps/as/src/widgets/pbadms-sprt/ui/task-se-picker-dialog.tsx +++ /dev/null @@ -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([]); - 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 ( - - - - {title} - - - {isPending ? ( - - ) : ( - - - - 업무구분 - -
- - {taskOptions?.map((option) => ( - - - handleCheckedChange(option.lwpoCd, checked === true) - } - /> - - {option.lwpoCdNm} - - - ))} - -
-
-
-
-
- )} - - - - - -
-
- ); -} - -export { TaskSePickerDialog };