From f7e80c9c38d679585d2d0dca1e94e0ba71821873 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Sun, 25 May 2025 22:54:31 +0900
Subject: [PATCH 1/5] =?UTF-8?q?KW-431/feat:=20=ED=95=98=EB=8B=A8=20?=
=?UTF-8?q?=ED=83=AD=20=EC=B6=94=EA=B0=80,=20=EC=8A=A4=ED=83=9D=20?=
=?UTF-8?q?=EB=B6=84=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AppNavigator.js | 166 +++++++++++++++++++++++++++-------------------
app.config.js | 2 +-
package-lock.json | 120 +++++++++++++--------------------
package.json | 1 +
pages/MainPage.js | 4 +-
5 files changed, 147 insertions(+), 146 deletions(-)
diff --git a/AppNavigator.js b/AppNavigator.js
index 20c285b..68e27e2 100644
--- a/AppNavigator.js
+++ b/AppNavigator.js
@@ -1,5 +1,6 @@
import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { useState, useEffect } from 'react';
import Ionicons from '@expo/vector-icons/Ionicons';
import { StatusBar } from 'react-native';
@@ -25,6 +26,75 @@ import AccessRequestRolePage from './pages/AccessRequestRolePage';
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-outline';
+ else if (route.name === 'MyPageStack') iconName = 'person-outline';
+ else if (route.name === 'AccessStack') iconName = 'list-outline';
+ 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 (
+
+
+
+
+
+
+ );
+}
export default function AppNavigator() {
const {
@@ -36,6 +106,7 @@ export default function AppNavigator() {
setAccessToken,
clearAccessToken,
} = useAuthStore();
+
const [navState, setNavState] = useState(null);
// 앱 시작 시 토큰 유효성 확인
@@ -75,76 +146,35 @@ export default function AppNavigator() {
return (
-
+
- ,
- headerBackTitle: '',
- }}
- >
- {isLoggedIn ? (
- <>
-
-
-
-
-
-
-
- >
- ) : (
- <>
-
-
-
-
- >
- )}
-
+ {isLoggedIn ? (
+
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ )}
);
}
diff --git a/app.config.js b/app.config.js
index 9b9e9d9..2dc863a 100644
--- a/app.config.js
+++ b/app.config.js
@@ -26,7 +26,7 @@ export default {
},
extra: {
//BASE_URL: 'http://keywe.site', // EKS 사용시
- BASE_URL: 'http://192.168.0.111:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
+ BASE_URL: 'http://192.168.0.17:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
},
},
};
diff --git a/package-lock.json b/package-lock.json
index d1d6f90..1aba7b4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"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",
@@ -3892,53 +3893,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 +3956,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": {
diff --git a/package.json b/package.json
index 8102387..aa1153c 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"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",
diff --git a/pages/MainPage.js b/pages/MainPage.js
index 75e4f3a..5c4d2d4 100644
--- a/pages/MainPage.js
+++ b/pages/MainPage.js
@@ -131,10 +131,10 @@ const MainPage = () => {
userVC={userVC}
initialIndex={initialIndex >= 0 ? initialIndex : 0} // 처음 보여줄 카드 인덱스
/>
-
+ {/*
-
+ */}
);
};
From a4c61ec08f8332a3ff92f64b5a31d4e3b3ee6df5 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Mon, 26 May 2025 11:18:43 +0900
Subject: [PATCH 2/5] =?UTF-8?q?KW-431/feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98?=
=?UTF-8?q?=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EB=B9=84=EB=B0=80?=
=?UTF-8?q?=EB=B2=88=ED=98=B8=20=EB=B3=80=EA=B2=BD=20=EB=AA=A8=EB=8B=AC=20?=
=?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20isverified=20=EB=B3=80?=
=?UTF-8?q?=EC=88=98=20=EC=A0=9C=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AppNavigator.js | 2 +
app.config.js | 2 +-
components/headers/WaveHeader.js | 9 +++-
modals/PasswordConfirmModal.js | 11 ++---
pages/MyPage.js | 77 ++++++++++++++++++++------------
stores/modalStore.js | 8 ++++
6 files changed, 73 insertions(+), 36 deletions(-)
create mode 100644 stores/modalStore.js
diff --git a/AppNavigator.js b/AppNavigator.js
index 68e27e2..bce5266 100644
--- a/AppNavigator.js
+++ b/AppNavigator.js
@@ -8,6 +8,7 @@ import HomeButtonController from './components/buttons/HomeButtonController';
import LoadingOverlay from './components/loadings/LoadingOverlay';
import { getMyInfo } from './apis/MyPageApi';
import { useAuthStore } from './stores/authStore';
+import PasswordConfirmModal from './modals/PasswordConfirmModal';
// 로그인 전 페이지
import WelcomePage from './pages/WelcomePage';
@@ -149,6 +150,7 @@ export default function AppNavigator() {
+
{isLoggedIn ? (
diff --git a/app.config.js b/app.config.js
index 2dc863a..9b9e9d9 100644
--- a/app.config.js
+++ b/app.config.js
@@ -26,7 +26,7 @@ export default {
},
extra: {
//BASE_URL: 'http://keywe.site', // EKS 사용시
- BASE_URL: 'http://192.168.0.17:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
+ BASE_URL: 'http://192.168.0.111:8081', // 도커 사용시 - 본인 pc IPv4 주소로 수정하세용
},
},
};
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..caeaabd 100644
--- a/modals/PasswordConfirmModal.js
+++ b/modals/PasswordConfirmModal.js
@@ -6,8 +6,10 @@ 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 = () => {
+ const { isPasswordModalVisible, setPasswordModalVisible } = useModalStore();
const [password, setPassword] = useState('');
const [errorText, setErrorText] = useState(''); // NormalText ErrorText
@@ -31,12 +33,11 @@ const PasswordConfirmModal = ({ visible = true, onCloseHandler }) => {
setErrorText('8자 이상, 영문/숫자/특수문자를 포함해야 합니다.');
return;
}
-
try {
await verifyPassword(password);
// 모달창 닫기
- onCloseHandler();
+ setPasswordModalVisible(false);
} catch (error) {
console.log(error);
setErrorText('비밀번호가 일치하지 않습니다. 다시 입력해주세요.');
@@ -58,14 +59,14 @@ const PasswordConfirmModal = ({ visible = true, onCloseHandler }) => {
// };
return (
-
+
-
+
비밀번호 확인
개인정보 보호를 위해 비밀번호를 확인합니다.
diff --git a/pages/MyPage.js b/pages/MyPage.js
index 0978053..4d9f714 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,8 @@ import { useAuthStore } from '../stores/authStore';
export default function MyPage() {
const { accessToken, clearAccessToken } = useAuthStore();
- const [isVerified, setIsVerified] = useState(false); // 비밀번호 인증 여부
- const [isModalVisible, setIsModalVisible] = useState(true);
+ // const [isVerified, setIsVerified] = useState(false); // 비밀번호 인증 여부
+ // const [isModalVisible, setIsModalVisible] = useState(true);
// Alert 관리 상태변수
const [showUpdatePasswordConfirmAlert, setShowUpdatePasswordConfirmAlert] = useState(false);
@@ -31,27 +31,49 @@ 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 handleCloseModal = async () => {
+ // setIsModalVisible(false);
+ // setIsVerified(true);
+
+ // // 회원 정보 불러오기
+ // 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 handleLogout = () => {
@@ -115,8 +137,8 @@ export default function MyPage() {
return (
- {/* 비밀번호 인증 완료 시, 본문 보이도록 설정 */}
- {isVerified && (
+ {/* {isVerified && ( */}
+ {
<>
마이 페이지
@@ -177,9 +199,8 @@ export default function MyPage() {
onConfirmHandler={handleDeleteUserSuccess}
/>
>
- )}
-
-
+ }
+ {/* */}
);
}
diff --git a/stores/modalStore.js b/stores/modalStore.js
new file mode 100644
index 0000000..6ac71d2
--- /dev/null
+++ b/stores/modalStore.js
@@ -0,0 +1,8 @@
+import { create } from 'zustand';
+
+export const useModalStore = create((set) => ({
+ isPasswordModalVisible: true,
+ setPasswordModalVisible: (visible) => set({ isPasswordModalVisible: visible }),
+ //isVerified: false,
+ //setVerified: (verified) => set({ isVerified: verified }),
+}));
From 4f36b620a4e140c3a3b4dfc325b224064f9fbbd3 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Mon, 26 May 2025 15:14:33 +0900
Subject: [PATCH 3/5] =?UTF-8?q?KW-431/fix:=20=EB=B9=84=EB=B0=80=EB=B2=88?=
=?UTF-8?q?=ED=98=B8=20=EC=9D=B8=EC=A6=9D=20=EC=9D=B4=ED=9B=84,=20?=
=?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=91?=
=?UTF-8?q?=EA=B7=BC=20=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=98=A4?=
=?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
AppNavigator.js | 19 ++++++++++++++++---
modals/PasswordConfirmModal.js | 31 +++++++++++++++++++++++--------
stores/modalStore.js | 17 +++++++++++++++--
3 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/AppNavigator.js b/AppNavigator.js
index bce5266..29957be 100644
--- a/AppNavigator.js
+++ b/AppNavigator.js
@@ -1,13 +1,14 @@
import { NavigationContainer, DefaultTheme } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
-import { useState, useEffect } from 'react';
+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';
// 로그인 전 페이지
@@ -108,6 +109,15 @@ export default function AppNavigator() {
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);
// 앱 시작 시 토큰 유효성 확인
@@ -146,11 +156,11 @@ export default function AppNavigator() {
};
return (
-
+
-
+
{isLoggedIn ? (
@@ -158,6 +168,9 @@ export default function AppNavigator() {
name="MyPageStack"
component={MyPageStack}
options={{ title: '마이페이지' }}
+ listeners={{
+ tabPress: (e) => handleTabPress(e, 'MyPageStack'), // 비밀번호 인증 이후 이동
+ }}
/>
diff --git a/modals/PasswordConfirmModal.js b/modals/PasswordConfirmModal.js
index caeaabd..69154c2 100644
--- a/modals/PasswordConfirmModal.js
+++ b/modals/PasswordConfirmModal.js
@@ -1,5 +1,5 @@
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';
@@ -8,11 +8,18 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view
import { verifyPassword } from '../apis/PasswordApi';
import { useModalStore } from '../stores/modalStore';
-const PasswordConfirmModal = () => {
- const { isPasswordModalVisible, setPasswordModalVisible } = useModalStore();
+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);
@@ -35,14 +42,18 @@ const PasswordConfirmModal = () => {
}
try {
await verifyPassword(password);
-
- // 모달창 닫기
- setPasswordModalVisible(false);
+ navigationRef.current?.navigate(pendingTab);
+ hidePasswordModal();
} catch (error) {
console.log(error);
setErrorText('비밀번호가 일치하지 않습니다. 다시 입력해주세요.');
}
};
+
+ const onClosePasswordModal = () => {
+ hidePasswordModal();
+ navigationRef.current?.navigate(prevTab);
+ };
// 모달 오류시 임시 코드
// const handleConfirm = async () => {
// if (!isValidPassword(password)) {
@@ -59,14 +70,18 @@ const PasswordConfirmModal = () => {
// };
return (
-
+
-
+
비밀번호 확인
개인정보 보호를 위해 비밀번호를 확인합니다.
diff --git a/stores/modalStore.js b/stores/modalStore.js
index 6ac71d2..11b539a 100644
--- a/stores/modalStore.js
+++ b/stores/modalStore.js
@@ -1,8 +1,21 @@
import { create } from 'zustand';
export const useModalStore = create((set) => ({
- isPasswordModalVisible: true,
- setPasswordModalVisible: (visible) => set({ isPasswordModalVisible: visible }),
+ 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 }),
}));
From 68e474117560e42106dc2e57e61f4a748df239ee Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Mon, 26 May 2025 21:17:44 +0900
Subject: [PATCH 4/5] =?UTF-8?q?KW-431/feat:=20=ED=95=98=EB=8B=A8=ED=83=AD?=
=?UTF-8?q?=20=EB=94=94=EC=9E=90=EC=9D=B8=20=EB=B0=8F=20=EC=95=A0=EB=8B=88?=
=?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
App.js | 8 +-
AppNavigator.js | 29 +++++--
components/AnimatedTabBar.js | 144 ++++++++++++++++++++++++++++++++
modals/PasswordConfirmModal.js | 3 +-
package-lock.json | 31 ++++++-
package.json | 4 +-
pages/AlertList.js | 16 ++++
pages/MyPage.js | 146 +++++++++++++--------------------
8 files changed, 281 insertions(+), 100 deletions(-)
create mode 100644 components/AnimatedTabBar.js
create mode 100644 pages/AlertList.js
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 29957be..f0a4716 100644
--- a/AppNavigator.js
+++ b/AppNavigator.js
@@ -10,6 +10,7 @@ import { getMyInfo } from './apis/MyPageApi';
import { useAuthStore } from './stores/authStore';
import { useModalStore } from './stores/modalStore';
import PasswordConfirmModal from './modals/PasswordConfirmModal';
+import AnimatedTabBar from './components/AnimatedTabBar';
// 로그인 전 페이지
import WelcomePage from './pages/WelcomePage';
@@ -25,6 +26,7 @@ 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();
@@ -34,9 +36,10 @@ const Tab = createBottomTabNavigator();
const tabScreenOptions = ({ route }) => ({
tabBarIcon: ({ color, size }) => {
let iconName;
- if (route.name === 'MainPage') iconName = 'home-outline';
- else if (route.name === 'MyPageStack') iconName = 'person-outline';
- else if (route.name === 'AccessStack') iconName = 'list-outline';
+ 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 ;
},
@@ -98,6 +101,14 @@ function AccessStack() {
);
}
+function AlertStack() {
+ return (
+
+
+
+ );
+}
+
export default function AppNavigator() {
const {
isLoggedIn,
@@ -162,8 +173,17 @@ export default function AppNavigator() {
{isLoggedIn ? (
-
+ }
+ >
+
+
handleTabPress(e, 'MyPageStack'), // 비밀번호 인증 이후 이동
}}
/>
-
) : (
diff --git a/components/AnimatedTabBar.js b/components/AnimatedTabBar.js
new file mode 100644
index 0000000..e05d89a
--- /dev/null
+++ b/components/AnimatedTabBar.js
@@ -0,0 +1,144 @@
+import React, { useRef } from 'react';
+import { View, TouchableOpacity, Animated, StyleSheet, Text } from 'react-native';
+import Ionicons from '@expo/vector-icons/Ionicons';
+import { colors } from '../constants/colors';
+
+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}
+
+ );
+ })}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ tabBar: {
+ flexDirection: 'row',
+ height: 80, // 높이 조절
+ backgroundColor: '#fff',
+ borderTopLeftRadius: 24,
+ borderTopRightRadius: 24,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: -2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 12,
+ 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,
+ // shadowColor: colors.darkGray,
+ // shadowOpacity: 0.7,
+ // shadowRadius: 8,
+ // elevation: 8,
+ },
+ label: {
+ fontSize: 13,
+ color: colors.lightGray,
+ fontWeight: '500',
+ marginTop: 2,
+ },
+ labelActive: {
+ color: colors.darkGray,
+ fontWeight: 'bold',
+ // textShadowOffset: { width: 0, height: 1 },
+ // textShadowRadius: 4,
+ },
+});
diff --git a/modals/PasswordConfirmModal.js b/modals/PasswordConfirmModal.js
index 69154c2..eeedcad 100644
--- a/modals/PasswordConfirmModal.js
+++ b/modals/PasswordConfirmModal.js
@@ -63,7 +63,8 @@ const PasswordConfirmModal = ({ navigationRef }) => {
// // 임시: 비밀번호가 'Lgcns01!'이면 성공, 아니면 실패
// if (password === 'Lgcns01!') {
- // onCloseHandler(); // 성공 시 모달 닫기
+ // navigationRef.current?.navigate(pendingTab);
+ // hidePasswordModal();
// } else {
// setErrorText('비밀번호가 일치하지 않습니다. 다시 입력해주세요.');
// }
diff --git a/package-lock.json b/package-lock.json
index 1aba7b4..1c0f5b7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,16 +15,18 @@
"@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"
@@ -6425,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",
@@ -10834,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",
@@ -10888,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 aa1153c..1a5d1a6 100644
--- a/package.json
+++ b/package.json
@@ -16,16 +16,18 @@
"@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/MyPage.js b/pages/MyPage.js
index 4d9f714..1709457 100644
--- a/pages/MyPage.js
+++ b/pages/MyPage.js
@@ -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);
@@ -53,28 +51,6 @@ export default function MyPage() {
fetchUserInfo();
}, [accessToken]);
- // // 인증 완료 시, 모달 창 닫음
- // const handleCloseModal = async () => {
- // setIsModalVisible(false);
- // setIsVerified(true);
-
- // // 회원 정보 불러오기
- // 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 handleLogout = () => {
setShowUpdatePasswordConfirmAlert(true);
@@ -137,70 +113,64 @@ export default function MyPage() {
return (
- {/* {isVerified && ( */}
- {
- <>
-
- 마이 페이지
-
-
-
-
-
-
- |
-
- |
-
-
-
- setShowUpdatePasswordConfirmAlert(false)}
- />
-
- setShowDeleteUserConfirmAlert(false)}
- />
-
- >
- }
- {/* */}
+
+ 마이 페이지
+
+
+
+
+
+
+ |
+
+ |
+
+
+
+ setShowUpdatePasswordConfirmAlert(false)}
+ />
+
+ setShowDeleteUserConfirmAlert(false)}
+ />
+
);
}
From bb2d07e5e09471af7c7af880e1be263184758a51 Mon Sep 17 00:00:00 2001
From: Jiwon Chae <63784453+jiwon0226@users.noreply.github.com>
Date: Tue, 27 May 2025 16:40:52 +0900
Subject: [PATCH 5/5] =?UTF-8?q?KW-431/fix:=20=ED=95=98=EB=8B=A8=ED=83=AD?=
=?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../AnimatedTabBar.js => AnimatedTabBar.js | 61 +++----------------
AnimatedTabBar.styles.js | 50 +++++++++++++++
AppNavigator.js | 26 ++++----
pages/MainPage.js | 4 --
4 files changed, 70 insertions(+), 71 deletions(-)
rename components/AnimatedTabBar.js => AnimatedTabBar.js (68%)
create mode 100644 AnimatedTabBar.styles.js
diff --git a/components/AnimatedTabBar.js b/AnimatedTabBar.js
similarity index 68%
rename from components/AnimatedTabBar.js
rename to AnimatedTabBar.js
index e05d89a..4c9fe51 100644
--- a/components/AnimatedTabBar.js
+++ b/AnimatedTabBar.js
@@ -1,7 +1,8 @@
import React, { useRef } from 'react';
-import { View, TouchableOpacity, Animated, StyleSheet, Text } from 'react-native';
+import { View, TouchableOpacity, Animated, Text } from 'react-native';
import Ionicons from '@expo/vector-icons/Ionicons';
-import { colors } from '../constants/colors';
+import { colors } from './constants/colors';
+import { styles } from './AnimatedTabBar.styles';
const TAB_ICONS = {
MainPage: 'home',
@@ -27,15 +28,17 @@ export default function AnimatedTabBar({ state, descriptors, navigation }) {
target: route.key,
canPreventDefault: true,
});
- // 이미 포커스된 탭이 아니고, 이벤트가 취소되지 않았으면 해당 route로 이동
+ // 포커스된 탭이 아니고, 이벤트가 취소되지 않았으면 해당 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)
@@ -82,8 +85,7 @@ export default function AnimatedTabBar({ state, descriptors, navigation }) {
{label}
@@ -93,52 +95,3 @@ export default function AnimatedTabBar({ state, descriptors, navigation }) {
);
}
-
-const styles = StyleSheet.create({
- tabBar: {
- flexDirection: 'row',
- height: 80, // 높이 조절
- backgroundColor: '#fff',
- borderTopLeftRadius: 24,
- borderTopRightRadius: 24,
- shadowColor: '#000',
- shadowOffset: { width: 0, height: -2 },
- shadowOpacity: 0.1,
- shadowRadius: 12,
- 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,
- // shadowColor: colors.darkGray,
- // shadowOpacity: 0.7,
- // shadowRadius: 8,
- // elevation: 8,
- },
- label: {
- fontSize: 13,
- color: colors.lightGray,
- fontWeight: '500',
- marginTop: 2,
- },
- labelActive: {
- color: colors.darkGray,
- fontWeight: 'bold',
- // textShadowOffset: { width: 0, height: 1 },
- // textShadowRadius: 4,
- },
-});
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/AppNavigator.js b/AppNavigator.js
index f0a4716..694c329 100644
--- a/AppNavigator.js
+++ b/AppNavigator.js
@@ -10,7 +10,7 @@ import { getMyInfo } from './apis/MyPageApi';
import { useAuthStore } from './stores/authStore';
import { useModalStore } from './stores/modalStore';
import PasswordConfirmModal from './modals/PasswordConfirmModal';
-import AnimatedTabBar from './components/AnimatedTabBar';
+import AnimatedTabBar from './AnimatedTabBar';
// 로그인 전 페이지
import WelcomePage from './pages/WelcomePage';
@@ -34,17 +34,17 @@ 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',
+ // 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,
});
@@ -174,7 +174,7 @@ export default function AppNavigator() {
{isLoggedIn ? (
}
>
diff --git a/pages/MainPage.js b/pages/MainPage.js
index 5c4d2d4..5e2d77d 100644
--- a/pages/MainPage.js
+++ b/pages/MainPage.js
@@ -131,10 +131,6 @@ const MainPage = () => {
userVC={userVC}
initialIndex={initialIndex >= 0 ? initialIndex : 0} // 처음 보여줄 카드 인덱스
/>
- {/*
-
-
- */}
);
};