diff --git a/AnimatedTabBar.js b/AnimatedTabBar.js new file mode 100644 index 0000000..4c9fe51 --- /dev/null +++ b/AnimatedTabBar.js @@ -0,0 +1,97 @@ +import React, { useRef } from 'react'; +import { View, TouchableOpacity, Animated, Text } from 'react-native'; +import Ionicons from '@expo/vector-icons/Ionicons'; +import { colors } from './constants/colors'; +import { styles } from './AnimatedTabBar.styles'; + +const TAB_ICONS = { + MainPage: 'home', + AccessStack: 'list', + MyPageStack: 'person-sharp', + AlertStack: 'notifications', +}; + +const TAB_LABELS = { + MainPage: '홈', + AccessStack: '출입 권한', + MyPageStack: '마이페이지', + AlertStack: '알림', +}; + +export default function AnimatedTabBar({ state, descriptors, navigation }) { + const scales = useRef(state.routes.map(() => new Animated.Value(1))).current; + const tilts = useRef(state.routes.map(() => new Animated.Value(0))).current; + + const onPress = (route, index, isFocused) => { + const event = navigation.emit({ + type: 'tabPress', + target: route.key, + canPreventDefault: true, + }); + // 포커스된 탭이 아니고, 이벤트가 취소되지 않았으면 해당 route로 이동 + if (!isFocused && !event.defaultPrevented) { + navigation.navigate(route.name); + } + Animated.parallel([ + // 크기 변화 + Animated.sequence([ + Animated.timing(scales[index], { toValue: 1.2, duration: 120, useNativeDriver: true }), + Animated.spring(scales[index], { toValue: 1, friction: 3, useNativeDriver: true }), + ]), + // 기울기 변화 + Animated.sequence([ + Animated.timing(tilts[index], { toValue: 1, duration: 150, useNativeDriver: true }), // 느리게(150ms) + Animated.timing(tilts[index], { toValue: -1, duration: 150, useNativeDriver: true }), // 느리게(150ms) + Animated.timing(tilts[index], { toValue: 0, duration: 100, useNativeDriver: true }), // 중앙으로 복귀 + ]), + ]).start(); + }; + + return ( + + {state.routes.map((route, index) => { + // 현재 탭이 포커스된 상태인지 확인 + const isFocused = state.index === index; + // 현재 탭의 아이콘과 레이블 설정 + const iconName = TAB_ICONS[route.name] || 'ellipse-outline'; + const label = TAB_LABELS[route.name] || route.name; + + return ( + onPress(route, index, isFocused)} + style={styles.tab} + activeOpacity={0.8} + > + + + + {label} + + ); + })} + + ); +} diff --git a/AnimatedTabBar.styles.js b/AnimatedTabBar.styles.js new file mode 100644 index 0000000..74a2a70 --- /dev/null +++ b/AnimatedTabBar.styles.js @@ -0,0 +1,50 @@ +import { StyleSheet } from 'react-native'; +import { colors } from './constants/colors'; + +export const styles = StyleSheet.create({ + tabBar: { + flexDirection: 'row', + height: 80, // 하단 탭 높이 + backgroundColor: colors.white, // 하단 탭 배경색 + // 테두리 반경 + borderTopLeftRadius: 24, + borderTopRightRadius: 24, + // 그림자 효과 + shadowColor: colors.black, + elevation: 8, + }, + tab: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + iconWrapper: { + backgroundColor: colors.white, + padding: 3, + borderRadius: 16, + marginBottom: 2, + alignItems: 'center', + justifyContent: 'center', + }, + iconWrapperActive: { + backgroundColor: colors.white, + padding: 3, + borderRadius: 8, + }, + icon: { + color: colors.lightGray, + }, + iconActive: { + color: colors.primary, + }, + label: { + fontSize: 13, + color: colors.lightGray, + fontWeight: 'bold', + marginTop: 2, + }, + labelActive: { + color: colors.darkGray, + fontWeight: 'bold', + }, +}); diff --git a/App.js b/App.js index adc90d6..1bf4a17 100644 --- a/App.js +++ b/App.js @@ -1,7 +1,13 @@ import AppNavigator from './AppNavigator'; +import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context'; const App = () => { - return ; + return ( + + + + + ); }; export default App; diff --git a/AppNavigator.js b/AppNavigator.js index 20c285b..694c329 100644 --- a/AppNavigator.js +++ b/AppNavigator.js @@ -1,12 +1,16 @@ import { NavigationContainer, DefaultTheme } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; -import { useState, useEffect } from 'react'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { useState, useEffect, useRef } from 'react'; import Ionicons from '@expo/vector-icons/Ionicons'; import { StatusBar } from 'react-native'; import HomeButtonController from './components/buttons/HomeButtonController'; import LoadingOverlay from './components/loadings/LoadingOverlay'; import { getMyInfo } from './apis/MyPageApi'; import { useAuthStore } from './stores/authStore'; +import { useModalStore } from './stores/modalStore'; +import PasswordConfirmModal from './modals/PasswordConfirmModal'; +import AnimatedTabBar from './AnimatedTabBar'; // 로그인 전 페이지 import WelcomePage from './pages/WelcomePage'; @@ -22,9 +26,88 @@ import AccessListPage from './pages/AccessListPage'; import MyAccessListPage from './pages/MyAccessListPage'; import AccessRequestPage from './pages/AccessRequestPage'; import AccessRequestRolePage from './pages/AccessRequestRolePage'; +import AlertList from './pages/AlertList'; import { colors } from './constants/colors'; const Stack = createStackNavigator(); +const Tab = createBottomTabNavigator(); + +// Tab 네비게이터 옵션 +const tabScreenOptions = ({ route }) => ({ + // tabBarIcon: ({ color, size }) => { + // let iconName; + // if (route.name === 'MainPage') iconName = 'home'; + // else if (route.name === 'MyPageStack') iconName = 'person-sharp'; + // else if (route.name === 'AccessStack') iconName = 'list'; + // else if (route.name === 'AlertStack') iconName = 'notifications'; + // else iconName = 'ellipse-outline'; + // return ; + // }, + // tabBarActiveTintColor: colors.secondary, + // tabBarInactiveTintColor: 'gray', + headerShown: false, +}); + +// Stack 네비게이터 옵션 +const screenOptions = { + headerStyle: { backgroundColor: colors.secondary, height: 100 }, + headerTintColor: colors.white, + headerTitleStyle: { fontWeight: '600', fontSize: 26 }, + headerTitleAlign: 'center', + gestureEnabled: true, + headerBackImage: () => , + headerBackTitle: '', +}; + +// 마이페이지 스택 네비게이터 +function MyPageStack() { + return ( + + + + + ); +} + +// 출입 권한 스택 네비게이터 +function AccessStack() { + return ( + + + + + + + ); +} + +function AlertStack() { + return ( + + + + ); +} export default function AppNavigator() { const { @@ -36,6 +119,16 @@ export default function AppNavigator() { setAccessToken, clearAccessToken, } = useAuthStore(); + + const showPasswordModal = useModalStore((state) => state.showPasswordModal); + // 네비게이션 객체에 직접 접근하기 위한 ref + const navigationRef = useRef(); + + const handleTabPress = (e, tabName) => { + e.preventDefault(); + const currentRoute = navigationRef.current?.getCurrentRoute(); + showPasswordModal(tabName, currentRoute?.name || 'MainPage'); + }; const [navState, setNavState] = useState(null); // 앱 시작 시 토큰 유효성 확인 @@ -74,77 +167,48 @@ export default function AppNavigator() { }; return ( - - + + ); } diff --git a/components/headers/WaveHeader.js b/components/headers/WaveHeader.js index a5f5f98..31abc14 100644 --- a/components/headers/WaveHeader.js +++ b/components/headers/WaveHeader.js @@ -4,11 +4,16 @@ import { Ionicons } from '@expo/vector-icons'; import { useNavigation } from '@react-navigation/native'; import { colors } from '../../constants/colors'; -const WaveHeader = () => { +const WaveHeader = ({ onBackPress }) => { const navigation = useNavigation(); const handleBackButton = () => { - navigation.goBack(); + if (onBackPress) { + // onBackPress가 전달된 경우 + onBackPress(); + } else { + navigation.goBack(); + } }; return ( diff --git a/modals/PasswordConfirmModal.js b/modals/PasswordConfirmModal.js index aaf3d9f..eeedcad 100644 --- a/modals/PasswordConfirmModal.js +++ b/modals/PasswordConfirmModal.js @@ -1,16 +1,25 @@ import { View, Text, Modal } from 'react-native'; -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { styles } from './styles/PasswordConfirmModal.styles'; import NormalInput from '../components/textinputs/NormalInput'; import NormalButton from '../components/buttons/NormalButton'; import WaveHeader from '../components/headers/WaveHeader'; import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; import { verifyPassword } from '../apis/PasswordApi'; +import { useModalStore } from '../stores/modalStore'; -const PasswordConfirmModal = ({ visible = true, onCloseHandler }) => { +const PasswordConfirmModal = ({ navigationRef }) => { + const { isPasswordModalVisible, pendingTab, prevTab, hidePasswordModal } = useModalStore(); const [password, setPassword] = useState(''); const [errorText, setErrorText] = useState(''); // NormalText ErrorText + useEffect(() => { + if (isPasswordModalVisible) { + setPassword(''); + setErrorText(''); + } + }, [isPasswordModalVisible]); + // 비밀번호 규칙 검사 핸들러 (8자 이상, 영문/숫자/특수문자 포함) const isValidPassword = (pw) => /^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*()_+{}\[\]:;<>,.?~\\/-]).{8,}$/.test(pw); @@ -31,17 +40,20 @@ const PasswordConfirmModal = ({ visible = true, onCloseHandler }) => { setErrorText('8자 이상, 영문/숫자/특수문자를 포함해야 합니다.'); return; } - try { await verifyPassword(password); - - // 모달창 닫기 - onCloseHandler(); + navigationRef.current?.navigate(pendingTab); + hidePasswordModal(); } catch (error) { console.log(error); setErrorText('비밀번호가 일치하지 않습니다. 다시 입력해주세요.'); } }; + + const onClosePasswordModal = () => { + hidePasswordModal(); + navigationRef.current?.navigate(prevTab); + }; // 모달 오류시 임시 코드 // const handleConfirm = async () => { // if (!isValidPassword(password)) { @@ -51,21 +63,26 @@ const PasswordConfirmModal = ({ visible = true, onCloseHandler }) => { // // 임시: 비밀번호가 'Lgcns01!'이면 성공, 아니면 실패 // if (password === 'Lgcns01!') { - // onCloseHandler(); // 성공 시 모달 닫기 + // navigationRef.current?.navigate(pendingTab); + // hidePasswordModal(); // } else { // setErrorText('비밀번호가 일치하지 않습니다. 다시 입력해주세요.'); // } // }; return ( - + - + 비밀번호 확인 개인정보 보호를 위해 비밀번호를 확인합니다. diff --git a/package-lock.json b/package-lock.json index d1d6f90..1c0f5b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,20 +10,23 @@ "dependencies": { "@react-native-async-storage/async-storage": "1.23.1", "@react-native-masked-view/masked-view": "0.3.2", + "@react-navigation/bottom-tabs": "^7.3.13", "@react-navigation/native": "^7.1.6", "@react-navigation/stack": "^7.2.10", "axios": "^1.9.0", "expo": "~52.0.46", + "expo-linear-gradient": "~14.0.2", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-native": "0.76.9", "react-native-awesome-alerts": "^2.0.0", "react-native-gesture-handler": "~2.20.2", "react-native-keyboard-aware-scroll-view": "^0.9.5", + "react-native-linear-gradient": "^2.8.3", "react-native-modal": "^14.0.0-rc.1", "react-native-qrcode-svg": "^6.3.15", "react-native-reanimated": "~3.16.1", - "react-native-safe-area-context": "^4.12.0", + "react-native-safe-area-context": "^4.14.1", "react-native-screens": "~4.4.0", "react-native-vector-icons": "^10.2.0", "zustand": "^5.0.4" @@ -3892,53 +3895,58 @@ } } }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.3.13.tgz", + "integrity": "sha512-J3MWXBJc3y6hefZNRqdj/JD4nzIDLzZL5GIYj89pR6oRf2Iibz9t1qV7yzxEc1KOaNDkXVZ/5U16PArEJFfykQ==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.4.2", + "color": "^4.2.3" + }, + "peerDependencies": { + "@react-navigation/native": "^7.1.9", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, "node_modules/@react-navigation/core": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.8.5.tgz", - "integrity": "sha512-xDUXs6NI6ASiZgf53I7NPG0iJVGClPL5O3r8ddOCkS6fhVmPRun64m2zxUWnPcxtheFNTFfQ1IXH+gcenTcv/w==", + "version": "7.9.2", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.9.2.tgz", + "integrity": "sha512-lqCyKMWWaSwGK4VV3wRXXEKvl5IKrVH207Kp77TLCnITnd4KQIdgjzzJ/Pr62ugki3VTAErq1vg0yRlcXciCbg==", "license": "MIT", "dependencies": { - "@react-navigation/routers": "^7.3.5", + "@react-navigation/routers": "^7.3.7", "escape-string-regexp": "^4.0.0", - "nanoid": "3.3.8", + "nanoid": "^3.3.11", "query-string": "^7.1.3", - "react-is": "^18.2.0", - "use-latest-callback": "^0.2.1", - "use-sync-external-store": "^1.2.2" + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.3", + "use-sync-external-store": "^1.5.0" }, "peerDependencies": { "react": ">= 18.2.0" } }, - "node_modules/@react-navigation/core/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" }, "node_modules/@react-navigation/elements": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.3.8.tgz", - "integrity": "sha512-2ZVBtPfrkmOxzvIyDu3fPZ6aS4HcXL+TvzPDGa1znY2OP1Llo6wH14AmJHQFDquiInp2656hRMM1BkfJ3yPwew==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.4.2.tgz", + "integrity": "sha512-cudKLsRtOB+i8iDzfBKypdqiHsDy1ruqCfYAtwKEclDmLsxu3/90YXoBtoPyFNyIpsn3GtsJzZsrYWQh78xSWg==", "license": "MIT", "dependencies": { "color": "^4.2.3" }, "peerDependencies": { "@react-native-masked-view/masked-view": ">= 0.2.0", - "@react-navigation/native": "^7.1.6", + "@react-navigation/native": "^7.1.9", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0" @@ -3950,65 +3958,29 @@ } }, "node_modules/@react-navigation/native": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.6.tgz", - "integrity": "sha512-XcfygfHDfAgf2iC4rNBc67Yy0M1aYRGNeNKqja5AJPFZoBQhAEAxKCwHsH4g3qU0zIbzLCthoSl5107dBjoeZw==", + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.9.tgz", + "integrity": "sha512-/A0oBwZIeD23o4jsnB0fEyKmKS+l4LAbJP/ioVvsGEubGp+sc5ouQNranOh7JwR0R1eX0MjcsLKprEwB+nztdw==", "license": "MIT", "dependencies": { - "@react-navigation/core": "^7.8.5", + "@react-navigation/core": "^7.9.2", "escape-string-regexp": "^4.0.0", "fast-deep-equal": "^3.1.3", - "nanoid": "3.3.8", - "use-latest-callback": "^0.2.1" + "nanoid": "^3.3.11", + "use-latest-callback": "^0.2.3" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*" } }, - "node_modules/@react-navigation/native/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/@react-navigation/routers": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.3.5.tgz", - "integrity": "sha512-SBh/3G7pURIQfIwG4OnAfLvq0E4+l1Ii6577z22cIhWIrTOHFXg0rMxC7ft/amzxYn+iG2nYa4dONRd+xIs+yg==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.3.7.tgz", + "integrity": "sha512-5ffgrefOs2zWqcCVX+OKn+RDx0puopQtxqetegFrTfWQ6pGXdY/5v4kBpPwaOFrNEeE/LPbHt9IJaJuvyhB7RA==", "license": "MIT", "dependencies": { - "nanoid": "3.3.8" - } - }, - "node_modules/@react-navigation/routers/node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "nanoid": "^3.3.11" } }, "node_modules/@react-navigation/stack": { @@ -6455,6 +6427,17 @@ "react": "*" } }, + "node_modules/expo-linear-gradient": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-14.0.2.tgz", + "integrity": "sha512-nvac1sPUfFFJ4mY25UkvubpUV/olrBH+uQw5k+beqSvQaVQiUfFtYzfRr+6HhYBNb4AEsOtpsCRkpDww3M2iGQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-modules-autolinking": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-2.0.8.tgz", @@ -10864,6 +10847,16 @@ "react-native": ">=0.48.4" } }, + "node_modules/react-native-linear-gradient": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz", + "integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-modal": { "version": "14.0.0-rc.1", "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-14.0.0-rc.1.tgz", @@ -10918,9 +10911,9 @@ } }, "node_modules/react-native-safe-area-context": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.12.0.tgz", - "integrity": "sha512-ukk5PxcF4p3yu6qMZcmeiZgowhb5AsKRnil54YFUUAXVIS7PJcMHGGC+q44fCiBg44/1AJk5njGMez1m9H0BVQ==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.14.1.tgz", + "integrity": "sha512-+tUhT5WBl8nh5+P+chYhAjR470iCByf9z5EYdCEbPaAK3Yfzw+o8VRPnUgmPAKlSccOgQBxx3NOl/Wzckn9ujg==", "license": "MIT", "peerDependencies": { "react": "*", diff --git a/package.json b/package.json index 8102387..1a5d1a6 100644 --- a/package.json +++ b/package.json @@ -11,20 +11,23 @@ "dependencies": { "@react-native-async-storage/async-storage": "1.23.1", "@react-native-masked-view/masked-view": "0.3.2", + "@react-navigation/bottom-tabs": "^7.3.13", "@react-navigation/native": "^7.1.6", "@react-navigation/stack": "^7.2.10", "axios": "^1.9.0", "expo": "~52.0.46", + "expo-linear-gradient": "~14.0.2", "expo-status-bar": "~2.0.1", "react": "18.3.1", "react-native": "0.76.9", "react-native-awesome-alerts": "^2.0.0", "react-native-gesture-handler": "~2.20.2", "react-native-keyboard-aware-scroll-view": "^0.9.5", + "react-native-linear-gradient": "^2.8.3", "react-native-modal": "^14.0.0-rc.1", "react-native-qrcode-svg": "^6.3.15", "react-native-reanimated": "~3.16.1", - "react-native-safe-area-context": "^4.12.0", + "react-native-safe-area-context": "^4.14.1", "react-native-screens": "~4.4.0", "react-native-vector-icons": "^10.2.0", "zustand": "^5.0.4" diff --git a/pages/AlertList.js b/pages/AlertList.js new file mode 100644 index 0000000..2ec3903 --- /dev/null +++ b/pages/AlertList.js @@ -0,0 +1,16 @@ +import React from 'react'; +import { View } from 'react-native'; +import MenuList from '../components/lists/MenuList'; + +const alertlist = [ + { label: '알림 제목 1', message: '알림 내용 1' }, + { label: '알림 재목 2', message: '알림 내용 2' }, +]; + +export default function AlertList() { + return ( + + + + ); +} diff --git a/pages/MainPage.js b/pages/MainPage.js index 75e4f3a..5e2d77d 100644 --- a/pages/MainPage.js +++ b/pages/MainPage.js @@ -131,10 +131,6 @@ const MainPage = () => { userVC={userVC} initialIndex={initialIndex >= 0 ? initialIndex : 0} // 처음 보여줄 카드 인덱스 /> - - - - ); }; diff --git a/pages/MyPage.js b/pages/MyPage.js index 0978053..1709457 100644 --- a/pages/MyPage.js +++ b/pages/MyPage.js @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { View, Text } from 'react-native'; import { styles } from './styles/MyPage.styles'; -import PasswordConfirmModal from '../modals/PasswordConfirmModal'; +// import PasswordConfirmModal from '../modals/PasswordConfirmModal'; import WaveHeader from '../components/headers/WaveHeader'; import NormalInput from '../components/textinputs/NormalInput'; import GrayButton from '../components/buttons/GrayButton'; @@ -12,8 +12,6 @@ import { useAuthStore } from '../stores/authStore'; export default function MyPage() { const { accessToken, clearAccessToken } = useAuthStore(); - const [isVerified, setIsVerified] = useState(false); // 비밀번호 인증 여부 - const [isModalVisible, setIsModalVisible] = useState(true); // Alert 관리 상태변수 const [showUpdatePasswordConfirmAlert, setShowUpdatePasswordConfirmAlert] = useState(false); @@ -31,27 +29,27 @@ export default function MyPage() { const navigation = useNavigation(); - // 인증 완료 시, 모달 창 닫음 - const handleCloseModal = async () => { - setIsModalVisible(false); - setIsVerified(true); - + useEffect(() => { // 회원 정보 불러오기 - try { - if (!accessToken) { - throw new Error('토큰이 존재하지 않습니다.'); + const fetchUserInfo = async () => { + try { + if (!accessToken) { + throw new Error('토큰이 존재하지 않습니다.'); + } + const data = await getMyInfo(); + setUserInfo({ + name: data.name, + birth: data.birthDate, + contact: data.contact, + email: data.email, + }); + } catch (error) { + console.log('내 정보 조회 실패:', error.response.data); } - const data = await getMyInfo(); - setUserInfo({ - name: data.name, - birth: data.birthDate, - contact: data.contact, - email: data.email, - }); - } catch (error) { - console.log('내 정보 조회 실패:', error.response.data); - } - }; + }; + + fetchUserInfo(); + }, [accessToken]); // 로그아웃 버튼 클릭 핸들러 const handleLogout = () => { @@ -115,71 +113,64 @@ export default function MyPage() { return ( - {/* 비밀번호 인증 완료 시, 본문 보이도록 설정 */} - {isVerified && ( - <> - - 마이 페이지 - - - - - - - | - - | - - - - setShowUpdatePasswordConfirmAlert(false)} - /> - - setShowDeleteUserConfirmAlert(false)} - /> - - - )} - - + + 마이 페이지 + + + + + + + | + + | + + + + setShowUpdatePasswordConfirmAlert(false)} + /> + + setShowDeleteUserConfirmAlert(false)} + /> + ); } diff --git a/stores/modalStore.js b/stores/modalStore.js new file mode 100644 index 0000000..11b539a --- /dev/null +++ b/stores/modalStore.js @@ -0,0 +1,21 @@ +import { create } from 'zustand'; + +export const useModalStore = create((set) => ({ + isPasswordModalVisible: false, + pendingTab: null, // 이동 시도한 탭 이름 + prevTab: '', // 이전 탭 이름 + showPasswordModal: (tabName, prevTab) => + set({ + isPasswordModalVisible: true, + pendingTab: tabName, + prevTab, + }), + hidePasswordModal: () => + set({ + isPasswordModalVisible: false, + pendingTab: null, + }), + // 일단 이건 킾 + //isVerified: false, + //setVerified: (verified) => set({ isVerified: verified }), +}));