dm: 로그인 변경

This commit is contained in:
2026-07-14 16:48:08 +09:00
parent b336651503
commit 450de39f8c
5 changed files with 78 additions and 41 deletions
+12 -12
View File
@@ -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("");
+7 -2
View File
@@ -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 (
<StoreContext.Provider value={storeRef.current}>
{children}
@@ -39,4 +44,4 @@ export const useDmStore = <T,>(
}
return useStore(storeContext, selector)
}
}
+50 -3
View File
@@ -43,6 +43,20 @@ export const sdmInfoFormSchema = z.object({
export type SdmInfoFormData = z.infer<typeof sdmInfoFormSchema>;
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<boolean> =
}
}
const postSdmLoginData = async (data: DemandCompType) => {
const postSdmLoginData = async (data: DemandCompType): Promise<boolean> => {
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<void>;
insertSdmInfoData: (data: SdmInfoFormData) => Promise<boolean>;
updateSdmInfoData: (data: SdmInfoFormData) => Promise<boolean>;
getDemandCompList: (searchText: string, pageCnt: number) => Promise<void>;
actionLogin: (data: DemandCompType) => Promise<void>;
actionLogin: (data: DemandCompType) => Promise<boolean>;
getSdmInfoStatusList: (dmdInfoId: string) => Promise<void>;
getSimilarCaseList: (part: string, value: number | string) => Promise<void>;
actionLogout: () => Promise<void>;
@@ -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<boolean> => {
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,
}
}))
},
+8 -24
View File
@@ -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<MenuItem, "menuCd" | "menuKornNm" | "urlPath" | "newWndwYn">[] = [
{ 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<string | null>(null);
const [topMenus, setTopMenus] = useState<MenuItem[]>([]);
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 (
<button
key={item.menuCd}
@@ -149,7 +136,7 @@ export default function TopNav() {
{/* ✅ 우측: 로그인 버튼 / 로그인 정보 + 로그아웃 */}
<div className="flex items-center gap-3">
{!userName ? (
{!isLoggedIn ? (
<button
type="button"
onClick={openLogin}
@@ -197,10 +184,7 @@ export default function TopNav() {
<LoginModal
open={loginOpen}
onClose={() => setLoginOpen(false)}
onSuccess={({ userName: nextUserName }) => {
// localStorage.setItem(LS_USER_KEY, nextUserName);
// if (accessToken) localStorage.setItem(LS_TOKEN_KEY, accessToken);
setUserName(nextUserName);
onSuccess={() => {
setLoginOpen(false);
router.refresh();
}}
+1
View File
@@ -7,6 +7,7 @@
"build": "next build",
"start:dm": "next start -p 3015",
"lint": "next lint",
"dev:e2e": "next dev --port 3016",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed"
},