fix(sn): 조사관리 팝업 레이아웃과 등록 흐름 개선

This commit is contained in:
2026-08-20 17:14:07 +09:00
parent 7e3911dbd6
commit 71c5dfb8dd
4 changed files with 46 additions and 18 deletions
@@ -3,7 +3,10 @@
import LoadingOverlay from "@/components/ui/LoadingBar";
import { getStartYearArray } from "@/components/ui/YearRangeSelectBox";
import useStore from "@/store/useStore";
import { postPopupMessage } from "@/features/windowPopup/lib/popupMessage";
import {
postPopupMessage,
postPopupMessageAndClose,
} from "@/features/windowPopup/lib/popupMessage";
import { WINDOW_POPUP_MESSAGE_TYPE } from "@/features/windowPopup/model/types";
import {
StandardFormField,
@@ -319,19 +322,24 @@ export function ExmnBusinessRegisterPopupPage({
: await createExmnBusiness(request);
setSavedBusiness(persisted);
const popupPayload = {
exmnBizId: persisted.exmnBizId,
};
if (!isEditMode) {
postPopupMessageAndClose(
WINDOW_POPUP_MESSAGE_TYPE.EXMN_BUSINESS_CREATED,
popupPayload,
);
return;
}
postPopupMessage(
isEditMode
? WINDOW_POPUP_MESSAGE_TYPE.EXMN_BUSINESS_UPDATED
: WINDOW_POPUP_MESSAGE_TYPE.EXMN_BUSINESS_CREATED,
{
exmnBizId: persisted.exmnBizId,
},
WINDOW_POPUP_MESSAGE_TYPE.EXMN_BUSINESS_UPDATED,
popupPayload,
);
setNotice({
type: "success",
text: isEditMode
? "사업정보를 수정했습니다. 변경된 처리분구 기준으로 양식을 다시 받을 수 있습니다."
: "사업정보와 처리분구별 기본 요약행을 저장했습니다.",
text: "사업정보를 수정했습니다. 변경된 처리분구 기준으로 양식을 다시 받을 수 있습니다.",
});
} catch (error) {
setNotice({
@@ -447,7 +455,7 @@ export function ExmnBusinessRegisterPopupPage({
{notice && (
<div
role="alert"
className={`rounded-sm border px-4 py-3 text-[1.3rem] ${
className={`shrink-0 rounded-sm border px-4 py-3 text-[1.3rem] ${
notice.type === "error"
? "border-red-200 bg-red-50 text-red-700"
: notice.type === "success"
@@ -583,7 +591,7 @@ export function ExmnBusinessRegisterPopupPage({
</StandardFormField>
</StandardFormSection>
<section className="card card-border !m-0 min-h-0 overflow-hidden !p-[0.6rem]">
<section className="card card-border !m-0 min-h-0 shrink-0 overflow-hidden !p-[0.6rem]">
<div className="card-header flex min-h-[5.2rem] flex-wrap items-center justify-between gap-4">
<h2 className="text-2xl font-medium text-label">사업대상 처리분구</h2>
<div className="flex flex-wrap items-center justify-end gap-2">
@@ -98,6 +98,8 @@ export function ExmnRegistrationPage() {
const [selectedBusinessId, setSelectedBusinessId] = useState<string | null>(
null,
);
// 목록 행을 선택한 뒤 스크롤과 키보드 포커스를 함께 이동할 상세현황 영역이다.
const detailPanelRef = useRef<HTMLDivElement>(null);
const [isLoading, setIsLoading] = useState(false);
const [notice, setNotice] = useState<Notice>(null);
@@ -122,6 +124,17 @@ export function ExmnRegistrationPage() {
[businesses, selectedBusinessId],
);
/** 목록 행 선택 후 렌더링된 상세현황을 화면 상단으로 이동하고 포커스를 부여한다. */
const handleBusinessRowClick = (business: ExmnBusiness) => {
setSelectedBusinessId(business.exmnBizId);
window.requestAnimationFrame(() => {
const detailPanel = detailPanelRef.current;
if (!detailPanel) return;
detailPanel.scrollIntoView({ behavior: "smooth", block: "start" });
detailPanel.focus({ preventScroll: true });
});
};
/** 사업 목록의 숫자·행정구역·사업보고서 파일명을 표시 전용 값으로 변환한다. */
const businessRows = useMemo(
() =>
@@ -598,7 +611,7 @@ export function ExmnRegistrationPage() {
className={EXMN_TABLE_HEADER_CLASS}
scrollMode="horizontal"
minTableWidth="110rem"
onRowClick={(row) => setSelectedBusinessId(row.exmnBizId)}
onRowClick={handleBusinessRowClick}
actions={
<>
<Button
@@ -629,7 +642,14 @@ export function ExmnRegistrationPage() {
}
/>
</div>
<ExmnStatusDetailPanel business={selectedBusiness} />
<div
ref={detailPanelRef}
tabIndex={-1}
aria-label="조사 상세현황"
className="scroll-mt-[1.2rem] focus:outline-none"
>
<ExmnStatusDetailPanel business={selectedBusiness} />
</div>
</div>
);
}
@@ -432,7 +432,7 @@ export function ExmnResultRegisterPopupPage({
{notice && notice.type !== "success" && (
<div
role="alert"
className={`whitespace-pre-line rounded-sm border px-4 py-3 text-[1.3rem] ${
className={`shrink-0 whitespace-pre-line rounded-sm border px-4 py-3 text-[1.3rem] ${
notice.type === "error"
? "border-red-200 bg-red-50 text-red-700"
: "border-primary bg-primary-transparent text-primary"
@@ -472,7 +472,7 @@ export function ExmnResultRegisterPopupPage({
</StandardFormField>
</StandardFormSection>
<section className="overflow-hidden rounded-sm border border-border bg-background">
<section className="shrink-0 overflow-hidden rounded-sm border border-border bg-background">
<div
className="grid items-center gap-3 bg-primary px-3 py-3 text-center text-[1.3rem] font-semibold text-primary-foreground"
style={{ gridTemplateColumns: "180px minmax(0, 1fr) 80px 112px" }}
@@ -568,7 +568,7 @@ export function ExmnResultRegisterPopupPage({
{visibleValidationTypes.length > 0 && (
<section
className="overflow-hidden rounded-sm border border-border bg-background"
className="shrink-0 overflow-hidden rounded-sm border border-border bg-background"
aria-label="데이터 검토 내역"
>
<div className="flex items-center border-b border-border bg-container px-4 py-3">