From 450de39f8c772a501536df2559a320950ac36775 Mon Sep 17 00:00:00 2001 From: ljpark Date: Tue, 14 Jul 2026 16:48:08 +0900 Subject: [PATCH] =?UTF-8?q?dm:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dm/app/(with-layout)/apply/dmdco/page.tsx | 24 ++++----- apps/dm/app/store/index.tsx | 9 +++- apps/dm/app/store/sdmMng/index.tsx | 53 +++++++++++++++++-- apps/dm/components/TopNav.tsx | 32 +++-------- apps/dm/package.json | 1 + 5 files changed, 78 insertions(+), 41 deletions(-) diff --git a/apps/dm/app/(with-layout)/apply/dmdco/page.tsx b/apps/dm/app/(with-layout)/apply/dmdco/page.tsx index 1edd73d3e..fb893c8fb 100644 --- a/apps/dm/app/(with-layout)/apply/dmdco/page.tsx +++ b/apps/dm/app/(with-layout)/apply/dmdco/page.tsx @@ -11,6 +11,7 @@ import PostcodeModal from "@/components/PostcodeModal"; import type { AddrItem } from "@/app/store/sdmMng/postcode-service"; import { useDmStore } from "@/app/store"; import { fetchType, getFetch, postFetch, putFetch } from "@/components/ui/api"; +import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; import { getCookie } from "@common/components/lib"; type Option = { value: string; label: string }; @@ -166,7 +167,7 @@ function Hr({ className = "" }: { className?: string }) { export default function DemandPlaceRegisterPage() { const router = useRouter(); - const { Common, initializeCommonData } = useDmStore((state) => state); + const { Common, initializeCommonData, actionLogin } = useDmStore((state) => state); const { selectSidoData, selectSigunData } = Common; const [editMode, setEditMode] = useState(false); @@ -444,21 +445,20 @@ export default function DemandPlaceRegisterPage() { alert("수요처 수정 완료!"); } else { - const response = await postFetch("/reuseFc/request", payload); - const responseJson = await response.json().catch(() => null); - const savedUser = responseJson?.data ?? payload; + await postFetch("/reuseFc/request", payload); - if (typeof window !== "undefined") { - const nextSessionUser = { - ...(sessionUser ?? {}), - ...savedUser, - }; - delete nextSessionUser.dmdAplyPswd; - sessionStorage.setItem("user", JSON.stringify(nextSessionUser)); + const loginSuccess = await actionLogin({ + dmdInfoId: fullDmdInfoId, + dmdAplyPswd: sha512.hex(password), + } as DemandCompType); + + if (!loginSuccess) { + alert("수요처 등록은 완료되었지만 자동 로그인에 실패하였습니다. 다시 로그인해 주세요."); + return; } alert("수요처 등록 완료!"); - router.push("/apply/dmdinfo"); // 수요정보등록 + router.push("/apply/dmdinfo"); } setPw(""); diff --git a/apps/dm/app/store/index.tsx b/apps/dm/app/store/index.tsx index 47170b3db..4291adfba 100644 --- a/apps/dm/app/store/index.tsx +++ b/apps/dm/app/store/index.tsx @@ -1,6 +1,6 @@ 'use client' -import { type ReactNode, createContext, useContext, useRef } from 'react' +import { type ReactNode, createContext, useContext, useEffect, useRef } from 'react' import { useStore } from 'zustand' import { type DmStore, StoreZus } from './store' @@ -23,6 +23,11 @@ export const StoreProvider = ({ // Create store instance if not initialized storeRef.current = StoreZus() as StoreApi } + + useEffect(() => { + storeRef.current?.getState().hydrateLoginUser(); + }, []) + return ( {children} @@ -39,4 +44,4 @@ export const useDmStore = ( } return useStore(storeContext, selector) -} \ No newline at end of file +} diff --git a/apps/dm/app/store/sdmMng/index.tsx b/apps/dm/app/store/sdmMng/index.tsx index c51209515..904c0a6b0 100644 --- a/apps/dm/app/store/sdmMng/index.tsx +++ b/apps/dm/app/store/sdmMng/index.tsx @@ -43,6 +43,20 @@ export const sdmInfoFormSchema = z.object({ export type SdmInfoFormData = z.infer; +export type LoginUser = { + dmdCoNm?: string; + dmdInfoId?: string; + dmdCoSn?: number; + zip?: string; + daddr?: string; + daddr2?: string; + telno?: string; + ctpvCd?: string; + sggCd?: string; + rgtr?: string; + [key: string]: unknown; +}; + const formatTelno = (telno?: string | null) => { const digits = (telno ?? '').replace(/\D/g, ''); @@ -512,7 +526,7 @@ const fetchUpdateSdmInfoData = async (data: SdmInfoFormData): Promise = } } -const postSdmLoginData = async (data: DemandCompType) => { +const postSdmLoginData = async (data: DemandCompType): Promise => { try { const res = await postFetch("/reuseFc/request/login", data); const jsonData = await res.json(); @@ -539,9 +553,23 @@ const postSdmLoginData = async (data: DemandCompType) => { } catch (error) { console.log(error); alert("수요처 로그인에 실패하였습니다."); + return false; } } +const getStoredLoginUser = (): LoginUser | null => { + if (typeof window === "undefined") return null; + + const sessionUser = sessionStorage.getItem("user"); + if (!sessionUser) return null; + + try { + return JSON.parse(sessionUser) as LoginUser; + } catch { + return null; + } +}; + const getDemandCompList = async (searchText: string, pageCnt: number) => { try { const url = '/reuseFc/request/' + (searchText ? searchText : '') + '/' + pageCnt; @@ -586,11 +614,12 @@ const fetchGetSimilarCaseList = async (part: string, value: number | string) => ====================================*/ export type SdmActions = { initializeSdmData: () => void; + hydrateLoginUser: () => void; insertSdmData: (data: DemandCompType) => Promise; insertSdmInfoData: (data: SdmInfoFormData) => Promise; updateSdmInfoData: (data: SdmInfoFormData) => Promise; getDemandCompList: (searchText: string, pageCnt: number) => Promise; - actionLogin: (data: DemandCompType) => Promise; + actionLogin: (data: DemandCompType) => Promise; getSdmInfoStatusList: (dmdInfoId: string) => Promise; getSimilarCaseList: (part: string, value: number | string) => Promise; actionLogout: () => Promise; @@ -616,6 +645,7 @@ export type SdmType = { // 로그인관련 successNextPage: boolean; successLogin: boolean; + loginUser: LoginUser | null; } } @@ -637,6 +667,7 @@ export const SdmState: SdmType = { // 로그인관련 successNextPage: false, successLogin: false, + loginUser: null, } } @@ -644,6 +675,15 @@ export const SdmReducer = (set: any): SdmActions => { return { initializeSdmData: async () => { }, + hydrateLoginUser: () => { + const loginUser = getStoredLoginUser(); + set((state: SdmType) => ({ + Sdm: { + ...state.Sdm, + loginUser, + } + })) + }, insertSdmData: async (data: DemandCompType) => { const preRes = await getSdmInfoStatusList(data.dmdInfoId); @@ -743,14 +783,20 @@ export const SdmReducer = (set: any): SdmActions => { })) }, - actionLogin: async (data: DemandCompType) => { + actionLogin: async (data: DemandCompType): Promise => { const loginSuccess = await postSdmLoginData(data); + const loginUser = loginSuccess ? getStoredLoginUser() : undefined; set((state: SdmType) => ({ Sdm: { ...state.Sdm, successLogin: loginSuccess, + loginUser: + loginSuccess + ? loginUser + : state.Sdm.loginUser, } })) + return loginSuccess; }, // 유사사례 조회 @@ -792,6 +838,7 @@ export const SdmReducer = (set: any): SdmActions => { Sdm: { ...state.Sdm, successLogin: false, + loginUser: null, } })) }, diff --git a/apps/dm/components/TopNav.tsx b/apps/dm/components/TopNav.tsx index 5e24ead78..741dbed2a 100644 --- a/apps/dm/components/TopNav.tsx +++ b/apps/dm/components/TopNav.tsx @@ -8,9 +8,6 @@ import LoginModal from "@/components/LoginModal"; import { fetchAnonymousMenu, isMenuActive, type MenuItem } from "@/app/store/common"; import { useDmStore } from "@/app/store"; -// const LS_TOKEN_KEY = "reuse_accessToken"; -const LS_USER_KEY = "user"; - const DEFAULT_NAV_ITEMS: Pick[] = [ { menuCd: 1, menuKornNm: "물 재이용 소개", urlPath: "/intro", newWndwYn: "N" }, { menuCd: 2, menuKornNm: "물 재이용 현황", urlPath: "/status", newWndwYn: "N" }, @@ -22,21 +19,11 @@ export default function TopNav() { const router = useRouter(); const pathname = usePathname(); - const { actionLogout } = useDmStore((state) => state); + const { actionLogout, Sdm } = useDmStore((state) => state); + const { loginUser } = Sdm; const [loginOpen, setLoginOpen] = useState(false); - const [userName, setUserName] = useState(null); const [topMenus, setTopMenus] = useState([]); - useEffect(() => { - const sessionUser = sessionStorage.getItem(LS_USER_KEY); - if (sessionUser) { - const parsed = JSON.parse(sessionUser) as { dmdCoNm?: string }; - setUserName(parsed.dmdCoNm ?? "수요처"); - } else { - setUserName(null); - } - }, []); - useEffect(() => { let isMounted = true; @@ -72,13 +59,13 @@ export default function TopNav() { otptYn: "Y", })); }, [topMenus]); + + const userName = loginUser?.dmdCoNm ?? null; + const isLoggedIn = Boolean(loginUser); const openLogin = () => setLoginOpen(true); const logout = async () => { - // localStorage.removeItem(LS_TOKEN_KEY); - // localStorage.removeItem(LS_USER_KEY); - setUserName(null); await actionLogout(); router.push("/main"); }; @@ -113,7 +100,7 @@ export default function TopNav() { active ? "text-sky-700" : "text-gray-800 hover:text-sky-700", ].join(" "); - if (requiresLogin && !userName) { + if (requiresLogin && !isLoggedIn) { return (