diff --git a/.yarn/cache/@babel-helper-plugin-utils-npm-7.24.8-a288f101a7-73b1a83ba8.zip b/.yarn/cache/@babel-helper-plugin-utils-npm-7.24.8-a288f101a7-73b1a83ba8.zip new file mode 100644 index 00000000..9da160c7 Binary files /dev/null and b/.yarn/cache/@babel-helper-plugin-utils-npm-7.24.8-a288f101a7-73b1a83ba8.zip differ diff --git a/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.24.8-3f07208b22-45e55e3a2f.zip b/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.24.8-3f07208b22-45e55e3a2f.zip new file mode 100644 index 00000000..31fd9505 Binary files /dev/null and b/.yarn/cache/@babel-plugin-transform-optional-chaining-npm-7.24.8-3f07208b22-45e55e3a2f.zip differ diff --git a/.yarn/cache/@react-navigation-material-top-tabs-npm-6.6.14-97af57dac8-565919b1a9.zip b/.yarn/cache/@react-navigation-material-top-tabs-npm-6.6.14-97af57dac8-565919b1a9.zip new file mode 100644 index 00000000..8a0256b6 Binary files /dev/null and b/.yarn/cache/@react-navigation-material-top-tabs-npm-6.6.14-97af57dac8-565919b1a9.zip differ diff --git a/.yarn/cache/@tanstack-query-core-npm-5.51.9-6ef6539693-f3192fe32a.zip b/.yarn/cache/@tanstack-query-core-npm-5.51.9-6ef6539693-f3192fe32a.zip new file mode 100644 index 00000000..00f046c0 Binary files /dev/null and b/.yarn/cache/@tanstack-query-core-npm-5.51.9-6ef6539693-f3192fe32a.zip differ diff --git a/.yarn/cache/@tanstack-react-query-npm-5.51.9-b0e195cb17-f0e1612227.zip b/.yarn/cache/@tanstack-react-query-npm-5.51.9-b0e195cb17-f0e1612227.zip new file mode 100644 index 00000000..18d46dee Binary files /dev/null and b/.yarn/cache/@tanstack-react-query-npm-5.51.9-b0e195cb17-f0e1612227.zip differ diff --git a/.yarn/cache/@types-tinycolor2-npm-1.4.6-62a2039a99-50179851b3.zip b/.yarn/cache/@types-tinycolor2-npm-1.4.6-62a2039a99-50179851b3.zip new file mode 100644 index 00000000..6e7b97df Binary files /dev/null and b/.yarn/cache/@types-tinycolor2-npm-1.4.6-62a2039a99-50179851b3.zip differ diff --git a/.yarn/cache/asynckit-npm-0.4.0-c718858525-7b78c451df.zip b/.yarn/cache/asynckit-npm-0.4.0-c718858525-7b78c451df.zip new file mode 100644 index 00000000..bb08c24f Binary files /dev/null and b/.yarn/cache/asynckit-npm-0.4.0-c718858525-7b78c451df.zip differ diff --git a/.yarn/cache/axios-npm-1.7.2-c89264f6f7-e457e2b0ab.zip b/.yarn/cache/axios-npm-1.7.2-c89264f6f7-e457e2b0ab.zip new file mode 100644 index 00000000..5d20f72e Binary files /dev/null and b/.yarn/cache/axios-npm-1.7.2-c89264f6f7-e457e2b0ab.zip differ diff --git a/.yarn/cache/combined-stream-npm-1.0.8-dc14d4a63a-49fa4aeb49.zip b/.yarn/cache/combined-stream-npm-1.0.8-dc14d4a63a-49fa4aeb49.zip new file mode 100644 index 00000000..89c8caa0 Binary files /dev/null and b/.yarn/cache/combined-stream-npm-1.0.8-dc14d4a63a-49fa4aeb49.zip differ diff --git a/.yarn/cache/delayed-stream-npm-1.0.0-c5a4c4cc02-46fe6e83e2.zip b/.yarn/cache/delayed-stream-npm-1.0.0-c5a4c4cc02-46fe6e83e2.zip new file mode 100644 index 00000000..71514340 Binary files /dev/null and b/.yarn/cache/delayed-stream-npm-1.0.0-c5a4c4cc02-46fe6e83e2.zip differ diff --git a/.yarn/cache/follow-redirects-npm-1.15.6-50635fe51d-a62c378dfc.zip b/.yarn/cache/follow-redirects-npm-1.15.6-50635fe51d-a62c378dfc.zip new file mode 100644 index 00000000..4a44b00e Binary files /dev/null and b/.yarn/cache/follow-redirects-npm-1.15.6-50635fe51d-a62c378dfc.zip differ diff --git a/.yarn/cache/form-data-npm-4.0.0-916facec2d-01135bf867.zip b/.yarn/cache/form-data-npm-4.0.0-916facec2d-01135bf867.zip new file mode 100644 index 00000000..8ae5189b Binary files /dev/null and b/.yarn/cache/form-data-npm-4.0.0-916facec2d-01135bf867.zip differ diff --git a/.yarn/cache/proxy-from-env-npm-1.1.0-c13d07f26b-ed7fcc2ba0.zip b/.yarn/cache/proxy-from-env-npm-1.1.0-c13d07f26b-ed7fcc2ba0.zip new file mode 100644 index 00000000..a58e6bf3 Binary files /dev/null and b/.yarn/cache/proxy-from-env-npm-1.1.0-c13d07f26b-ed7fcc2ba0.zip differ diff --git a/.yarn/cache/react-native-pager-view-npm-6.3.3-7b62f58674-b4f6ef33a7.zip b/.yarn/cache/react-native-pager-view-npm-6.3.3-7b62f58674-b4f6ef33a7.zip new file mode 100644 index 00000000..a0f13bd0 Binary files /dev/null and b/.yarn/cache/react-native-pager-view-npm-6.3.3-7b62f58674-b4f6ef33a7.zip differ diff --git a/.yarn/cache/react-native-reanimated-npm-3.14.0-e00554c9e8-31eb58d1c7.zip b/.yarn/cache/react-native-reanimated-npm-3.14.0-e00554c9e8-31eb58d1c7.zip new file mode 100644 index 00000000..6a781071 Binary files /dev/null and b/.yarn/cache/react-native-reanimated-npm-3.14.0-e00554c9e8-31eb58d1c7.zip differ diff --git a/.yarn/cache/react-native-tab-view-npm-3.5.2-fb6cb6fe6f-bd287e5543.zip b/.yarn/cache/react-native-tab-view-npm-3.5.2-fb6cb6fe6f-bd287e5543.zip new file mode 100644 index 00000000..f9d96253 Binary files /dev/null and b/.yarn/cache/react-native-tab-view-npm-3.5.2-fb6cb6fe6f-bd287e5543.zip differ diff --git a/.yarn/cache/reanimated-color-picker-npm-3.0.4-ee2956e6a1-c402ac8033.zip b/.yarn/cache/reanimated-color-picker-npm-3.0.4-ee2956e6a1-c402ac8033.zip new file mode 100644 index 00000000..4e3d4c06 Binary files /dev/null and b/.yarn/cache/reanimated-color-picker-npm-3.0.4-ee2956e6a1-c402ac8033.zip differ diff --git a/.yarn/cache/tinycolor2-npm-1.6.0-8df41252c6-6df4d07fce.zip b/.yarn/cache/tinycolor2-npm-1.6.0-8df41252c6-6df4d07fce.zip new file mode 100644 index 00000000..ed477a53 Binary files /dev/null and b/.yarn/cache/tinycolor2-npm-1.6.0-8df41252c6-6df4d07fce.zip differ diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz index a2e01e09..605b2f26 100644 Binary files a/.yarn/install-state.gz and b/.yarn/install-state.gz differ diff --git a/packages/design-system/src/Font.tsx b/packages/design-system/src/Font.tsx index b47f8a43..794461c2 100644 --- a/packages/design-system/src/Font.tsx +++ b/packages/design-system/src/Font.tsx @@ -19,6 +19,7 @@ const FONT_TYPE_PREFIX = { body1: 'text-[16px] leading-[24px]', body2: 'text-[14px] leading-[18px]', body3: 'text-[12px] leading-[16px]', + 'ui-text': 'text-[10px] leading-[10px]', }; export type Color = keyof typeof COLOR_PREFIX; @@ -36,13 +37,7 @@ const FontRegular = ({ type, color, children, underline }: FontProps) => { const colorStyle = COLOR_PREFIX[color]; const underLineStyle = underline ? 'underline underline-offset-1' : ''; const fontStyle = FONT_PREFIX.MEDIUM; - return ( - - {children} - - ); + return {children}; }; const FontBold = ({ type, color, children, underline }: FontProps) => { @@ -50,13 +45,7 @@ const FontBold = ({ type, color, children, underline }: FontProps) => { const colorStyle = COLOR_PREFIX[color]; const underLineStyle = underline ? 'underline underline-offset-1' : ''; const fontStyle = FONT_PREFIX.BOLD; - return ( - - {children} - - ); + return {children}; }; const FontLight = ({ type, color, children, underline }: FontProps) => { @@ -65,13 +54,7 @@ const FontLight = ({ type, color, children, underline }: FontProps) => { const underLineStyle = underline ? 'underline underline-offset-1' : ''; const fontStyle = FONT_PREFIX.LIGHT; - return ( - - {children} - - ); + return {children}; }; export const Font = Object.assign(FontRegular, { diff --git a/packages/design-system/src/TextField.tsx b/packages/design-system/src/TextField.tsx index f3c1eb90..d07ec812 100644 --- a/packages/design-system/src/TextField.tsx +++ b/packages/design-system/src/TextField.tsx @@ -4,18 +4,12 @@ import { TextInput } from 'react-native'; interface TextField { value: string; onChange: (value: string) => void; - onSubmit: () => void; + onSubmit?: () => void; placeholder: string; - isCorrect: boolean; + isCorrect?: boolean; } -export function TextField({ - value, - onChange, - placeholder, - onSubmit, - isCorrect, -}: TextField) { +export function TextField({ value, onChange, placeholder, onSubmit, isCorrect }: TextField) { const defaultClassName = 'text-SPOT-black text-body2 rounded-md p-4 bg-SPOT-white/60 border-[2px] border-bg-SPOT-white/60'; const incorrectClassName = 'border-SPOT-red border-[2px]'; @@ -34,7 +28,7 @@ export function TextField({ value={value} onChangeText={onChange} placeholder={placeholder} - placeholderTextColor="#ffffff" + placeholderTextColor='#ffffff' className={`${defaultClassName} ${getBorderClassName()}`} onSubmitEditing={onSubmit} /> diff --git a/packages/react-native/babel.config.js b/packages/react-native/babel.config.js index db1e1189..669e3441 100644 --- a/packages/react-native/babel.config.js +++ b/packages/react-native/babel.config.js @@ -13,6 +13,7 @@ module.exports = { '@pages': './src/pages', '@routes': './src/routes', '@components': './src/components', + '@layouts': './src/layouts', '@assets': './src/assets', '@constants': './src/constants', '@utils': './src/utils', diff --git a/packages/react-native/ios/Podfile.lock b/packages/react-native/ios/Podfile.lock index 913dff6a..a5397a17 100644 --- a/packages/react-native/ios/Podfile.lock +++ b/packages/react-native/ios/Podfile.lock @@ -979,6 +979,27 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga + - react-native-pager-view (6.3.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-safe-area-context (4.10.8): - React-Core - react-native-view-shot (3.8.0): @@ -1325,6 +1346,7 @@ DEPENDENCIES: - React-Mapbuffer (from `../../../node_modules/react-native/ReactCommon`) - "react-native-cameraroll (from `../../../node_modules/@react-native-camera-roll/camera-roll`)" - react-native-image-picker (from `../../../node_modules/react-native-image-picker`) + - react-native-pager-view (from `../../../node_modules/react-native-pager-view`) - react-native-safe-area-context (from `../../../node_modules/react-native-safe-area-context`) - react-native-view-shot (from `../../../node_modules/react-native-view-shot`) - React-nativeconfig (from `../../../node_modules/react-native/ReactCommon`) @@ -1430,6 +1452,8 @@ EXTERNAL SOURCES: :path: "../../../node_modules/@react-native-camera-roll/camera-roll" react-native-image-picker: :path: "../../../node_modules/react-native-image-picker" + react-native-pager-view: + :path: "../../../node_modules/react-native-pager-view" react-native-safe-area-context: :path: "../../../node_modules/react-native-safe-area-context" react-native-view-shot: @@ -1529,6 +1553,7 @@ SPEC CHECKSUMS: React-Mapbuffer: 9f68550e7c6839d01411ac8896aea5c868eff63a react-native-cameraroll: a9138c165c9975da773d26945591d313992c799b react-native-image-picker: c3afe5472ef870d98a4b28415fc0b928161ee5f7 + react-native-pager-view: f848f89049a8e888d38f10ff31588eb63292a95f react-native-safe-area-context: b7daa1a8df36095a032dff095a1ea8963cb48371 react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688 React-nativeconfig: fa5de9d8f4dbd5917358f8ad3ad1e08762f01dcb diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 6875e06b..fe183297 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -19,6 +19,7 @@ "@gorhom/bottom-sheet": "^4.6.4", "@react-native-camera-roll/camera-roll": "^7.8.1", "@react-navigation/bottom-tabs": "^6.6.0", + "@react-navigation/material-top-tabs": "^6.6.14", "@react-navigation/native": "^6.1.17", "@react-navigation/stack": "^6.4.0", "@tanstack/react-query": "^5.51.9", @@ -32,11 +33,13 @@ "react-native-gesture-handler": "^2.17.1", "react-native-image-picker": "^7.1.2", "react-native-linear-gradient": "^2.8.3", + "react-native-pager-view": "^6.3.3", "react-native-permissions": "^4.1.5", "react-native-reanimated": "^3.14.0", "react-native-safe-area-context": "^4.10.8", "react-native-screens": "^3.32.0", "react-native-svg": "^15.4.0", + "react-native-tab-view": "^3.5.2", "react-native-view-shot": "^3.8.0", "react-native-vision-camera": "^4.5.0", "reanimated-color-picker": "^3.0.4", diff --git a/packages/react-native/src/assets/EditIcon.tsx b/packages/react-native/src/assets/EditIcon.tsx new file mode 100644 index 00000000..bd0450b2 --- /dev/null +++ b/packages/react-native/src/assets/EditIcon.tsx @@ -0,0 +1,17 @@ +import { Path, Svg, SvgProps } from 'react-native-svg'; + +export default function EditIcon({ width, height, color }: SvgProps) { + return ( + + + + ); +} diff --git a/packages/react-native/src/assets/Heart.tsx b/packages/react-native/src/assets/HeartIcon.tsx similarity index 95% rename from packages/react-native/src/assets/Heart.tsx rename to packages/react-native/src/assets/HeartIcon.tsx index 6578e25d..98724d9a 100644 --- a/packages/react-native/src/assets/Heart.tsx +++ b/packages/react-native/src/assets/HeartIcon.tsx @@ -1,6 +1,6 @@ import { Path, Svg, SvgProps } from 'react-native-svg'; -export default function Heart({ width, height, color }: SvgProps) { +export default function HeartIcon({ width, height, color }: SvgProps) { return ( - + {/* FIXME: 디자인 시스템 적용 */} diff --git a/packages/react-native/src/components/common/EditButton.tsx b/packages/react-native/src/components/common/EditButton.tsx new file mode 100644 index 00000000..d7952f0a --- /dev/null +++ b/packages/react-native/src/components/common/EditButton.tsx @@ -0,0 +1,17 @@ +import { TouchableOpacity } from 'react-native'; +import EditIcon from '@/assets/EditIcon'; + +interface EditButtonProps { + onPress: () => void; +} + +export default function EditButton({ onPress }: EditButtonProps) { + return ( + + + + ); +} diff --git a/packages/react-native/src/components/mypage/Badge.tsx b/packages/react-native/src/components/mypage/Badge.tsx new file mode 100644 index 00000000..0b0c654c --- /dev/null +++ b/packages/react-native/src/components/mypage/Badge.tsx @@ -0,0 +1,16 @@ +import { Font } from 'design-system'; +import { View } from 'react-native'; + +interface BadgeProps { + content: string; +} + +export default function Badge({ content }: BadgeProps) { + return ( + + + {content} + + + ); +} diff --git a/packages/react-native/src/hooks/useColorPalette.ts b/packages/react-native/src/hooks/useColorPalette.ts new file mode 100644 index 00000000..c3f11d7b --- /dev/null +++ b/packages/react-native/src/hooks/useColorPalette.ts @@ -0,0 +1,33 @@ +import { useState } from 'react'; +import tinycolor from 'tinycolor2'; +import { returnedResults } from 'reanimated-color-picker'; +import { + NICKNAME_COLOR_SET, + NicknameColorSet, +} from '@/constants/NICKNAME_COLOR_SET'; + +export default function useColorPalette() { + const [selectedColor, setSelectedColor] = useState(NICKNAME_COLOR_SET[0]); + const [selectedPalette, setSelectedPalette] = useState( + NICKNAME_COLOR_SET[0], + ); + + const onSelectColor = ({ hex }: returnedResults) => { + setSelectedColor(hex); + }; + + const onChangeSelectedBarColor = (color: NicknameColorSet) => { + setSelectedColor(color); + setSelectedPalette(color); + }; + + const textColor = tinycolor(selectedColor).darken(25).toHexString(); + + return { + selectedColor, + selectedPalette, + onSelectColor, + onChangeSelectedBarColor, + textColor, + }; +} diff --git a/packages/react-native/src/hooks/useProfileImage.tsx b/packages/react-native/src/hooks/useProfileImage.tsx new file mode 100644 index 00000000..47414496 --- /dev/null +++ b/packages/react-native/src/hooks/useProfileImage.tsx @@ -0,0 +1,35 @@ +import { useState } from 'react'; +import { Image, TouchableOpacity } from 'react-native'; +import useGallery from './useGallery'; +import SelectProfile from '@/assets/SelectProfile'; + +export default function useProfileImage(uri?: string) { + const { getPhoto } = useGallery(); + const [photoUri, setPhotoUri] = useState(uri || ''); + + const getPhtoFromLibrary = async () => { + const photo = await getPhoto(); + + if (photoUri && !photo) return; + + setPhotoUri(photo || ''); + }; + + function ProfileImage() { + return ( + + {photoUri ? ( + + ) : ( + + )} + + ); + } + + return { photoUri, ProfileImage }; +} diff --git a/packages/react-native/src/layouts/BackGroundGradient.tsx b/packages/react-native/src/layouts/BackGroundGradient.tsx new file mode 100644 index 00000000..2cdddd87 --- /dev/null +++ b/packages/react-native/src/layouts/BackGroundGradient.tsx @@ -0,0 +1,30 @@ +import { SafeAreaView, ScrollView } from 'react-native'; +import LinearGradient from 'react-native-linear-gradient'; + +export default function BackGroundGradient({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + {children} + + + + + ); +} diff --git a/packages/react-native/src/pages/Home.tsx b/packages/react-native/src/pages/Home.tsx index 4fcf3393..30ae47de 100644 --- a/packages/react-native/src/pages/Home.tsx +++ b/packages/react-native/src/pages/Home.tsx @@ -1,10 +1,10 @@ -import { ScrollView, View, SafeAreaView } from 'react-native'; -import LinearGradient from 'react-native-linear-gradient'; +import { View, Text } from 'react-native'; import { Button, Font } from 'design-system'; import CardSlider from '@components/CardSlider'; import SearchBar from '@components/common/SearchBar'; import { SpotData } from '@/types/spot'; import { ScreenNavigationProp } from '@/types/navigation'; +import BackGroundGradient from '@/layouts/BackGroundGradient'; const mockData: SpotData[] = [ { @@ -56,42 +56,27 @@ interface HomeScreenProps { export default function Home({ navigation }: HomeScreenProps) { return ( - - - - - - - - 안녕하세요, 아무개님.{'\n'}오늘은 어디로 가 볼까요? - - {/* FIXME: 추후 삭제 */} - + + + + + + + + + + + + ); } diff --git a/packages/react-native/src/pages/MyPage.tsx b/packages/react-native/src/pages/MyPage.tsx index c5e868e7..1aa11500 100644 --- a/packages/react-native/src/pages/MyPage.tsx +++ b/packages/react-native/src/pages/MyPage.tsx @@ -1,9 +1,46 @@ -import { Text, View } from 'react-native'; +import { View } from 'react-native'; +import { Font } from 'design-system'; +import BackGroundGradient from '@/layouts/BackGroundGradient'; +import SelectProfile from '@/assets/SelectProfile'; +import Badge from '@/components/mypage/Badge'; +import EditButton from '@/components/common/EditButton'; +import MyPageTabNavigator from '@/routes/MyPageTabNavigator'; +import { MyPageStackNavigation } from '@/types/navigation'; -export default function MyPage() { +interface MyPageProps { + navigation: MyPageStackNavigation<'myPage/profile'>; +} + +export default function MyPage({ navigation }: MyPageProps) { return ( - - Tab2 - + + + + {/* FIXME: 실제 이미지 받아와서 설정 */} + + + + navigation.navigate('myPage/editProfile')} + /> + + + + + + + + {/* FIXME: 실제 닉네임 받아와서 설정 */} + + 닉네임네임 + + + + + + + + + ); } diff --git a/packages/react-native/src/pages/MyPage/EditProfile.tsx b/packages/react-native/src/pages/MyPage/EditProfile.tsx new file mode 100644 index 00000000..445fd97f --- /dev/null +++ b/packages/react-native/src/pages/MyPage/EditProfile.tsx @@ -0,0 +1,78 @@ +import { useState } from 'react'; +import { Alert, TouchableOpacity, View } from 'react-native'; +import { Button, Font, TextField } from 'design-system'; +import useProfileImage from '@/hooks/useProfileImage'; +import BackGroundGradient from '@/layouts/BackGroundGradient'; +import { MyPageStackNavigation } from '@/types/navigation'; + +interface EditProfileProps { + navigation: MyPageStackNavigation<'myPage/editProfile'>; +} + +export default function EditProfile({ navigation }: EditProfileProps) { + // FIXME: 실제 닉네임으로 변경 + const { ProfileImage, photoUri } = useProfileImage(); + const [nickname, setNickname] = useState(''); + + const handleChangeProfile = () => { + Alert.alert(photoUri); + }; + + return ( + <> + + + + + + + + + + 닉네임 + + + + setNickname(newNickName)} + /> + + + + + navigation.navigate('myPage/editProfileWithNickname', { + nickname, + }) + } + > + + 닉네임으로 프로필 사진 설정하기 + + + {/* FIXME: 로그아웃 기능 추가 */} + Alert.alert('로그아웃')} + className="opacity-50" + > + + 로그아웃 하기 + + + + + + + + + + + + ); +} diff --git a/packages/react-native/src/pages/MyPage/EditProfileWithNickname.tsx b/packages/react-native/src/pages/MyPage/EditProfileWithNickname.tsx new file mode 100644 index 00000000..418897d3 --- /dev/null +++ b/packages/react-native/src/pages/MyPage/EditProfileWithNickname.tsx @@ -0,0 +1,71 @@ +import { Text, View } from 'react-native'; +import { useRoute } from '@react-navigation/native'; +import { Button, Font } from 'design-system'; +import { MyPageRouteProps, MyPageStackNavigation } from '@/types/navigation'; +import BackGroundGradient from '@/layouts/BackGroundGradient'; +import NicknameColorPalette from '@/components/signup/nicknameProfile/NicknameColorPalette'; +import ColorSlider from '@/components/signup/nicknameProfile/ColorSlider'; +import useColorPalette from '@/hooks/useColorPalette'; + +interface EditProfileWithNicknameProps { + navigation: MyPageStackNavigation<'myPage/editProfileWithNickname'>; +} + +export default function EditProfileWithNickname({ + navigation, +}: EditProfileWithNicknameProps) { + const route = useRoute>(); + const { nickname } = route.params; + const { + selectedColor, + selectedPalette, + onSelectColor, + onChangeSelectedBarColor, + textColor, + } = useColorPalette(); + + return ( + <> + + + + + + {nickname} + + + + + + + + + + + + + + + + + + + ); +} diff --git a/packages/react-native/src/pages/MyPage/MyBadge.tsx b/packages/react-native/src/pages/MyPage/MyBadge.tsx new file mode 100644 index 00000000..544840d9 --- /dev/null +++ b/packages/react-native/src/pages/MyPage/MyBadge.tsx @@ -0,0 +1,12 @@ +import { Font } from 'design-system'; +import { ScrollView } from 'react-native'; + +export default function MyBadge() { + return ( + + + MyBadge + + + ); +} diff --git a/packages/react-native/src/pages/MyPage/MyRoute.tsx b/packages/react-native/src/pages/MyPage/MyRoute.tsx new file mode 100644 index 00000000..f1b8400f --- /dev/null +++ b/packages/react-native/src/pages/MyPage/MyRoute.tsx @@ -0,0 +1,12 @@ +import { Font } from 'design-system'; +import { ScrollView } from 'react-native'; + +export default function MyRoute() { + return ( + + + MyRoute + + + ); +} diff --git a/packages/react-native/src/pages/MyPage/MySpot.tsx b/packages/react-native/src/pages/MyPage/MySpot.tsx new file mode 100644 index 00000000..f687fc92 --- /dev/null +++ b/packages/react-native/src/pages/MyPage/MySpot.tsx @@ -0,0 +1,12 @@ +import { Font } from 'design-system'; +import { ScrollView } from 'react-native'; + +export default function MySpot() { + return ( + + + MySpot + + + ); +} diff --git a/packages/react-native/src/pages/Signup/NicknameProfile.tsx b/packages/react-native/src/pages/Signup/NicknameProfile.tsx index 3b350ba7..53146a08 100644 --- a/packages/react-native/src/pages/Signup/NicknameProfile.tsx +++ b/packages/react-native/src/pages/Signup/NicknameProfile.tsx @@ -1,18 +1,12 @@ import { Button, Font } from 'design-system'; import { Text, View } from 'react-native'; -import { returnedResults } from 'reanimated-color-picker'; -import { useState } from 'react'; -import tinycolor from 'tinycolor2'; import { useRoute } from '@react-navigation/native'; import { SignupRouteProps, SignupStackNavigation } from '@/types/navigation'; import Overlay from '@/components/signup/common/Overlay'; import Header from '@/components/signup/common/Header'; -import { - NICKNAME_COLOR_SET, - NicknameColorSet, -} from '@/constants/NICKNAME_COLOR_SET'; import NicknameColorPalette from '@/components/signup/nicknameProfile/NicknameColorPalette'; import ColorSlider from '@/components/signup/nicknameProfile/ColorSlider'; +import useColorPalette from '@/hooks/useColorPalette'; interface NicknameProfileProps { navigation: SignupStackNavigation<'Signup/NicknameProfile'>; @@ -21,24 +15,13 @@ interface NicknameProfileProps { export default function NicknameProfile({ navigation }: NicknameProfileProps) { const route = useRoute>(); const { nickname } = route.params; - const [selectedColor, setSelectedColor] = useState(NICKNAME_COLOR_SET[0]); - const [selectedPalette, setSelectedPalette] = useState( - NICKNAME_COLOR_SET[0], - ); - - const onSelectColor = ({ hex }: returnedResults) => { - setSelectedColor(hex); - }; - - const onChangeSelectedBarColor = (color: NicknameColorSet) => { - setSelectedColor(color); - setSelectedPalette(color); - }; - - const getFontColor = () => { - const textColor = tinycolor(selectedColor); - return textColor.darken(25).toHexString(); - }; + const { + selectedColor, + selectedPalette, + onSelectColor, + onChangeSelectedBarColor, + textColor, + } = useColorPalette(); const handleNext = () => { navigation.navigate('Main'); @@ -62,7 +45,7 @@ export default function NicknameProfile({ navigation }: NicknameProfileProps) { {nickname} @@ -78,14 +61,14 @@ export default function NicknameProfile({ navigation }: NicknameProfileProps) { - + - + diff --git a/packages/react-native/src/pages/Signup/Profile.tsx b/packages/react-native/src/pages/Signup/Profile.tsx index df2df392..df374cae 100644 --- a/packages/react-native/src/pages/Signup/Profile.tsx +++ b/packages/react-native/src/pages/Signup/Profile.tsx @@ -1,32 +1,21 @@ import { Button, Font } from 'design-system'; -import { Image, View } from 'react-native'; +import { View } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; -import { useState } from 'react'; import { useRoute } from '@react-navigation/native'; -import SelectProfile from '@/assets/SelectProfile'; import Header from '@/components/signup/common/Header'; import Overlay from '@/components/signup/common/Overlay'; import { SignupRouteProps, SignupStackNavigation } from '@/types/navigation'; -import useGallery from '@/hooks/useGallery'; +import useProfileImage from '@/hooks/useProfileImage'; interface ProfileProps { navigation: SignupStackNavigation<'Signup/Profile'>; } export default function Profile({ navigation }: ProfileProps) { - const { getPhoto } = useGallery(); - const [photoUri, setPhotoUri] = useState(''); + const { ProfileImage, photoUri } = useProfileImage(); const route = useRoute>(); const { nickname } = route.params; - const handlePhotoGet = async () => { - const photo = await getPhoto(); - - if (photoUri && !photo) return; - - setPhotoUri(photo || ''); - }; - const handleNext = () => { if (!photoUri) return; @@ -51,17 +40,7 @@ export default function Profile({ navigation }: ProfileProps) { - - {photoUri ? ( - - ) : ( - - )} - + diff --git a/packages/react-native/src/pages/TabScreens.tsx b/packages/react-native/src/pages/TabScreens.tsx index 16d3c846..d4513ca9 100644 --- a/packages/react-native/src/pages/TabScreens.tsx +++ b/packages/react-native/src/pages/TabScreens.tsx @@ -1,5 +1,10 @@ import BottomTabNavigator from '@routes/BottomTabNavigator'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; export default function TabScreens() { - return ; + return ( + + + + ); } diff --git a/packages/react-native/src/routes/BottomTabNavigator.tsx b/packages/react-native/src/routes/BottomTabNavigator.tsx index 25705271..bf274dc6 100644 --- a/packages/react-native/src/routes/BottomTabNavigator.tsx +++ b/packages/react-native/src/routes/BottomTabNavigator.tsx @@ -1,16 +1,17 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; -import { Platform } from 'react-native'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; import Home from '@pages/Home'; import HomeIcon from '@assets/HomeIcon'; import Detail from '@pages/Detail'; -import MyPage from '@pages/MyPage'; import MapIcon from '@assets/MapIcon'; import DetailIcon from '@assets/DetailIcon'; import MyPageIcon from '@assets/MyPageIcon'; import Maps from '@/pages/Maps'; +import MyPageStackNavigator from './MyPageStackNavigator'; export default function BottomTabNavigator() { const Tab = createBottomTabNavigator(); + const insets = useSafeAreaInsets(); return ( - {/* FIXME: 경로 페이지로 변경 */} + + + + + ); +} diff --git a/packages/react-native/src/routes/MyPageTabNavigator.tsx b/packages/react-native/src/routes/MyPageTabNavigator.tsx new file mode 100644 index 00000000..acf1d046 --- /dev/null +++ b/packages/react-native/src/routes/MyPageTabNavigator.tsx @@ -0,0 +1,47 @@ +import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs'; +import MyBadge from '@/pages/MyPage/MyBadge'; +import MyRoute from '@/pages/MyPage/MyRoute'; +import MySpot from '@/pages/MyPage/MySpot'; + +export default function MyPageTabNavigator() { + const Tab = createMaterialTopTabNavigator(); + + return ( + + + + + + ); +} diff --git a/packages/react-native/src/types/navigation.ts b/packages/react-native/src/types/navigation.ts index 604825ff..948ba26d 100644 --- a/packages/react-native/src/types/navigation.ts +++ b/packages/react-native/src/types/navigation.ts @@ -2,6 +2,7 @@ import { StackNavigationProp } from '@react-navigation/stack'; import { RouteProp } from '@react-navigation/native'; import { RootStackParamList } from '@/routes/StackNavigator'; import { SignupStackParamList } from '@/routes/SignupStackNavigator'; +import { MyPageStackParamList } from '@/routes/MyPageStackNavigator'; export type ScreenNavigationProp = StackNavigationProp; @@ -13,3 +14,11 @@ export type SignupRouteProps = RouteProp< SignupStackParamList, T >; + +export type MyPageStackNavigation = + StackNavigationProp; + +export type MyPageRouteProps = RouteProp< + MyPageStackParamList, + T +>; diff --git a/packages/react-native/tsconfig.json b/packages/react-native/tsconfig.json index 9a236eeb..2ddfffa5 100644 --- a/packages/react-native/tsconfig.json +++ b/packages/react-native/tsconfig.json @@ -7,6 +7,7 @@ "@pages/*": ["./src/pages/*"], "@routes/*": ["./src/routes/*"], "@components/*": ["./src/components/*"], + "@layouts/*": ["./src/layouts/*"], "@assets/*": ["./src/assets/*"], "@constants/*": ["./src/constants/*"], "@utils/*": ["./src/utils/*"] diff --git a/yarn.lock b/yarn.lock index e436b160..edddc9b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3608,6 +3608,22 @@ __metadata: languageName: node linkType: hard +"@react-navigation/material-top-tabs@npm:^6.6.14": + version: 6.6.14 + resolution: "@react-navigation/material-top-tabs@npm:6.6.14" + dependencies: + color: ^4.2.3 + warn-once: ^0.1.0 + peerDependencies: + "@react-navigation/native": ^6.0.0 + react: "*" + react-native: "*" + react-native-pager-view: ">= 4.0.0" + react-native-tab-view: ">= 3.0.0" + checksum: 565919b1a9a948ab30d6448dd2d59035cb05f1d87d559f3710072a0795b344fdcc543f2eeb8884b5d699a965cac7db5d88641ba87ec7544e23245404ffb860ec + languageName: node + linkType: hard + "@react-navigation/native@npm:^6.1.17": version: 6.1.17 resolution: "@react-navigation/native@npm:6.1.17" @@ -14598,6 +14614,16 @@ __metadata: languageName: node linkType: hard +"react-native-pager-view@npm:^6.3.3": + version: 6.3.3 + resolution: "react-native-pager-view@npm:6.3.3" + peerDependencies: + react: "*" + react-native: "*" + checksum: b4f6ef33a7de34c254aa0cfdcdb7231c256e5d2b5c5d16f16a7c54379829bae7ec1d86e7daf23ef89dbac6088cf36e9678c3009a20e4ba786498848c86113399 + languageName: node + linkType: hard + "react-native-permissions@npm:^4.1.5": version: 4.1.5 resolution: "react-native-permissions@npm:4.1.5" @@ -14669,6 +14695,19 @@ __metadata: languageName: node linkType: hard +"react-native-tab-view@npm:^3.5.2": + version: 3.5.2 + resolution: "react-native-tab-view@npm:3.5.2" + dependencies: + use-latest-callback: ^0.1.5 + peerDependencies: + react: "*" + react-native: "*" + react-native-pager-view: "*" + checksum: bd287e5543881aa662ee55418a3bd5dacb25033425a9fcb0fff21c3a3b96f956af1a77cd9bab4e7a8e94590080a5d8e3cb99cfa8613b19bf6da24bfc9b4942d4 + languageName: node + linkType: hard + "react-native-view-shot@npm:^3.8.0": version: 3.8.0 resolution: "react-native-view-shot@npm:3.8.0" @@ -14789,6 +14828,7 @@ __metadata: "@react-native/metro-config": 0.74.84 "@react-native/typescript-config": 0.74.84 "@react-navigation/bottom-tabs": ^6.6.0 + "@react-navigation/material-top-tabs": ^6.6.14 "@react-navigation/native": ^6.1.17 "@react-navigation/stack": ^6.4.0 "@tanstack/react-query": ^5.51.9 @@ -14822,11 +14862,13 @@ __metadata: react-native-gesture-handler: ^2.17.1 react-native-image-picker: ^7.1.2 react-native-linear-gradient: ^2.8.3 + react-native-pager-view: ^6.3.3 react-native-permissions: ^4.1.5 react-native-reanimated: ^3.14.0 react-native-safe-area-context: ^4.10.8 react-native-screens: ^3.32.0 react-native-svg: ^15.4.0 + react-native-tab-view: ^3.5.2 react-native-view-shot: ^3.8.0 react-native-vision-camera: ^4.5.0 react-test-renderer: 18.2.0 @@ -17100,7 +17142,7 @@ __metadata: languageName: node linkType: hard -"use-latest-callback@npm:^0.1.9": +"use-latest-callback@npm:^0.1.5, use-latest-callback@npm:^0.1.9": version: 0.1.11 resolution: "use-latest-callback@npm:0.1.11" peerDependencies: