From 70b75eca33dc6e96e07eb954e05ed218ddd49579 Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 12 Mar 2025 15:57:02 +0900 Subject: [PATCH 1/9] =?UTF-8?q?style:=20=EA=B0=80=EB=A1=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A1=A4=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20height=20?= =?UTF-8?q?padding=ED=99=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/LoginPage/LoginPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/LoginPage/LoginPage.tsx b/src/pages/LoginPage/LoginPage.tsx index af3f5a0..848ab94 100644 --- a/src/pages/LoginPage/LoginPage.tsx +++ b/src/pages/LoginPage/LoginPage.tsx @@ -44,6 +44,8 @@ const Background = styled.div` display: flex; justify-content: center; align-items: center; + overflow-x: hidden; + padding: 10px 0px; `; const LogoContainer = styled.img` width: 100%; From 951a6308eae8deba8ed48c987d886fa129dc0a37 Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 12 Mar 2025 17:06:33 +0900 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=EA=B3=B5=ED=86=B5=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20zustand=EB=A1=9C=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 32 ++++++++++++++++++- package.json | 3 +- src/App.tsx | 2 ++ src/components/NotificationProvider.tsx | 41 +++++++++++++++++++++++++ src/hooks/notificationStore.ts | 37 ++++++++++++++++++++++ 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 src/components/NotificationProvider.tsx create mode 100644 src/hooks/notificationStore.ts diff --git a/package-lock.json b/package-lock.json index 1e61862..cfa0918 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,8 @@ "react-naver-maps": "^0.1.3", "react-router-dom": "^7.1.1", "react-table": "^7.8.0", - "styled-components": "^6.1.14" + "styled-components": "^6.1.14", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.17.0", @@ -4948,6 +4949,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index 983e7dd..412d05b 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "react-naver-maps": "^0.1.3", "react-router-dom": "^7.1.1", "react-table": "^7.8.0", - "styled-components": "^6.1.14" + "styled-components": "^6.1.14", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/src/App.tsx b/src/App.tsx index ee6efed..0863e18 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import Router from './Router'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import GlobalStyle from './styles/globalStyle'; import './styles/font.css'; +import { NotificationProvider } from './components/NotificationProvider'; function App() { const queryClient = new QueryClient(); return ( @@ -14,6 +15,7 @@ function App() { + ); } diff --git a/src/components/NotificationProvider.tsx b/src/components/NotificationProvider.tsx new file mode 100644 index 0000000..8ab24d0 --- /dev/null +++ b/src/components/NotificationProvider.tsx @@ -0,0 +1,41 @@ +import { useEffect } from 'react'; +import Snackbar from '@mui/material/Snackbar'; +import Alert from '@mui/material/Alert'; +import { useNotificationStore } from '../hooks/notificationStore'; + +export const NotificationProvider = () => { + const { isOpen, message, severity, autoHideDuration, hideNotification } = + useNotificationStore(); + + // 컴포넌트 언마운트 시 알림 초기화 (선택 사항) + useEffect(() => { + return () => { + if (isOpen) { + hideNotification(); + } + }; + }, []); + + const handleClose = ( + event?: React.SyntheticEvent | Event, + reason?: string + ) => { + if (reason === 'clickaway') { + return; + } + hideNotification(); + }; + + return ( + + + {message} + + + ); +}; diff --git a/src/hooks/notificationStore.ts b/src/hooks/notificationStore.ts new file mode 100644 index 0000000..b88ecce --- /dev/null +++ b/src/hooks/notificationStore.ts @@ -0,0 +1,37 @@ +import { create } from 'zustand'; +import { AlertColor } from '@mui/material/Alert'; + +interface NotificationState { + isOpen: boolean; + message: string; + severity: AlertColor; + autoHideDuration: number | null; + showNotification: ( + message: string, + options?: { + severity?: AlertColor; + autoHideDuration?: number | null; + } + ) => void; + hideNotification: () => void; +} + +export const useNotificationStore = create((set) => ({ + isOpen: false, + message: '', + severity: 'info', + autoHideDuration: 4000, + + showNotification: (message, options = {}) => + set({ + isOpen: true, + message, + severity: options.severity || 'info', + autoHideDuration: + options.autoHideDuration !== undefined + ? options.autoHideDuration + : 4000, + }), + + hideNotification: () => set({ isOpen: false }), +})); From c078ef13e0f364f958b3148303b004c3c1ab7ab3 Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 12 Mar 2025 17:07:21 +0900 Subject: [PATCH 3/9] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=8F=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20alert=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/LoginPage/LoginPage.tsx | 11 +++- src/pages/LoginPage/components/Join.tsx | 26 ++++++-- src/pages/LoginPage/components/Login.tsx | 78 ++++++++++++++---------- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/pages/LoginPage/LoginPage.tsx b/src/pages/LoginPage/LoginPage.tsx index 848ab94..c0e24d7 100644 --- a/src/pages/LoginPage/LoginPage.tsx +++ b/src/pages/LoginPage/LoginPage.tsx @@ -7,6 +7,7 @@ import Join from './components/Join'; const LoginPage = () => { const [isLogin, setIsLogin] = useState(true); + return ( @@ -30,7 +31,15 @@ const LoginPage = () => { - {isLogin ? : } + {isLogin ? ( + + ) : ( + { + setIsLogin(true); + }} + /> + )} ); diff --git a/src/pages/LoginPage/components/Join.tsx b/src/pages/LoginPage/components/Join.tsx index 842af09..3f3af72 100644 --- a/src/pages/LoginPage/components/Join.tsx +++ b/src/pages/LoginPage/components/Join.tsx @@ -5,8 +5,12 @@ import { authAPI, JoinFormType } from '../../../apis/Auth'; import styled from 'styled-components'; import PrivacyPolicyModal from '../../MapPage/components/map/PrivacyPolicyModal'; import TermsofUseModal from '../../MapPage/components/map/TermsofUseModal'; +import { useNotificationStore } from '../../../hooks/notificationStore'; -const Join = () => { +interface joinPropsType { + completeJoin: () => void; +} +const Join = ({ completeJoin }: joinPropsType) => { const [joinForm, setJoinForm] = useState({ name: '', phone: '', @@ -25,6 +29,10 @@ const Join = () => { const [agreementError, setAgreementError] = useState(false); const [isPrivacyPolicyOpen, setIsPrivacyPolicyOpen] = useState(false); const [isTermofUseOpen, setIsTermofUseOpen] = useState(false); + const showNotification = useNotificationStore( + (state) => state.showNotification + ); + const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; @@ -39,7 +47,7 @@ const Join = () => { [name]: value, })); } - console.log(joinForm); + // console.log(joinForm); }; const handlePwCheckChange = (e: React.ChangeEvent) => { @@ -84,7 +92,7 @@ const Join = () => { const joinMutation = useMutation({ mutationFn: (data: JoinFormType) => authAPI.join(data), onSuccess: () => { - alert('회원가입이 완료되었습니다.'); + showNotification('회원가입 성공!', { severity: 'success' }); setJoinForm({ name: '', phone: '', @@ -98,9 +106,13 @@ const Join = () => { terms: false, privacy: false, }); + completeJoin(); }, - onError: (error) => { - alert('회원가입에 실패했습니다. 다시 시도해주세요.'); + onError: (error: any) => { + const errorMes = + error.response?.data?.message || + '회원가입에 실패했습니다. 다시 시도해주세요.'; + showNotification(errorMes, { severity: 'error', autoHideDuration: 6000 }); console.error('join Error:', error); }, }); @@ -116,7 +128,9 @@ const Join = () => { if (pwVerfiy && isFormFilled && isAgreementsChecked) { joinMutation.mutate(joinForm); } else { - alert('정보를 정확히 입력하고 필수 약관에 동의해주세요.'); + showNotification('정보를 정확히 입력하고 필수 약관에 동의해주세요.', { + severity: 'error', + }); } }; diff --git a/src/pages/LoginPage/components/Login.tsx b/src/pages/LoginPage/components/Login.tsx index ffc4dba..f4f6809 100644 --- a/src/pages/LoginPage/components/Login.tsx +++ b/src/pages/LoginPage/components/Login.tsx @@ -3,6 +3,7 @@ import { useNavigate } from 'react-router-dom'; import { ErrorText, Input, InputWrapper, LoginButton } from './Style'; import { useMutation } from '@tanstack/react-query'; import { authAPI, LoginFormType } from '../../../apis/Auth'; +import { useNotificationStore } from '../../../hooks/notificationStore'; const Login = () => { const nav = useNavigate(); @@ -11,20 +12,29 @@ const Login = () => { password: '', }); const [isPhoneValid, setIsPhoneValid] = useState(true); - + const showNotification = useNotificationStore( + (state) => state.showNotification + ); const joinMutation = useMutation({ mutationFn: (data: LoginFormType) => authAPI.login(data), onSuccess: () => { - alert('로그인 성공'); + showNotification('로그인 성공!', { severity: 'success' }); setLoginForm({ phone: '', password: '', }); + nav('/manage/map'); }, - onError: (error) => { - alert('로그인에 실패했습니다. 다시 시도해주세요.'); - console.error('join Error:', error); + onError: (error: any) => { + const errorMes = + error.response?.data?.message || + '로그인에 실패했습니다. 다시 시도해주세요.'; + showNotification(errorMes, { + severity: 'error', + autoHideDuration: 6000, + }); + console.error('login Error:', error); }, }); @@ -58,34 +68,36 @@ const Login = () => { } }; return ( - - { - if (e.key === '-' || e.key === '+' || e.key === 'e') { - e.preventDefault(); - setIsPhoneValid(false); - setTimeout(() => setIsPhoneValid(true), 2000); - } - }} - /> - {!isPhoneValid && ( - "-"를 제외한 숫자만 입력해 주세요 - )} - - 로그인 - + <> + + { + if (e.key === '-' || e.key === '+' || e.key === 'e') { + e.preventDefault(); + setIsPhoneValid(false); + setTimeout(() => setIsPhoneValid(true), 2000); + } + }} + /> + {!isPhoneValid && ( + "-"를 제외한 숫자만 입력해 주세요 + )} + + 로그인 + + ); }; From ae0603872835558a1206995054ec1c746d8cb7ee Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Thu, 13 Mar 2025 17:37:08 +0900 Subject: [PATCH 4/9] =?UTF-8?q?style:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=8F=20=ED=9A=8C=EC=9B=90=EA=B4=80=EB=A6=AC=20alert=20->?= =?UTF-8?q?=20mui=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/LoginPage/components/Login.tsx | 2 +- src/pages/ManagePage/User/pages/UserLookUp.tsx | 12 ++++++++---- src/pages/ManagePage/User/pages/UserModi.tsx | 13 ++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/pages/LoginPage/components/Login.tsx b/src/pages/LoginPage/components/Login.tsx index f4f6809..33d0e84 100644 --- a/src/pages/LoginPage/components/Login.tsx +++ b/src/pages/LoginPage/components/Login.tsx @@ -45,7 +45,7 @@ const Login = () => { if (isFormFilled) { joinMutation.mutate(loginForm); } else { - alert('빈칸 없이 입력해주세요.'); + showNotification('빈칸 없이 입력해주세요', { severity: 'warning' }); } }; const handleChange = (e: React.ChangeEvent) => { diff --git a/src/pages/ManagePage/User/pages/UserLookUp.tsx b/src/pages/ManagePage/User/pages/UserLookUp.tsx index 7b9ffa2..3a8a7be 100644 --- a/src/pages/ManagePage/User/pages/UserLookUp.tsx +++ b/src/pages/ManagePage/User/pages/UserLookUp.tsx @@ -21,6 +21,7 @@ import Pagination from '../../components/Pagination'; import SearchRoundedIcon from '@mui/icons-material/SearchRounded'; import DoneRoundedIcon from '@mui/icons-material/DoneRounded'; import ClearRoundedIcon from '@mui/icons-material/ClearRounded'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; const columnHelper = createColumnHelper(); declare module '@tanstack/react-table' { @@ -31,15 +32,18 @@ declare module '@tanstack/react-table' { const UserLookUp = () => { const queryClient = useQueryClient(); + const showNotification = useNotificationStore( + (state) => state.showNotification + ); //승인API const ApproveMutation = useMutation({ mutationFn: (id: number) => userAPI.approveUser(id), onSuccess: () => { - alert('승인 성공'); + showNotification('승인 성공!', { severity: 'success' }); queryClient.invalidateQueries({ queryKey: ['users'] }); }, onError: (error) => { - alert('승인에 실패했습니다. 다시 시도해주세요.'); + showNotification('승인에 실패했습니다.', { severity: 'error' }); console.error('approve Error:', error); }, }); @@ -47,11 +51,11 @@ const UserLookUp = () => { const DeleteMutation = useMutation({ mutationFn: (id: number) => userAPI.deleteUser(id), onSuccess: () => { - alert('삭제 성공'); + showNotification('삭제 성공!', { severity: 'success' }); queryClient.invalidateQueries({ queryKey: ['users'] }); }, onError: (error) => { - alert('삭제에 실패했습니다. 다시 시도해주세요.'); + showNotification('삭제에 실패했습니다.', { severity: 'error' }); console.error('approve Error:', error); }, }); diff --git a/src/pages/ManagePage/User/pages/UserModi.tsx b/src/pages/ManagePage/User/pages/UserModi.tsx index 8a365bd..d3a4219 100644 --- a/src/pages/ManagePage/User/pages/UserModi.tsx +++ b/src/pages/ManagePage/User/pages/UserModi.tsx @@ -22,6 +22,7 @@ import EditModal from '../components/UserEditModal'; import SearchRoundedIcon from '@mui/icons-material/SearchRounded'; import EditRoundedIcon from '@mui/icons-material/EditRounded'; import DeleteForeverRoundedIcon from '@mui/icons-material/DeleteForeverRounded'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; const columnHelper = createColumnHelper(); @@ -33,16 +34,18 @@ declare module '@tanstack/react-table' { const UserModi = () => { const queryClient = useQueryClient(); - + const showNotification = useNotificationStore( + (state) => state.showNotification + ); //승인API const ModifyMutation = useMutation({ mutationFn: (Modiuser: User) => userAPI.modifyUser(Modiuser), onSuccess: () => { - alert('수정 성공'); + showNotification('수정 성공!', { severity: 'success' }); queryClient.invalidateQueries({ queryKey: ['users'] }); }, onError: (error) => { - alert('수정에 실패했습니다. 다시 시도해주세요.'); + showNotification('수정에 실패했습니다.', { severity: 'error' }); console.error('approve Error:', error); }, }); @@ -50,11 +53,11 @@ const UserModi = () => { const DeleteMutation = useMutation({ mutationFn: (id: number) => userAPI.deleteUser(id), onSuccess: () => { - alert('삭제 성공'); + showNotification('삭제 성공!', { severity: 'success' }); queryClient.invalidateQueries({ queryKey: ['users'] }); }, onError: (error) => { - alert('삭제에 실패했습니다. 다시 시도해주세요.'); + showNotification('삭제에 실패했습니다.', { severity: 'error' }); console.error('approve Error:', error); }, }); From ed74c6e89b04fc1a703a305f9ffdb1af082ee49e Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Thu, 13 Mar 2025 17:38:40 +0900 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=97=91=EC=85=80=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20rea?= =?UTF-8?q?ct-query=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20alert->=20?= =?UTF-8?q?mui=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StepSlope/pages/SteepSlopeLookUp.tsx | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/pages/ManagePage/StepSlope/pages/SteepSlopeLookUp.tsx b/src/pages/ManagePage/StepSlope/pages/SteepSlopeLookUp.tsx index 12e59aa..e4a8441 100644 --- a/src/pages/ManagePage/StepSlope/pages/SteepSlopeLookUp.tsx +++ b/src/pages/ManagePage/StepSlope/pages/SteepSlopeLookUp.tsx @@ -16,7 +16,11 @@ import { import { useVirtualizer } from '@tanstack/react-virtual'; import { FilterFn } from '@tanstack/react-table'; import { rankItem } from '@tanstack/match-sorter-utils'; -import { useInfiniteQuery, useQueryClient } from '@tanstack/react-query'; +import { + useInfiniteQuery, + useMutation, + useQueryClient, +} from '@tanstack/react-query'; import { Slope } from '../../../../apis/slopeMap'; import styled from 'styled-components'; @@ -34,6 +38,7 @@ import CachedRoundedIcon from '@mui/icons-material/CachedRounded'; import TravelExploreRoundedIcon from '@mui/icons-material/TravelExploreRounded'; import DownloadRoundedIcon from '@mui/icons-material/DownloadRounded'; import SearchRoundedIcon from '@mui/icons-material/SearchRounded'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; const FETCH_SIZE = 50; declare module '@tanstack/react-table' { @@ -96,7 +101,7 @@ const SteepSlopeLookUp = () => { initialPageParam: 0, }); - // //flatData를 통해 페이지 계산 + //flatData를 통해 페이지 계산 const flatData = useMemo(() => { return data?.pages.flatMap((page) => page.data) ?? []; }, [data]); @@ -530,16 +535,43 @@ const SteepSlopeLookUp = () => { } }; - const handleDownload = async () => { - try { - await slopeManageAPI.downloadExcel({ - searchQuery: searchQuery || undefined, - city: selectedRegion?.city, - county: selectedRegion?.county, + // 알림 함수 가져오기 + const showNotification = useNotificationStore( + (state) => state.showNotification + ); + + // 다운로드 mutation 설정 + const { mutate: downloadExcel, isPending: isDownloading } = useMutation({ + mutationFn: (params: { + searchQuery?: string; + city?: string; + county?: string; + }) => slopeManageAPI.downloadExcel(params), + + onSuccess: () => { + showNotification('엑셀 파일 다운로드가 완료되었습니다.', { + severity: 'success', + }); + }, + + onError: (error: any) => { + const errorMessage = + error.response?.data?.message || '다운로드에 실패했습니다.'; + showNotification(errorMessage, { + severity: 'error', + autoHideDuration: 6000, }); - } catch (error) { console.error('다운로드 실패:', error); - } + }, + }); + + // 다운로드 버튼 클릭 핸들러 + const handleDownload = () => { + downloadExcel({ + searchQuery: searchQuery || undefined, + city: selectedRegion?.city, + county: selectedRegion?.county, + }); }; return ( @@ -606,7 +638,7 @@ const SteepSlopeLookUp = () => { />

초기화

- + { color: '#24478f', }} /> -

다운로드

+

{isDownloading ? '다운로드 중...' : '엑셀 다운로드'}

From ef6daf21172033e24eab6696cc03713012151656 Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 19 Mar 2025 11:45:51 +0900 Subject: [PATCH 6/9] =?UTF-8?q?style:=20Map=20LeftModal=20width=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MapPage/components/map/LeftModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/MapPage/components/map/LeftModal.tsx b/src/pages/MapPage/components/map/LeftModal.tsx index 65ae1e1..dac076c 100644 --- a/src/pages/MapPage/components/map/LeftModal.tsx +++ b/src/pages/MapPage/components/map/LeftModal.tsx @@ -131,7 +131,7 @@ const ModalOverlay = styled.div` `; const LeftModalContainer = styled.div<{ $animationOpen: boolean }>` - width: 80%; + width: 70%; height: 100%; background-color: #fff; position: absolute; From 4add7561c61721bc7735bdb22ba40f3ccc72148c Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 19 Mar 2025 12:16:01 +0900 Subject: [PATCH 7/9] =?UTF-8?q?style:=20=EC=9D=B4=EC=9A=A9=EC=95=BD?= =?UTF-8?q?=EA=B4=80=20=EB=B0=8F=20=EA=B0=9C=EC=9D=B8=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=B3=B4=ED=98=B8=EB=B0=A9=EC=B9=A8=20=EB=AA=A8=EB=8B=AC=20mar?= =?UTF-8?q?gintop=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MapPage/components/map/PrivacyPolicyModal.tsx | 1 + src/pages/MapPage/components/map/TermsofUseModal.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/pages/MapPage/components/map/PrivacyPolicyModal.tsx b/src/pages/MapPage/components/map/PrivacyPolicyModal.tsx index 70cc8a8..c67c5ac 100644 --- a/src/pages/MapPage/components/map/PrivacyPolicyModal.tsx +++ b/src/pages/MapPage/components/map/PrivacyPolicyModal.tsx @@ -402,6 +402,7 @@ const ModalHeader = styled.div` top: 0; background-color: white; z-index: 10; + margin-top: 35px; `; const HeaderTitle = styled.h1` diff --git a/src/pages/MapPage/components/map/TermsofUseModal.tsx b/src/pages/MapPage/components/map/TermsofUseModal.tsx index ac7e950..3b5ae11 100644 --- a/src/pages/MapPage/components/map/TermsofUseModal.tsx +++ b/src/pages/MapPage/components/map/TermsofUseModal.tsx @@ -363,6 +363,7 @@ const ModalHeader = styled.div` top: 0; background-color: white; z-index: 10; + margin-top: 35px; `; const HeaderTitle = styled.h1` From 3ce689e57cffa3ebd0105a605ec9024174efa34d Mon Sep 17 00:00:00 2001 From: KimDoHyun Date: Wed, 19 Mar 2025 12:52:16 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=EC=97=91=EC=85=80=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EB=B0=8F=20=EC=BD=94=EB=A9=98=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EA=B4=80=EB=A0=A8=20alert=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/slopeManage.tsx | 1 - .../ManagePage/StepSlope/pages/SteepSlopeAdd.tsx | 15 ++++++++++++--- .../components/comment/CommentCreateModal.tsx | 7 ++++++- .../components/comment/CommentUpdateModal.tsx | 8 ++++++-- .../MapPage/components/map/DeleteIdModal.tsx | 8 +++++++- src/pages/MapPage/components/map/LeftModal.tsx | 8 ++++++-- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/apis/slopeManage.tsx b/src/apis/slopeManage.tsx index bd2070d..dcc8703 100644 --- a/src/apis/slopeManage.tsx +++ b/src/apis/slopeManage.tsx @@ -21,7 +21,6 @@ export const slopeManageAPI = { }, }); console.log('엑셀 업로드', response); - alert(`${response.data.message}\n${response.data.count}건 추가되었습니다.`); return response.data; }, createSlope: async (newSlope: Slope) => { diff --git a/src/pages/ManagePage/StepSlope/pages/SteepSlopeAdd.tsx b/src/pages/ManagePage/StepSlope/pages/SteepSlopeAdd.tsx index e0c649f..a6eb2df 100644 --- a/src/pages/ManagePage/StepSlope/pages/SteepSlopeAdd.tsx +++ b/src/pages/ManagePage/StepSlope/pages/SteepSlopeAdd.tsx @@ -5,6 +5,7 @@ import { slopeManageAPI } from '../../../../apis/slopeManage'; import AddSlope from '../components/AddSlopeContainer'; import { Slope } from '../../../../apis/slopeMap'; import CloudUploadRoundedIcon from '@mui/icons-material/CloudUploadRounded'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; interface FileInputContainerProps { $isDragActive?: boolean; $hasFile?: boolean; @@ -17,7 +18,10 @@ const SteepSlopeAdd: React.FC = () => { const [fileName, setFileName] = useState(''); const [isUploading, setIsUploading] = useState(false); const fileInputRef = useRef(null); - + //전역 알림 + const showNotification = useNotificationStore( + (state) => state.showNotification + ); // 드래그 시작 핸들러 const handleDragStart = (event: DragEvent): void => { event.preventDefault(); @@ -86,8 +90,10 @@ const SteepSlopeAdd: React.FC = () => { console.log('파일 업로드 시작:', uploadedFile); const formData = new FormData(); formData.append('file', uploadedFile); - await slopeManageAPI.uploadExcelSlope(formData); - + const data = await slopeManageAPI.uploadExcelSlope(formData); + showNotification(`${data.message}\n${data.count}건 추가되었습니다.`, { + severity: 'success', + }); // 업로드 성공 후 상태 초기화 setUploadedFile(null); setFileName(''); @@ -95,6 +101,9 @@ const SteepSlopeAdd: React.FC = () => { fileInputRef.current.value = ''; } } catch (error) { + showNotification('파일 업로드 오류', { + severity: 'error', + }); console.error('파일 업로드 오류:', error); } finally { setIsUploading(false); diff --git a/src/pages/MapPage/components/comment/CommentCreateModal.tsx b/src/pages/MapPage/components/comment/CommentCreateModal.tsx index a87240d..92825bb 100644 --- a/src/pages/MapPage/components/comment/CommentCreateModal.tsx +++ b/src/pages/MapPage/components/comment/CommentCreateModal.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; interface CommentAddModalProps { isOpen: boolean; @@ -29,6 +30,10 @@ const CommentAddModal = ({ }: CommentAddModalProps) => { const [comment, setComment] = useState(''); const [images, setImages] = useState([]); + //전역 알람 + const showNotification = useNotificationStore( + (state) => state.showNotification + ); const isReactNativeWebView = typeof window !== 'undefined' && window.ReactNativeWebView != null; //모달이 열릴 때 초기상태로 복원 @@ -141,7 +146,7 @@ const CommentAddModal = ({ } } } catch (error) { - alert(`React Native에서 오는 메시지 수신 useEffect\n${error}`); + showNotification('Error:', { severity: 'error' }); console.error('모바일 메시지 처리 오류:', error); } }; diff --git a/src/pages/MapPage/components/comment/CommentUpdateModal.tsx b/src/pages/MapPage/components/comment/CommentUpdateModal.tsx index 3535af8..314074c 100644 --- a/src/pages/MapPage/components/comment/CommentUpdateModal.tsx +++ b/src/pages/MapPage/components/comment/CommentUpdateModal.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; interface CommentUpdateModalProps { isOpen: boolean; @@ -46,7 +47,9 @@ const CommentUpdateModal = ({ ); const isReactNativeWebView = typeof window !== 'undefined' && window.ReactNativeWebView != null; - + const showNotification = useNotificationStore( + (state) => state.showNotification + ); // 모달이 열릴 때마다 초기 상태로 재설정 useEffect(() => { if (isOpen) { @@ -213,7 +216,8 @@ const CommentUpdateModal = ({ } } } catch (error) { - alert(`React Native에서 오는 메시지 수신 useEffect\n${error}`); + showNotification('Error:', { severity: 'error' }); + console.error('모바일 메시지 처리 오류:', error); } }; diff --git a/src/pages/MapPage/components/map/DeleteIdModal.tsx b/src/pages/MapPage/components/map/DeleteIdModal.tsx index 0df88d3..7a3b468 100644 --- a/src/pages/MapPage/components/map/DeleteIdModal.tsx +++ b/src/pages/MapPage/components/map/DeleteIdModal.tsx @@ -1,6 +1,7 @@ import styled from 'styled-components'; import { useState, useEffect } from 'react'; import { userAPI } from '../../../../apis/User'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; interface DeleteConfirmModalProps { isOpen: boolean; onClose: () => void; @@ -25,11 +26,16 @@ const DeleteIdModal = ({ isOpen, onClose }: DeleteConfirmModalProps) => { }; getUser(); }, []); - + const showNotification = useNotificationStore( + (state) => state.showNotification + ); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (inputValue === '회원탈퇴') { userAPI.selfDeleteUser(user!._id); + showNotification('회원탈퇴가 정상처리 되었습니다.', { + severity: 'success', + }); window.location.href = '/'; } }; diff --git a/src/pages/MapPage/components/map/LeftModal.tsx b/src/pages/MapPage/components/map/LeftModal.tsx index dac076c..ee93168 100644 --- a/src/pages/MapPage/components/map/LeftModal.tsx +++ b/src/pages/MapPage/components/map/LeftModal.tsx @@ -5,6 +5,7 @@ import DeleteIdModal from './DeleteIdModal'; import { userAPI } from '../../../../apis/User'; import TermsofUseModal from './TermsofUseModal'; import ArrowBackIcon from '@mui/icons-material/ArrowBackIosNewRounded'; +import { useNotificationStore } from '../../../../hooks/notificationStore'; interface LeftModalProps { isOpen: boolean; onClose: () => void; @@ -16,7 +17,10 @@ const LeftModal = ({ isOpen, onClose }: LeftModalProps) => { const [isPrivacyPolicyOpen, setIsPrivacyPolicyOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isTermofUseOpen, setIsTermofUseOpen] = useState(false); - + //전역 알람 + const showNotification = useNotificationStore( + (state) => state.showNotification + ); useEffect(() => { if (isOpen) setTimeout(() => setAnimationOpen(true), 10); else { @@ -44,7 +48,7 @@ const LeftModal = ({ isOpen, onClose }: LeftModalProps) => { localStorage.removeItem('_id'); localStorage.removeItem('isAdmin'); onClose(); - alert('로그아웃 되었습니다.'); + showNotification('로그아웃 되었습니다.', { severity: 'success' }); window.location.href = '/'; }; From 4a481a020923a9f12fefa60f970ade8589d9b42d Mon Sep 17 00:00:00 2001 From: Kimdohyun <115572203+kdhqwe1030@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:55:34 +0900 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20event=EB=A7=A4=EA=B0=9C=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=5F=EB=A5=BC=20=ED=86=B5=ED=95=9C=20eslint=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EB=AC=B4=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/NotificationProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/NotificationProvider.tsx b/src/components/NotificationProvider.tsx index 8ab24d0..88a4066 100644 --- a/src/components/NotificationProvider.tsx +++ b/src/components/NotificationProvider.tsx @@ -17,7 +17,7 @@ export const NotificationProvider = () => { }, []); const handleClose = ( - event?: React.SyntheticEvent | Event, + _event?: React.SyntheticEvent | Event, reason?: string ) => { if (reason === 'clickaway') {