diff --git a/.gitignore b/.gitignore index 6adb4dabd3998fe073a69ba5553576d31f732466..5b22b60ca37013558d0d61488d70acfd8f08658a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ /web/node_modules /mobile/node_modules /mobile/.expo -/mobile/metro \ No newline at end of file +/mobile/metro +/mobile/src/common/constants/api.ts +/mobile/%ProgramData%/Microsoft/Windows/UUS/State/_active.uusver +/mobile/assets/audio_prueba.mp3 diff --git a/mobile/app/(tabs)/_layout.tsx b/mobile/app/(tabs)/_layout.tsx index 1081d4af5f1717d706e826a1913879caa4d79966..142967addbb2aa27e5a5936b09d46fe8cdef7a25 100644 --- a/mobile/app/(tabs)/_layout.tsx +++ b/mobile/app/(tabs)/_layout.tsx @@ -1,27 +1,35 @@ import { Redirect, Tabs } from "expo-router"; import { Ionicons } from "@expo/vector-icons"; import { FontAwesome5 } from "@expo/vector-icons"; -import { LIGTHT_THEME } from "../../src/common/constants/theme"; +import { LIGHT_THEME } from "../../src/common/constants/theme"; import { useAuth } from "../../src/auth/contexts/auth_context"; +import { useTranslation } from "react-i18next"; +import { useSetUp } from "../../src/common/contexts/set_up_context"; export default function Layout() { const { user } = useAuth(); + const { isFirstTime } = useSetUp(); + const LANG = useTranslation(); console.log(user); if (!user) { return ; } + + if (isFirstTime) { + return ; + } return ( { if (focused) { return ; @@ -41,7 +49,7 @@ export default function Layout() { { if (focused) { return ; @@ -53,7 +61,7 @@ export default function Layout() { { if (focused) { return ; diff --git a/mobile/app/(tabs)/account.tsx b/mobile/app/(tabs)/account.tsx index 96163b6ccdcbf28044f532227af3257a1b07c582..2b7cfc0876806eec1761f499b30ea82036dc9cad 100644 --- a/mobile/app/(tabs)/account.tsx +++ b/mobile/app/(tabs)/account.tsx @@ -1,4 +1,4 @@ -import { AccountPage } from "../../src/account/screens/account_page"; +import { AccountPage } from "../../src/profile/screens/account_page"; export default function AccountScreen() { return ( diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx index 0024ab5ecc9a36ba126278e5518970346cc1f89c..e31d84675e2a07aae26b574270f838b14b6f7018 100644 --- a/mobile/app/_layout.tsx +++ b/mobile/app/_layout.tsx @@ -1,22 +1,32 @@ import { Stack, Tabs } from "expo-router"; import { DataContextProvider } from "../src/common/contexts/data_context"; -import { LIGTHT_THEME } from "../src/common/constants/theme"; -import { AuthContextProvider, useAuth } from "../src/auth/contexts/auth_context"; +import { LIGHT_THEME } from "../src/common/constants/theme"; +import { + AuthContextProvider, + useAuth, +} from "../src/auth/contexts/auth_context"; import { ActivityIndicator } from "react-native"; import { GestureHandlerRootView } from "react-native-gesture-handler"; import { AudioContextProvider } from "../src/common/contexts/audio_context"; +import { I18nextProvider } from "react-i18next"; +import i18n from "../src/lang/translations"; +import { SetUpContextProvider, useSetUp } from "../src/common/contexts/set_up_context"; export default function Root() { return ( - - - - - - - - - + + + + + + + + + + + + + ); } @@ -33,14 +43,14 @@ const MainLayout = () => { name="(tabs)" options={{ headerShown: false, - statusBarColor: LIGTHT_THEME.color.primary, + statusBarColor: LIGHT_THEME.color.primary, }} /> { name="scan" options={{ title: "Scan", - statusBarColor: LIGTHT_THEME.color.primary, + statusBarColor: LIGHT_THEME.color.primary, headerStyle: { - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, }, headerTitleStyle: { - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, }, headerTitleAlign: "center", - headerTintColor: LIGTHT_THEME.color.white, + headerTintColor: LIGHT_THEME.color.white, + }} + /> + + - - ); }; diff --git a/mobile/app/profile/_layout.tsx b/mobile/app/profile/_layout.tsx index d6a99319a4d2db87a8c7b53d196892a6852c11c1..2d267936290b90e3d7922853babeb54d21d5594e 100644 --- a/mobile/app/profile/_layout.tsx +++ b/mobile/app/profile/_layout.tsx @@ -1,12 +1,33 @@ import { Stack } from "expo-router"; +import { LIGHT_THEME } from "../../src/common/constants/theme"; export default function Layout() { return ( - + + + ); } \ No newline at end of file diff --git a/mobile/app/profile/interests.tsx b/mobile/app/profile/interests.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3e947d44225d8c6735dc2c24584f1a51e62b43e4 --- /dev/null +++ b/mobile/app/profile/interests.tsx @@ -0,0 +1,8 @@ +import { View } from "react-native"; +import { ChangeInterestsScreen } from "../../src/profile/screens/change_interests_screen"; + +export default function Interests() { + return ( + + ); +} \ No newline at end of file diff --git a/mobile/app/profile/set_up.tsx b/mobile/app/profile/set_up.tsx new file mode 100644 index 0000000000000000000000000000000000000000..25d4ff29765af5582b584c17ac07fd308670d299 --- /dev/null +++ b/mobile/app/profile/set_up.tsx @@ -0,0 +1,8 @@ +import { View } from "react-native"; +import { FirstTimeComfigScreen } from "../../src/profile/screens/first_time_config_screen"; + +export default function SetUp() { + return ( + + ); +} \ No newline at end of file diff --git a/mobile/app/sign_up.tsx b/mobile/app/sign_up.tsx index c6f7ba00592207537c0c451f83140ee4536735e2..23250b1a65eee188d3493d1e43b6b957a548678f 100644 --- a/mobile/app/sign_up.tsx +++ b/mobile/app/sign_up.tsx @@ -1,5 +1,5 @@ import { View, StyleSheet, Image, Text, Button } from "react-native"; -import { LIGTHT_THEME } from "../src/common/constants/theme"; +import { LIGHT_THEME } from "../src/common/constants/theme"; import { SignUpForm } from "../src/auth/components/sign_up_form"; import { router } from "expo-router"; import { SignUpPage } from "../src/auth/pages/sign_up_page"; diff --git a/mobile/app/state/[stateId]/town/[townId]/activity/_layout.tsx b/mobile/app/state/[stateId]/town/[townId]/activity/_layout.tsx index 38d73fd47ebb1430275623a52fd5bfd208c87551..7fb512f0b4b854be443550e198d38dcde1b409b0 100644 --- a/mobile/app/state/[stateId]/town/[townId]/activity/_layout.tsx +++ b/mobile/app/state/[stateId]/town/[townId]/activity/_layout.tsx @@ -1,5 +1,5 @@ import { Stack } from "expo-router"; -import { LIGTHT_THEME } from "../../../../../../src/common/constants/theme"; +import { LIGHT_THEME } from "../../../../../../src/common/constants/theme"; export default function ActivitySelectionScreen() { return ( diff --git a/mobile/app/state/[stateId]/town/_layout.tsx b/mobile/app/state/[stateId]/town/_layout.tsx index fe283a441dcc292dd26d691ca040fc040ec136f9..7eb489b5d7004777462c21f4bfbfac6ad5429bc5 100644 --- a/mobile/app/state/[stateId]/town/_layout.tsx +++ b/mobile/app/state/[stateId]/town/_layout.tsx @@ -1,5 +1,5 @@ import { Stack } from "expo-router"; -import { LIGTHT_THEME } from "../../../../src/common/constants/theme"; +import { LIGHT_THEME } from "../../../../src/common/constants/theme"; export default function Layout() { return ( @@ -7,13 +7,13 @@ export default function Layout() { =16", + "react-native": ">=0.57" + } + }, "node_modules/@react-native/assets-registry": { "version": "0.73.1", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.73.1.tgz", @@ -9708,6 +9722,14 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -9761,6 +9783,28 @@ "make-plural": "*" } }, + "node_modules/i18next": { + "version": "23.11.5", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz", + "integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -11206,6 +11250,16 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" + }, + "node_modules/lodash.isobject": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", + "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==" + }, "node_modules/lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", @@ -13410,6 +13464,27 @@ "react": "^16.8.0 || ^17 || ^18" } }, + "node_modules/react-i18next": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz", + "integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==", + "dependencies": { + "@babel/runtime": "^7.23.9", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 23.2.3", + "react": ">= 16.8.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -13469,6 +13544,14 @@ "react": "18.2.0" } }, + "node_modules/react-native-animatable": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/react-native-animatable/-/react-native-animatable-1.3.3.tgz", + "integrity": "sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w==", + "dependencies": { + "prop-types": "^15.7.2" + } + }, "node_modules/react-native-gesture-handler": { "version": "2.14.1", "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.14.1.tgz", @@ -13519,6 +13602,19 @@ } } }, + "node_modules/react-native-modal": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz", + "integrity": "sha512-UB+mjmUtf+miaG/sDhOikRfBOv0gJdBU2ZE1HtFWp6UixW9jCk/bhGdHUgmZljbPpp0RaO/6YiMmQSSK3kkMaw==", + "dependencies": { + "prop-types": "^15.6.2", + "react-native-animatable": "1.3.3" + }, + "peerDependencies": { + "react": "*", + "react-native": ">=0.65.0" + } + }, "node_modules/react-native-modal-datetime-picker": { "version": "17.1.0", "resolved": "https://registry.npmjs.org/react-native-modal-datetime-picker/-/react-native-modal-datetime-picker-17.1.0.tgz", @@ -13531,6 +13627,18 @@ "react-native": ">=0.65.0" } }, + "node_modules/react-native-picker-select": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/react-native-picker-select/-/react-native-picker-select-9.1.3.tgz", + "integrity": "sha512-O2EmlY4Mg5fZWxECTQJBDhO61as6RDbPYYiNoryaa0gmIkWxhANLsZI+ElEVru1h0Fp9UlCFtBDI5MwhHR9AxA==", + "dependencies": { + "lodash.isequal": "^4.5.0", + "lodash.isobject": "^3.0.2" + }, + "peerDependencies": { + "@react-native-picker/picker": "^2.4.0" + } + }, "node_modules/react-native-reanimated": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.3.tgz", @@ -15454,6 +15562,14 @@ "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", diff --git a/mobile/package.json b/mobile/package.json index 0db83aa0c93fb5c595464fec4d902f9b2b512ad6..380929d2fd3a053dabcf821bf5b8440f41d8518c 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -11,8 +11,10 @@ "dependencies": { "@gorhom/bottom-sheet": "^4.6.1", "@react-native-community/datetimepicker": "7.6.1", + "@react-native-community/slider": "4.4.2", "axios": "^1.6.8", "expo": "~50.0.14", + "expo-av": "~13.10.6", "expo-barcode-scanner": "~12.9.3", "expo-camera": "~14.1.1", "expo-checkbox": "~2.7.0", @@ -25,19 +27,22 @@ "expo-secure-store": "~12.8.1", "expo-status-bar": "~1.11.1", "i18n-js": "^4.4.3", + "i18next": "^23.11.5", "nativewind": "^2.0.11", "react": "18.2.0", "react-hook-form": "^7.51.2", + "react-i18next": "^14.1.2", "react-native": "0.73.6", "react-native-gesture-handler": "~2.14.0", + "react-native-maps": "1.10.0", + "react-native-modal": "^13.0.1", "react-native-modal-datetime-picker": "^17.1.0", + "react-native-picker-select": "^9.1.3", "react-native-reanimated": "~3.6.2", "react-native-safe-area-context": "4.8.2", "react-native-screens": "~3.29.0", - "expo-av": "~13.10.6", - "@react-native-community/slider": "4.4.2", - "react-native-maps": "1.10.0", - "react-native-svg": "14.1.0" + "react-native-svg": "14.1.0", + "@react-native-picker/picker": "2.6.1" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/mobile/src/account/screens/account_page.tsx b/mobile/src/account/screens/account_page.tsx deleted file mode 100644 index 229cd7211184ddf95bbcc49e23550a16a07e9dc7..0000000000000000000000000000000000000000 --- a/mobile/src/account/screens/account_page.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { - View, - Text, - Button, - StyleSheet, - Touchable, - TouchableOpacity, -} from "react-native"; -import { useAuth } from "../../auth/contexts/auth_context"; -import { CircleAvatar } from "../../common/components/circle_avatar"; -import { - MaterialIcons, - MaterialCommunityIcons, - FontAwesome, -} from "@expo/vector-icons"; -import { CustomTileButton } from "../../common/components/custom_tile_button"; -import { router } from "expo-router"; -import { LIGTHT_THEME } from "../../common/constants/theme"; - -//TODO: Add source to CircleAvatar -const source = require("../../../assets/avatar.png"); - -export const AccountPage = () => { - const { logout, user } = useAuth(); - return ( - - - - - {user?.name + " " + user?.lastName} - - - - - {/* - } - onPress={() => router.push("/profile/edit")} - /> - } - /> */} - - - - } - /> - - ); -}; - -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: "center", - padding: 20, - backgroundColor: LIGTHT_THEME.color.background, - }, - profilePhotoContainer: { - alignItems: "center", - justifyContent: "center", - width: "100%", - flex: 1 - }, - user_name: { - fontSize: 18, - fontWeight: "bold", - }, -}); diff --git a/mobile/src/auth/components/login_form.tsx b/mobile/src/auth/components/login_form.tsx index e711512cefd88d321b8804ec7b99bcb96d7bb96e..7715bdaf62e733e5622bd2d854a73781e0938745 100644 --- a/mobile/src/auth/components/login_form.tsx +++ b/mobile/src/auth/components/login_form.tsx @@ -1,10 +1,13 @@ import { Control, Controller, FieldValues } from "react-hook-form"; import { ScrollView, StyleSheet, Text, TouchableOpacity, View } from "react-native"; import { CustomTextInput } from "../../common/components/form/text_input"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { LoginFormValues } from "../hooks/useLoggin"; import { OrDivision } from "../../common/components/form/or_division"; -import { LANG } from "../../lang/translations"; +import { AntDesign } from '@expo/vector-icons'; +import { Link } from "expo-router"; +import { useTranslation } from "react-i18next"; +import { LanguageIcon } from "../../lang/components/language_icon"; interface LoginFormProps { control: Control; @@ -12,8 +15,11 @@ interface LoginFormProps { } export const LoginForm = ({ control, onSubmit }: LoginFormProps) => { + const LANG = useTranslation(); + console.log("Lang"+LANG); return ( + {LANG.t('loginScreen.title')} { )} rules={{ required: "Password is required" }} /> + + + Recuperar contraseña + + {LANG.t('loginScreen.loginButton')} @@ -78,7 +89,7 @@ const styles = StyleSheet.create({ mainContainer: { flex: 1, backgroundColor: - LIGTHT_THEME.color.background + LIGHT_THEME.color.background }, imageContainer: { height: "40%", @@ -92,7 +103,7 @@ const styles = StyleSheet.create({ marginBottom: 20, elevation: 5, borderRadius: 10, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, height: "70%", }, loginScroll: { diff --git a/mobile/src/auth/components/sign_up_form.tsx b/mobile/src/auth/components/sign_up_form.tsx index 5d6ee916cf65681a6b6cf76b8a7d9fdde0f311cd..641b33e99d6035a251ca7255a39debe1c166a29e 100644 --- a/mobile/src/auth/components/sign_up_form.tsx +++ b/mobile/src/auth/components/sign_up_form.tsx @@ -7,7 +7,7 @@ import { View, } from "react-native"; import { CustomTextInput } from "../../common/components/form/text_input"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { useLoggin } from "../hooks/useLoggin"; import { OrDivision } from "../../common/components/form/or_division"; import { SignUpFormValues, useSignUp } from "../hooks/useSignUp"; @@ -171,7 +171,7 @@ export const SignUpForm = ({ control, onSubmit }: SignUpFormProps) => { const styles = StyleSheet.create({ mainContainer: { flex: 1, - backgroundColor: LIGTHT_THEME.color.background, + backgroundColor: LIGHT_THEME.color.background, }, imageContainer: { height: "40%", @@ -185,7 +185,7 @@ const styles = StyleSheet.create({ marginBottom: 20, elevation: 5, borderRadius: 10, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, height: "70%", }, loginScroll: { diff --git a/mobile/src/auth/pages/login_page.tsx b/mobile/src/auth/pages/login_page.tsx index 92c5af64fb9765398b53e33746823d7292e57a80..45518bf8281da72d4309a697764a7820cc47bf82 100644 --- a/mobile/src/auth/pages/login_page.tsx +++ b/mobile/src/auth/pages/login_page.tsx @@ -1,16 +1,17 @@ import { View, Image, StyleSheet, Button } from "react-native"; import { LoginForm } from "../components/login_form"; import { useLoggin } from "../hooks/useLoggin"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; -import { LANG } from "../../lang/translations"; import { LanguageIcon } from "../../lang/components/language_icon"; import { ApiRequestStatus } from "../../common/constants/api_request_states"; import { FullPageLoader } from "../../common/components/full_page_loader"; +import { useTranslation } from "react-i18next"; const loginImage = require("../../../assets/login-image.jpg"); export const LoginPage = () => { const { control, onSubmit, requestStatus } = useLoggin(); + const LANG = useTranslation(); if (requestStatus === ApiRequestStatus.LOADING) { return ; @@ -37,7 +38,7 @@ export const LoginPage = () => { const styles = StyleSheet.create({ mainContainer: { flex: 1, - backgroundColor: LIGTHT_THEME.color.background, + backgroundColor: LIGHT_THEME.color.background, }, imageContainer: { height: "40%", @@ -51,7 +52,7 @@ const styles = StyleSheet.create({ marginBottom: 20, elevation: 5, borderRadius: 10, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, height: "70%", }, loginScroll: { diff --git a/mobile/src/auth/pages/sign_up_page.tsx b/mobile/src/auth/pages/sign_up_page.tsx index 38f356a387f55d1a813395905cfe613c48fd388a..5d451997c67914b1a71d3e2eb3fbc30a219be29b 100644 --- a/mobile/src/auth/pages/sign_up_page.tsx +++ b/mobile/src/auth/pages/sign_up_page.tsx @@ -1,7 +1,7 @@ import { View, StyleSheet, Image, Text, Button } from "react-native"; import { router } from "expo-router"; import { SignUpForm } from "../components/sign_up_form"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { useSignUp } from "../hooks/useSignUp"; import { ApiRequestStatus } from "../../common/constants/api_request_states"; import { FullPageLoader } from "../../common/components/full_page_loader"; @@ -33,7 +33,7 @@ export const SignUpPage = () => { const styles = StyleSheet.create({ mainContainer: { flex: 1, - backgroundColor: LIGTHT_THEME.color.background, + backgroundColor: LIGHT_THEME.color.background, }, imageContainer: { height: "40%", @@ -47,7 +47,7 @@ const styles = StyleSheet.create({ marginBottom: 20, elevation: 5, borderRadius: 10, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, height: "70%", }, loginScroll: { diff --git a/mobile/src/common/components/audio_player.tsx b/mobile/src/common/components/audio_player.tsx index 8d68de93ba30af11fd1ebd2fa56856387ec5a110..6de5d55ca5d5e036c62016644ef0e80962a39413 100644 --- a/mobile/src/common/components/audio_player.tsx +++ b/mobile/src/common/components/audio_player.tsx @@ -2,7 +2,7 @@ import { TouchableOpacity, View, StyleSheet, Text } from "react-native"; import { FontAwesome, Feather } from "@expo/vector-icons"; import Slider from "@react-native-community/slider"; import { millisecondsToHourFormat } from "../../utils/time"; -import { LIGTHT_THEME } from "../constants/theme"; +import { LIGHT_THEME } from "../constants/theme"; import { useAudio } from "../contexts/audio_context"; import { useEffect } from "react"; @@ -30,7 +30,7 @@ export const AudioPlayer = () => { { @@ -58,7 +58,7 @@ const styles = StyleSheet.create({ width: "100%", justifyContent: "center", alignItems: "center", - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, gap: 10, }, sliderContainer: { @@ -71,7 +71,7 @@ const styles = StyleSheet.create({ flex: 1, }, hour_text: { - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, fontWeight: "bold", }, }); diff --git a/mobile/src/common/components/custom_tile_button.tsx b/mobile/src/common/components/custom_tile_button.tsx index 501f935bd841308f09da43ae9b78a608f49e9740..f455775a2489307ef6fa53b86c8414851274668c 100644 --- a/mobile/src/common/components/custom_tile_button.tsx +++ b/mobile/src/common/components/custom_tile_button.tsx @@ -1,7 +1,7 @@ import { ReactNode } from "react"; import { TouchableOpacity, View, Text, StyleSheet } from "react-native"; import { MaterialIcons } from "@expo/vector-icons"; -import { LIGTHT_THEME } from "../constants/theme"; +import { LIGHT_THEME } from "../constants/theme"; interface CustomTileButtonProps { leadingIcon?: ReactNode; @@ -41,7 +41,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 10, borderTopWidth: 2, borderTopColor: "#ccc", - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, borderRadius: 5, width: "100%", }, diff --git a/mobile/src/common/components/floating_end_action_button.tsx b/mobile/src/common/components/floating_end_action_button.tsx index ec7d94d6ccf730853b0104977f01a7715c7fed28..758cead3a40e515bb039444b56e5c0e3a4cf661d 100644 --- a/mobile/src/common/components/floating_end_action_button.tsx +++ b/mobile/src/common/components/floating_end_action_button.tsx @@ -1,5 +1,5 @@ import { TouchableOpacity, Text, StyleSheet } from "react-native"; -import { LIGTHT_THEME } from "../constants/theme"; +import { LIGHT_THEME } from "../constants/theme"; interface FloatingEndActionButtonProps { onPress: () => void; @@ -23,7 +23,7 @@ const styles = StyleSheet.create({ position: "absolute", justifyContent: "center", alignItems: "center", - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, borderRadius: 25, bottom: 10, width: 200, @@ -32,7 +32,7 @@ const styles = StyleSheet.create({ alignSelf: "center", }, generate_router_button_text: { - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, fontWeight: "bold", }, }); diff --git a/mobile/src/common/components/form/or_division.tsx b/mobile/src/common/components/form/or_division.tsx index 439db1d9eb84a9194b03e4d5247ece3357588897..cee841d7196d71eadbb5d4fbfff3134f1a73ba5c 100644 --- a/mobile/src/common/components/form/or_division.tsx +++ b/mobile/src/common/components/form/or_division.tsx @@ -1,8 +1,9 @@ import { View, Text, StyleSheet } from "react-native"; -import { LIGTHT_THEME } from "../../constants/theme"; -import { LANG } from "../../../lang/translations"; +import { LIGHT_THEME } from "../../constants/theme"; +import { useTranslation } from "react-i18next"; export const OrDivision = () => { + const LANG = useTranslation(); return ( {LANG.t('common.or')} @@ -14,13 +15,13 @@ const styles = StyleSheet.create({ orDivision: { marginVertical: 30, borderTopWidth: 2, - borderTopColor: LIGTHT_THEME.color.black, + borderTopColor: LIGHT_THEME.color.black, alignItems: "center", }, orText: { fontSize: 16, marginTop: -12, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, width: 40, textAlign: "center", }, diff --git a/mobile/src/common/components/form/text_input.tsx b/mobile/src/common/components/form/text_input.tsx index cd72f6dadd1b356b82c4036e7db48977ae1fd9d2..b15ad3d76c37427f710737cab76ff745f94de407 100644 --- a/mobile/src/common/components/form/text_input.tsx +++ b/mobile/src/common/components/form/text_input.tsx @@ -1,6 +1,7 @@ -import { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { TextInput, Text, StyleSheet, View, Animated, TouchableOpacity, TextInputProps } from "react-native"; -import { LIGTHT_THEME } from "../../constants/theme"; +import { LIGHT_THEME } from "../../constants/theme"; +import { Feather } from '@expo/vector-icons'; interface CustomTextInputProps { isPassword?: boolean; @@ -15,6 +16,7 @@ interface CustomTextInputProps { export const CustomTextInput = ({ textInputProps, label, value, errors, onBlur, editable, isPassword }: CustomTextInputProps) => { const labelFocusAnimation = useRef(new Animated.Value(value.length > 0 ? 1 : 0)).current; const inputRef = useRef(null); + const [showPassword, setShowPassword] = useState(false); const handleFocus = () => { Animated.timing(labelFocusAnimation, { @@ -57,9 +59,20 @@ export const CustomTextInput = ({ textInputProps, label, value, errors, onBlur, onFocus={handleFocus} onBlur={handleBlur} style={styles.input} - secureTextEntry={isPassword} - cursorColor={LIGTHT_THEME.color.black} + secureTextEntry={isPassword && !showPassword} + cursorColor={LIGHT_THEME.color.black} /> + { + isPassword && ( + setShowPassword(!showPassword)} + /> + ) + } { errors ? {errors} : @@ -90,6 +103,11 @@ const styles = StyleSheet.create({ position: "absolute", left: 10, zIndex: 1, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, + }, + showPassword: { + position: "absolute", + right: 10, + zIndex: 2, }, }); diff --git a/mobile/src/common/components/slide_control.tsx b/mobile/src/common/components/slide_control.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a7688124cf008d5df95a73ebe4ea851def70f71 --- /dev/null +++ b/mobile/src/common/components/slide_control.tsx @@ -0,0 +1,67 @@ +import { TouchableOpacity, View, Text, StyleSheet } from "react-native"; +import { LIGHT_THEME } from "../constants/theme"; +import { FontAwesome, MaterialIcons } from "@expo/vector-icons"; + +interface SlideControlProps { + onNext: () => void; + onPrevious: () => void; + onFinish: () => void; + isLast: boolean; + isFirst: boolean; +} + +export const SlideControl = ({ + onNext, + onPrevious, + onFinish, + isFirst, + isLast, +}: SlideControlProps) => { + return ( + + {isFirst ? : ( + + + Previous + + )} + {isLast ? ( + + Finish + + ) : ( + + Next + + + )} + + ); +}; + +export const styles = StyleSheet.create({ + container: { + width: "100%", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + }, + button: { + height: 20, + flexDirection: "row", + justifyContent: "center", + }, + text: { + color: LIGHT_THEME.color.primary, + fontWeight: "bold", + fontSize: 16, + }, +}); diff --git a/mobile/src/common/constants/theme.ts b/mobile/src/common/constants/theme.ts index 57b3464216e88921060099970f995e32bc8f2982..c708fdc212fe5d9c8ed48024bddb49d684a0dcf9 100644 --- a/mobile/src/common/constants/theme.ts +++ b/mobile/src/common/constants/theme.ts @@ -14,11 +14,11 @@ interface Theme { }; } -export const LIGTHT_THEME: Theme = { +export const LIGHT_THEME: Theme = { color: { primary: "rgb(235, 73, 161)", - secondary: "gray", - terciary: "#f0f0f0", + secondary: "#333333", + terciary: "#e1e1e1", background: "#f5f5f5", white: "white", black: "black", diff --git a/mobile/src/common/contexts/data_context.tsx b/mobile/src/common/contexts/data_context.tsx index 1c59103f8d3f58549d92315cbe927acee3ed042d..a9f0f4b40bc16d6a2c79a74194ab0b64669a7e07 100644 --- a/mobile/src/common/contexts/data_context.tsx +++ b/mobile/src/common/contexts/data_context.tsx @@ -15,6 +15,10 @@ import { TravelRepository } from "../../domain/repositories/travel_repository"; import { RouteRepository } from "../../domain/repositories/route_repository"; import { RouteDataSourceDev } from "../../infrastructure/datasource/dev/route_datasource"; import { RouteRepositoryImpl } from "../../infrastructure/repositories/route_repository"; +import { StateDataSourceProd } from "../../infrastructure/datasource/prod/state_datasource"; +import { ProfileRepository } from "../../profile/domain/repositories/profile_repository"; +import { ProfileDataSourceDev } from "../../profile/infrastructure/datasources/dev/profile_datasource"; +import { ProfileRepositoryImpl } from "../../profile/infrastructure/repositories/profile_repository"; type DataContextType = { statesRepository: StateRepository | null; @@ -22,6 +26,7 @@ type DataContextType = { activityRepository: ActivityRepository | null; travelRepository: TravelRepository | null; routeRepository: RouteRepository | null; + profileRepository: ProfileRepository | null; }; type DataContextProviderProps = PropsWithChildren<{}>; @@ -31,7 +36,8 @@ const DataContext = createContext({ authRepository: null, activityRepository: null, travelRepository: null, - routeRepository: null + routeRepository: null, + profileRepository: null }); export const DataContextProvider = ({ children }: DataContextProviderProps) => { @@ -45,13 +51,16 @@ export const DataContextProvider = ({ children }: DataContextProviderProps) => { const travelRepository = new TravelRepositoryImpl(travelDatasource); const routeDatasource = new RouteDataSourceDev(); const routeRepository = new RouteRepositoryImpl(routeDatasource); + const profileDataSource = new ProfileDataSourceDev(); + const profileRepository = new ProfileRepositoryImpl(profileDataSource); const value = { statesRepository, authRepository, activityRepository, travelRepository, - routeRepository + routeRepository, + profileRepository }; return ( diff --git a/mobile/src/common/contexts/set_up_context.tsx b/mobile/src/common/contexts/set_up_context.tsx new file mode 100644 index 0000000000000000000000000000000000000000..beea4d517186030bbc18c46a621e48514416a979 --- /dev/null +++ b/mobile/src/common/contexts/set_up_context.tsx @@ -0,0 +1,42 @@ +import { PropsWithChildren, createContext, useContext, useEffect, useState } from "react"; +import * as SecureStore from 'expo-secure-store'; + +type SetUpContextType = { + isFirstTime: boolean; + setFirstTime: () => Promise; +}; + +type SetUpContextProviderProps = PropsWithChildren<{}>; + +const SetUpContext = createContext({ + isFirstTime: true, + setFirstTime: async () => {} +}); + +export const SetUpContextProvider = ({ children }: SetUpContextProviderProps) => { + console.log((SecureStore.getItem('isFirstTime') === 'false' ? false : true)+" Value"); + const [isFirstTime, setIsFirstTime] = useState(SecureStore.getItem('isFirstTime') === 'false' ? false : true); + const setFirstTime = async () => { + await SecureStore.setItemAsync('isFirstTime', 'false'); + setIsFirstTime(false); + }; + + const value = { + isFirstTime, + setFirstTime + }; + + return ( + + {children} + + ); +}; + +export const useSetUp = () => { + const context = useContext(SetUpContext); + if (context === undefined) { + throw new Error('useSetUp must be used within a SetUpContextProvider'); + } + return context; +} \ No newline at end of file diff --git a/mobile/src/common/domain/entities/option.ts b/mobile/src/common/domain/entities/option.ts new file mode 100644 index 0000000000000000000000000000000000000000..c049b74d973debad80e5b8de65e52dbc6f4dc3d3 --- /dev/null +++ b/mobile/src/common/domain/entities/option.ts @@ -0,0 +1,5 @@ +export interface IOption { + id: number; + name: string; + isSelected: boolean; +} \ No newline at end of file diff --git a/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx b/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx index acca09e4f127df0bfce6acece3f52fe7a11f9c35..4fd826d2db91d43e9e67751b779fc1dec657aee3 100644 --- a/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx +++ b/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx @@ -12,7 +12,7 @@ import { TouchableOpacity, } from "react-native"; import { ActivityInfoEntity } from "../../domain/entities/activity_info_entity"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; interface ActivityBottomSheetProps { @@ -114,7 +114,7 @@ const styles = StyleSheet.create({ do_activity_button: { height: 40, elevation: 5, - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, padding: 10, borderRadius: 20, justifyContent: "center", @@ -122,7 +122,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 20, }, do_activity_text: { - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, fontWeight: "bold", }, description_container: { diff --git a/mobile/src/components/activity_tile/activity_tile.tsx b/mobile/src/components/activity_tile/activity_tile.tsx index e55cf76b3fe956e19f3e25a44a2e9e55d2c00754..bea8a19d35b63f186d85f39a36e0931a76a69c1c 100644 --- a/mobile/src/components/activity_tile/activity_tile.tsx +++ b/mobile/src/components/activity_tile/activity_tile.tsx @@ -1,6 +1,6 @@ import { View, Text, StyleSheet, Image, TouchableOpacity } from "react-native"; import { ActivityInfoEntity } from "../../domain/entities/activity_info_entity"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; interface ActivityTileProps { activity: ActivityInfoEntity; @@ -30,7 +30,7 @@ const styles = StyleSheet.create({ container: { height: 300, width: "100%", - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, elevation: 5, borderWidth: 1, borderRadius: 10, diff --git a/mobile/src/hooks/useGetTravelHistory.ts b/mobile/src/hooks/useGetTravelHistory.ts index 604c269782d54fb0cb82febe9da19f3022bc9e54..69f63e4a019e4e03d454f564f1e630ef29b99bad 100644 --- a/mobile/src/hooks/useGetTravelHistory.ts +++ b/mobile/src/hooks/useGetTravelHistory.ts @@ -2,12 +2,14 @@ import { useEffect, useState } from "react"; import { useDataContext } from "../common/contexts/data_context" import { Route, TravelHistory } from "../domain/entities/travel_history"; import { useGet } from "./useGet"; +import { useTranslation } from "react-i18next"; export enum TravelHistorySection { ACTIVE = "Active Travels", PAST = "Past Travels", } interface SectionItem { + type: string; title: string; data: Route[]; } @@ -15,6 +17,7 @@ interface SectionItem { export const useGetTravelHistory = () => { const { travelRepository } = useDataContext(); const [preparedData, setPreparedData] = useState(null); + const LANG = useTranslation(); const callback = () => travelRepository!.getTravelHistory(); const { data, requestStatus } = useGet(callback); //TODO: Cambiar la destructuración múltiple de pastTravels @@ -23,8 +26,8 @@ export const useGetTravelHistory = () => { const pastTravels = [...data.pastTravels, ...data.pastTravels, ...data.pastTravels, ...data.pastTravels, ...data.pastTravels, ...data.pastTravels,]; const activeTravels = data.activeTravel ? [data.activeTravel] : []; const preparedData = [ - { title: TravelHistorySection.ACTIVE, data: activeTravels }, - { title: TravelHistorySection.PAST, data: pastTravels }, + { type: TravelHistorySection.ACTIVE, data: activeTravels, title: LANG.t("travelHistoryScreen.activeTravelsLabel") }, + { type: TravelHistorySection.PAST, data: pastTravels, title: LANG.t("travelHistoryScreen.pastTravelsLabel") }, ]; setPreparedData(preparedData); } diff --git a/mobile/src/infrastructure/datasource/prod/state_datasource.ts b/mobile/src/infrastructure/datasource/prod/state_datasource.ts index f2289af91cdc9b0cce972eb5db23a624693def0e..6f2c329da1cf35a149854785bbf0d9031d3b5364 100644 --- a/mobile/src/infrastructure/datasource/prod/state_datasource.ts +++ b/mobile/src/infrastructure/datasource/prod/state_datasource.ts @@ -1,11 +1,19 @@ +import axios from "axios"; import { StateDataSource } from "../../../domain/datasources/state_datasource"; import { ActivityInfoEntity } from "../../../domain/entities/activity_info_entity"; import { StateEntity } from "../../../domain/entities/state_entity"; import { TownEntity } from "../../../domain/entities/town_entity"; +import { API_URL } from "../../../common/constants/api"; +import { StateModel } from "../../models/prod/states_model"; +import { stateModelToEntity } from "../../utils/states_utils"; export class StateDataSourceProd implements StateDataSource { - getStates(): Promise { - throw new Error("Method not implemented."); + async getStates(): Promise { + const {status, data} = await axios.get(API_URL + '/state'); + if (status !== 200) { + throw new Error('Error fetching states'); + } + return data.map(stateModelToEntity); } getTowns(stateId: number): Promise { throw new Error("Method not implemented."); diff --git a/mobile/src/infrastructure/models/prod/states_model.ts b/mobile/src/infrastructure/models/prod/states_model.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c9bdb0ce27aac927d96fa48ec4d2bd97ddeba5d --- /dev/null +++ b/mobile/src/infrastructure/models/prod/states_model.ts @@ -0,0 +1,5 @@ +export interface StateModel { + stateId: number, + name: string, + imageURL: string +} \ No newline at end of file diff --git a/mobile/src/infrastructure/utils/states_utils.ts b/mobile/src/infrastructure/utils/states_utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..4083616425aea28b9bc58a8569162652bb547b45 --- /dev/null +++ b/mobile/src/infrastructure/utils/states_utils.ts @@ -0,0 +1,17 @@ +import { API_URL } from "../../common/constants/api"; +import { StateEntity } from "../../domain/entities/state_entity"; +import { StateModel } from "../models/prod/states_model"; + +export const stateModelToEntity = (stateModel: StateModel): StateEntity => { + //TODO: Fix this + let imageURL = stateModel.imageURL.split('/'); + imageURL = imageURL.filter((item) => item !== '' && item !== 'http:' && item !== 'https:'); + imageURL[0] = API_URL; + stateModel.imageURL = imageURL.join('/'); + console.log(stateModel.imageURL); + return { + id: stateModel.stateId, + name: stateModel.name, + imageUri: stateModel.imageURL + } +} \ No newline at end of file diff --git a/mobile/src/lang/components/language_icon.tsx b/mobile/src/lang/components/language_icon.tsx index c418be68a13d04d13efb0452d3f5c1631b7cd956..94c31bcb393397b6fb97ee247b9aef6fc1c7605f 100644 --- a/mobile/src/lang/components/language_icon.tsx +++ b/mobile/src/lang/components/language_icon.tsx @@ -1,18 +1,11 @@ import { Entypo } from '@expo/vector-icons'; import { TouchableOpacity } from 'react-native-gesture-handler'; -import { LANG } from '../translations'; +import { useTranslation } from 'react-i18next'; export const LanguageIcon = () => { + const { i18n } = useTranslation(); const changeLanguage = () => { - if (LANG.locale === 'es') { - // Change to english RTL - LANG.locale = 'en'; - - - } - else { - LANG.locale = 'es'; - } + i18n.changeLanguage(i18n.language === 'en' ? 'es' : 'en'); } return ( diff --git a/mobile/src/lang/english_lang.ts b/mobile/src/lang/english_lang.ts index 991949b71c630317ef2b4f463277e8d6e89297b9..73fb800cb1e9261521b5a08579f3a53750a0aacc 100644 --- a/mobile/src/lang/english_lang.ts +++ b/mobile/src/lang/english_lang.ts @@ -11,6 +11,40 @@ export const ENGLISH_LANG: Lang = { loginButton: "Login", registerButton: "Register", }, + homeScreen:{ + title: "Home", + }, + travelHistoryScreen:{ + title: "Travel history", + activeTravelsLabel: "Active travels", + pastTravelsLabel: "Past travels", + noTravelsLabel: "No travels", + }, + accountScreen:{ + title: "Account", + logoutButton: "Logout", + changeLanguageButton: "Change App Language", + selectLanguage: "Select language", + saveButton: "Save", + }, + selectTownScreen:{ + title: "Select Town", + }, + selectTownActivityScreen:{ + title: "Select Activity", + generateRouteButton: "Generate route", + }, + activityInfoScreen:{ + doActivityButton: "Do activity", + }, + scanScreen:{ + title: "Scan QR code", + }, + tabBar:{ + homeLabel: "Home", + travelHistoryLabel: "Travel history", + accountLabel: "Account", + }, forms : { email: "Email", password: "Password", @@ -27,5 +61,7 @@ export const ENGLISH_LANG: Lang = { }, common : { or: "or", + descriptionLabel: "Description", + showMore: "Show more", } } \ No newline at end of file diff --git a/mobile/src/lang/lang.ts b/mobile/src/lang/lang.ts index 22dd3943b3eb30f6574e6c7f1701eb2e7d9ec0f3..8bd3a094ff9901f72c7f007d59e0c4f6f82d7f67 100644 --- a/mobile/src/lang/lang.ts +++ b/mobile/src/lang/lang.ts @@ -9,6 +9,40 @@ export interface Lang { loginButton: string; registerButton: string; }, + homeScreen:{ + title: string; + }, + travelHistoryScreen:{ + title: string; + activeTravelsLabel: string; + pastTravelsLabel: string; + noTravelsLabel: string; + }, + accountScreen:{ + title: string; + logoutButton: string; + changeLanguageButton: string; + selectLanguage: string; + saveButton: string; + }, + selectTownScreen:{ + title: string; + }, + selectTownActivityScreen:{ + title: string; + generateRouteButton: string; + }, + activityInfoScreen:{ + doActivityButton: string; + }, + scanScreen:{ + title: string; + }, + tabBar:{ + homeLabel: string; + travelHistoryLabel: string; + accountLabel: string; + }, forms : { email: string; password: string; @@ -25,6 +59,8 @@ export interface Lang { }, common : { or: string; + descriptionLabel: string; + showMore: string; } } \ No newline at end of file diff --git a/mobile/src/lang/spanish_lang.ts b/mobile/src/lang/spanish_lang.ts index 9c7eb5fcdb383cff9db2a44ba535f4ae01483660..0d6591c9ecf8f9a8f5b8511299578535a9569076 100644 --- a/mobile/src/lang/spanish_lang.ts +++ b/mobile/src/lang/spanish_lang.ts @@ -11,6 +11,40 @@ export const SPANISH_LANG: Lang = { loginButton: "Iniciar sesión", registerButton: "Registrarse", }, + homeScreen:{ + title: "Inicio", + }, + travelHistoryScreen:{ + title: "Historial de viajes", + activeTravelsLabel: "Viajes activos", + pastTravelsLabel: "Viajes pasados", + noTravelsLabel: "No hay viajes", + }, + accountScreen:{ + title: "Cuenta", + logoutButton: "Cerrar sesión", + changeLanguageButton: "Cambiar idioma de la aplicación", + selectLanguage: "Seleccionar idioma", + saveButton: "Guardar", + }, + selectTownScreen:{ + title: "Seleccionar Pueblo", + }, + selectTownActivityScreen:{ + title: "Seleccionar Actividad", + generateRouteButton: "Generar ruta", + }, + activityInfoScreen:{ + doActivityButton: "Hacer actividad", + }, + scanScreen:{ + title: "Escanear código QR", + }, + tabBar:{ + homeLabel: "Inicio", + travelHistoryLabel: "Historial de viajes", + accountLabel: "Cuenta", + }, forms : { email: "Correo electrónico", password: "Contraseña", @@ -27,5 +61,7 @@ export const SPANISH_LANG: Lang = { }, common : { or: "o", + descriptionLabel: "Descripción", + showMore: "Mostrar más", } }; \ No newline at end of file diff --git a/mobile/src/lang/translations.ts b/mobile/src/lang/translations.ts index a21b25e350aa762239a30abc7ee3f4029683bf29..7bd0b31032751f8b4c0be791475bf4dea6763f1e 100644 --- a/mobile/src/lang/translations.ts +++ b/mobile/src/lang/translations.ts @@ -1,18 +1,36 @@ -import { ENGLISH_LANG } from "./english_lang"; -import { SPANISH_LANG } from "./spanish_lang"; -import { I18n } from 'i18n-js'; +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import * as Localization from 'expo-localization'; +import { SPANISH_LANG } from './spanish_lang'; +import { ENGLISH_LANG } from './english_lang'; -const translations = { - en : ENGLISH_LANG, - es : SPANISH_LANG -} +i18n.use(initReactI18next).init({ + compatibilityJSON: 'v3', // Necesario para compatibilidad con Expo + fallbackLng: 'en', // Idioma de respaldo + resources: { + es: { + translation: SPANISH_LANG + }, + en: { + translation: ENGLISH_LANG + } + }, + interpolation: { + escapeValue: false // React ya hace el escape de valores + } +}); -const LANG = new I18n(translations); +export const AvailableLanguages = [ + { + key: 'en', + value: 'English' + }, + { + key: 'es', + value: 'Español' + } +] -LANG.locale = 'es'; - -LANG.enableFallback = true; - -export { LANG }; +export default i18n; diff --git a/mobile/src/profile/components/birthdate_slide.tsx b/mobile/src/profile/components/birthdate_slide.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5343416d8d781f5c1d17358d6d089d06a549f554 --- /dev/null +++ b/mobile/src/profile/components/birthdate_slide.tsx @@ -0,0 +1,36 @@ +import { View, Text, StyleSheet } from "react-native"; +import { DateTextInput } from "../../common/components/form/date_text_input"; +import { Control, Controller } from "react-hook-form"; +import { SetUpProfileFormValues } from "../hooks/useSetUpProfile"; + +interface BirthdateSlideProps { + control: Control; +} + +export const BirthdateSlide = ({ control }: BirthdateSlideProps) => { + return ( + + Selecciona tu fecha de nacimiento + ( + + )} + name="birthdate" + defaultValue=" " + /> + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + width: "100%", + gap: 20, + }, +}); \ No newline at end of file diff --git a/mobile/src/profile/components/interest_slide.tsx b/mobile/src/profile/components/interest_slide.tsx new file mode 100644 index 0000000000000000000000000000000000000000..23f106339a71a696063004311c5ea4c34963c345 --- /dev/null +++ b/mobile/src/profile/components/interest_slide.tsx @@ -0,0 +1,29 @@ +import { View, Text, StyleSheet } from "react-native"; +import { IOption } from "../../common/domain/entities/option"; +import { MultipleOptionPicker } from "./multiple_option_pickeer"; + +interface InterestSlideProps { + options: IOption[]; + onToogleOption: (optionId: number) => void; +} + +export const InterestSlide = ({ options, onToogleOption }: InterestSlideProps) => { + return ( + + + Selecciona las categorías que te interesan, puedes cambiarlos en la + pestaña de + {` Cuenta > Cambiar intereses`} + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, +}); diff --git a/mobile/src/profile/components/multiple_option_pickeer.tsx b/mobile/src/profile/components/multiple_option_pickeer.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3383f8ff4635c500376980fa13a6c51386bd0da3 --- /dev/null +++ b/mobile/src/profile/components/multiple_option_pickeer.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; +import { ScrollView, Text, TouchableOpacity, StyleSheet, View } from "react-native"; +import { LIGHT_THEME } from "../../common/constants/theme"; +import { IOption } from "../../common/domain/entities/option"; + +interface MultipleOptionPickerProps { + options: IOption[]; + toogleOption: (optionId: number) => void; +} + +export const MultipleOptionPicker = ({ options, toogleOption }: MultipleOptionPickerProps) => { + + return ( + + {options.map(option => ( + toogleOption(option.id)} + style={{...styles.optionBtn, backgroundColor: option.isSelected ? LIGHT_THEME.color.primary : LIGHT_THEME.color.terciary}} + > + {option.name} + + ))} + + ); +} + +const styles = StyleSheet.create({ + container : { + padding: 20, + flexWrap: "wrap", + flexDirection: "row", + gap: 10, + width: "100%", + }, + optionBtn: { + paddingVertical: 10, + paddingHorizontal: 20, + height: 40, + borderRadius: 20, + }, + optionText: { + fontSize: 16, + }, +}); diff --git a/mobile/src/profile/domain/datasources/profile_datasource.ts b/mobile/src/profile/domain/datasources/profile_datasource.ts new file mode 100644 index 0000000000000000000000000000000000000000..28bc6c33ac5bb3cb383b954dbf938d321e08d274 --- /dev/null +++ b/mobile/src/profile/domain/datasources/profile_datasource.ts @@ -0,0 +1,7 @@ +import { IOption } from "../../../common/domain/entities/option"; + +export interface ProfileDataSource { + getInterests: () => Promise; + saveInterests: (options: IOption[]) => Promise; + setUpProfile: (birthdate: string, interests: IOption[]) => Promise; +}; \ No newline at end of file diff --git a/mobile/src/profile/domain/repositories/profile_repository.ts b/mobile/src/profile/domain/repositories/profile_repository.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f8164b9fd5eb8218525f30a9de5331f6b60e050 --- /dev/null +++ b/mobile/src/profile/domain/repositories/profile_repository.ts @@ -0,0 +1,7 @@ +import { IOption } from "../../../common/domain/entities/option"; + +export interface ProfileRepository { + getInterests: () => Promise; + saveInterests: (options: IOption[]) => Promise; + setUpProfile: (birthdate: string, interests: IOption[]) => Promise; +}; \ No newline at end of file diff --git a/mobile/src/profile/hooks/useGetInterests.ts b/mobile/src/profile/hooks/useGetInterests.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c1a885dfc84597988fad08347a5e3b186174bfe --- /dev/null +++ b/mobile/src/profile/hooks/useGetInterests.ts @@ -0,0 +1,12 @@ +import { useDataContext } from "../../common/contexts/data_context" +import { useGet } from "../../hooks/useGet"; + +export const useGetInterests = () => { + const { profileRepository } = useDataContext(); + const callback = async () => { + return profileRepository!.getInterests(); + }; + const { data: interests, requestStatus } = useGet(callback); + + return { interests, requestStatus }; +}; \ No newline at end of file diff --git a/mobile/src/profile/hooks/useSelectInterests.ts b/mobile/src/profile/hooks/useSelectInterests.ts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/mobile/src/profile/hooks/useSetUpProfile.ts b/mobile/src/profile/hooks/useSetUpProfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e0ef97beebfefa38ce8f267a679be8e6afd2bd94 --- /dev/null +++ b/mobile/src/profile/hooks/useSetUpProfile.ts @@ -0,0 +1,44 @@ +import { set, useForm } from "react-hook-form"; +import { useGetInterests } from "./useGetInterests"; +import { IOption } from "../../common/domain/entities/option"; +import { useEffect, useState } from "react"; +import { ApiRequestStatus } from "../../common/constants/api_request_states"; + +export type SetUpProfileFormValues = { + interests: number[]; + birthdate: string; +}; + +export const useSetUpProfile = () => { + const { control, handleSubmit, setValue } = useForm(); + const { interests: allCategories, requestStatus } = useGetInterests(); + // TODO: Si se agregan mas campos que requieran datos de la API, debemos procurar que todos los request status esten en success + const [interests, setInterests] = useState([]); + + useEffect(() => { + if (requestStatus === ApiRequestStatus.SUCCESS && allCategories && allCategories.length > 0) { + setInterests([...allCategories]); + } + }, [requestStatus]); + + const toogleInterest = (id: number) => { + console.log("toogle"); + const newInterests = interests.map((interest) => { + if (interest.id === id) { + return { ...interest, isSelected: !interest.isSelected }; + } + return interest; + }); + setInterests(newInterests); + }; + + const onSubmit = async () => { + setValue("interests", interests.filter((interest) => interest.isSelected).map((interest) => interest.id)); + await handleSubmit((data) => { + //TODO: Implementar la logica de envio de datos + //TODO: Verificar si se enviará la fecha de nacimiento y los intereses en el mismo request o por separado + console.log(data); + })(); + }; + return { control, onSubmit, toogleInterest, interests, requestStatus }; +}; diff --git a/mobile/src/profile/hooks/useSlideControl.ts b/mobile/src/profile/hooks/useSlideControl.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7bb55720520b470b014651b0774c6f25af48b66 --- /dev/null +++ b/mobile/src/profile/hooks/useSlideControl.ts @@ -0,0 +1,15 @@ +import { useState } from "react"; + +export const useSlideControl = ( onFinish: () => void) => { + const [currentSlide, setCurrentSlide] = useState(0); + + const onNext = () => { + setCurrentSlide(currentSlide + 1); + }; + + const onPrevious = () => { + setCurrentSlide(currentSlide - 1); + }; + + return { currentSlide, onNext, onPrevious, onFinish }; +}; \ No newline at end of file diff --git a/mobile/src/profile/infrastructure/datasources/dev/profile_datasource.ts b/mobile/src/profile/infrastructure/datasources/dev/profile_datasource.ts new file mode 100644 index 0000000000000000000000000000000000000000..1bf3b48e938501e80d530658116759be77c6264d --- /dev/null +++ b/mobile/src/profile/infrastructure/datasources/dev/profile_datasource.ts @@ -0,0 +1,26 @@ +import { IOption } from '../../../../common/domain/entities/option'; +import { ProfileDataSource } from '../../../domain/datasources/profile_datasource'; +export class ProfileDataSourceDev implements ProfileDataSource { + async getInterests(): Promise { + return [ + { id: 1, name: 'Tecnología', isSelected: false }, + { id: 2, name: 'Deportes', isSelected: false }, + { id: 3, name: 'Cine', isSelected: false}, + { id: 4, name: 'Música', isSelected: false }, + { id: 5, name: 'Ciencia', isSelected: false }, + { id: 6, name: 'Historia', isSelected: false }, + { id: 7, name: 'Arte', isSelected: false }, + { id: 8, name: 'Cocina', isSelected: false }, + { id: 9, name: 'Viajes', isSelected: false }, + { id: 10, name: 'Moda', isSelected: false }, + ]; + } + + async saveInterests(options: IOption[]): Promise { + console.log('Saving interests', options); + } + + async setUpProfile(birthdate: string, interests: IOption[]): Promise { + console.log('Setting up profile', birthdate, interests); + } +} \ No newline at end of file diff --git a/mobile/src/profile/infrastructure/repositories/profile_repository.ts b/mobile/src/profile/infrastructure/repositories/profile_repository.ts new file mode 100644 index 0000000000000000000000000000000000000000..a71049bc530712c83551f09dda85e9a022352f89 --- /dev/null +++ b/mobile/src/profile/infrastructure/repositories/profile_repository.ts @@ -0,0 +1,18 @@ +import { IOption } from "../../../common/domain/entities/option"; +import { ProfileDataSource } from "../../domain/datasources/profile_datasource"; +import { ProfileRepository } from "../../domain/repositories/profile_repository"; + +export class ProfileRepositoryImpl implements ProfileRepository { + constructor( + private dataSource: ProfileDataSource + ){} + async getInterests() { + return this.dataSource.getInterests(); + } + async saveInterests(options: IOption[]) { + return this.dataSource.saveInterests(options); + } + async setUpProfile(birthdate: string, interests: IOption[]) { + return this.dataSource.setUpProfile(birthdate, interests); + } +} \ No newline at end of file diff --git a/mobile/src/profile/screens/account_page.tsx b/mobile/src/profile/screens/account_page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3bd39f9819b28aacc7a200452b3781fa14170f76 --- /dev/null +++ b/mobile/src/profile/screens/account_page.tsx @@ -0,0 +1,186 @@ +import { + View, + Text, + Button, + StyleSheet, + Touchable, + TouchableOpacity, +} from "react-native"; +import { useAuth } from "../../auth/contexts/auth_context"; +import { CircleAvatar } from "../../common/components/circle_avatar"; +import { + MaterialIcons, + MaterialCommunityIcons, + FontAwesome, +} from "@expo/vector-icons"; +import { CustomTileButton } from "../../common/components/custom_tile_button"; +import { router } from "expo-router"; +import { LIGHT_THEME } from "../../common/constants/theme"; +import { useRef, useState } from "react"; +import Modal from "react-native-modal"; +import { set } from "react-hook-form"; +import { AntDesign } from "@expo/vector-icons"; +import RNPickerSelect from 'react-native-picker-select'; +import { AvailableLanguages } from "../../lang/translations"; +import i18n from 'i18next'; +import { useTranslation } from "react-i18next"; + +//TODO: Add source to CircleAvatar +const source = require("../../../assets/avatar.png"); + +export const AccountPage = () => { + const { logout, user } = useAuth(); + const LANG = useTranslation(); + const [isModalVisible, setModalVisible] = useState(false); + return ( + + + + + {user?.name + " " + user?.lastName} + + + + + {/* + } + onPress={() => router.push("/profile/edit")} + /> + } + />*/} + } + onPress={() => setModalVisible(true)} + /> + setModalVisible(false)} + /> + } + onPress={() => router.push("/profile/interests")} + /> + + } + /> + + ); +}; + +interface ChangeLanguageModalProps { + onClose: () => void; + isVisible: boolean; +} + +const ChangeLanguageModal = ({ + onClose, + isVisible, +}: ChangeLanguageModalProps) => { + const [selectedLanguage, setSelectedLanguage] = useState(null); + const {i18n} = useTranslation(); + const onSave = () => { + i18n.changeLanguage(selectedLanguage || 'en'); + onClose(); + } + return ( + + + + Select Language + setSelectedLanguage(value)} + items={AvailableLanguages.map((lang) => ({ + label: lang.value, + value: lang.key, + })) + } + /> + + Save + + + + ); +}; + +const modalStyles = StyleSheet.create({ + modal: { + justifyContent: "center", + alignItems: "center", + }, + modalContainer: { + width: "90%", + aspectRatio: 1, + backgroundColor: "white", + borderRadius: 10, + padding: 20, + justifyContent: "space-around", + alignItems: "center", + }, + closeButton: { + position: "absolute", + top: 10, + right: 10, + }, + selectLanguageText: { + fontSize: 20, + fontWeight: "bold", + }, + saveBtn: { + backgroundColor: LIGHT_THEME.color.primary, + padding: 10, + borderRadius: 20, + height: 40, + width: "70%", + justifyContent: "center", + alignItems: "center", + }, + saveBtnText: { + color: "white", + fontWeight: "bold", + } +}); + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: "center", + padding: 20, + backgroundColor: LIGHT_THEME.color.background, + }, + profilePhotoContainer: { + alignItems: "center", + justifyContent: "center", + width: "100%", + flex: 1, + }, + user_name: { + fontSize: 18, + fontWeight: "bold", + }, +}); diff --git a/mobile/src/profile/screens/change_interests_screen.tsx b/mobile/src/profile/screens/change_interests_screen.tsx new file mode 100644 index 0000000000000000000000000000000000000000..c08f54de835a14d60bef76b967a746322beb55c5 --- /dev/null +++ b/mobile/src/profile/screens/change_interests_screen.tsx @@ -0,0 +1,109 @@ +import { View, StyleSheet, Text } from "react-native"; +import { LIGHT_THEME } from "../../common/constants/theme"; +import { ScrollView } from "react-native-gesture-handler"; +import { useState } from "react"; +import { MultipleOptionPicker } from "../components/multiple_option_pickeer"; + +export const ChangeInterestsScreen = () => { + const [options, setOptions] = useState( [ + { + id: 1, + name: "Arquitectura", + isSelected: false, + }, + { + id: 2, + name: "Ciencia", + isSelected: false, + }, + { + id: 3, + name: "Cultura", + isSelected: false, + }, + { + id: 4, + name: "Deportes", + isSelected: false, + }, + { + id: 5, + name: "Economía", + isSelected: false, + }, + { + id: 6, + name: "Educación", + isSelected: false, + }, + { + id: 7, + name: "Entretenimiento", + isSelected: false, + }, + { + id: 8, + name: "Gastronomía", + isSelected: false, + }, + { + id: 9, + name: "Historia", + isSelected: false, + }, + { + id: 10, + name: "Moda", + isSelected: false, + }, + { + id: 11, + name: "Música", + isSelected: false, + }, + { + id: 12, + name: "Política", + isSelected: false, + }, + { + id: 13, + name: "Salud", + isSelected: false, + }, + { + id: 14, + name: "Tecnología", + isSelected: false, + }, + ]); + + + const onToogleOption = (optionId: number) => { + setOptions( + options.map((option) => + option.id === optionId + ? { ...option, isSelected: !option.isSelected } + : option + ) + ); + }; + + return ( + + + {`Selecciona las categorías que te interesan, puedes cambiarlos en la pestaña de cuenta > Cambiar intereses`} + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: "center", + padding: 20, + backgroundColor: LIGHT_THEME.color.background, + }, +}); diff --git a/mobile/src/profile/screens/first_time_config_screen.tsx b/mobile/src/profile/screens/first_time_config_screen.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d5fa60225e0417b2ea131b2bb5250099dec110a8 --- /dev/null +++ b/mobile/src/profile/screens/first_time_config_screen.tsx @@ -0,0 +1,51 @@ +import { View, StyleSheet, Text } from "react-native"; +import { LIGHT_THEME } from "../../common/constants/theme"; +import { ScrollView } from "react-native-gesture-handler"; +import { useState } from "react"; +import { + MultipleOptionPicker, +} from "../components/multiple_option_pickeer"; +import { DateTextInput } from "../../common/components/form/date_text_input"; +import { TouchableOpacity } from "@gorhom/bottom-sheet"; +import { SlideControl } from "../../common/components/slide_control"; +import { InterestSlide } from "../components/interest_slide"; +import { BirthdateSlide } from "../components/birthdate_slide"; +import { useSetUpProfile } from "../hooks/useSetUpProfile"; +import { useSlideControl } from "../hooks/useSlideControl"; +import { router } from "expo-router"; + +export const FirstTimeComfigScreen = () => { + const { onSubmit, toogleInterest, interests, control } = useSetUpProfile(); + const onFinishCallback = () => { + onSubmit(); + }; + console.log('render'); + const { onFinish, onNext, onPrevious, currentSlide } = useSlideControl(onFinishCallback); + const slides = [ + , + , + ]; + + return ( + + {slides[currentSlide]} + + + ); +}; + + +const styles = StyleSheet.create({ + mainContainer: { + flex: 1, + alignItems: "center", + padding: 20, + }, + container: { + flex: 1, + }, + controlsContainer: { + flexDirection: "row", + justifyContent: "space-between", + }, +}); diff --git a/mobile/src/route/components/maps/custom_map_marker.tsx b/mobile/src/route/components/maps/custom_map_marker.tsx index 9fc17b8aba175fae89bd2f4f0d3104be68dd26eb..a2757fed5a3372f40deb5a7c907031289d051846 100644 --- a/mobile/src/route/components/maps/custom_map_marker.tsx +++ b/mobile/src/route/components/maps/custom_map_marker.tsx @@ -1,6 +1,6 @@ import { View, Image, Text } from "react-native"; import { Callout, Marker } from "react-native-maps"; -import { LIGTHT_THEME } from "../../../common/constants/theme"; +import { LIGHT_THEME } from "../../../common/constants/theme"; import { SVGMarker } from "./svg_marker"; interface CustomMapMarkerProps { @@ -61,7 +61,7 @@ export const CustomMapMarker = ({ height: 30, width: "70%", borderRadius: 10, - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, justifyContent: "center", alignItems: "center", }}> diff --git a/mobile/src/route/components/route_activity_tile.tsx b/mobile/src/route/components/route_activity_tile.tsx index c7387da7539a469d41c538c05717757a47404632..a94fc48cd95a4d5a8db27cfa1948f868f33d356f 100644 --- a/mobile/src/route/components/route_activity_tile.tsx +++ b/mobile/src/route/components/route_activity_tile.tsx @@ -1,7 +1,7 @@ import { View, StyleSheet, Text, Image } from "react-native"; import { ActivityRouteEntity } from "../../domain/entities/activity_info_entity"; import { Entypo } from "@expo/vector-icons"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { FlatList } from "react-native-gesture-handler"; interface RouteActivityTileProps { @@ -74,7 +74,7 @@ const styles = StyleSheet.create({ activityContainer: { flex: 1, margin: 10, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, elevation: 5, padding: 10, borderRadius: 10, @@ -90,13 +90,13 @@ const styles = StyleSheet.create({ fontWeight: "bold", }, tag: { - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, height: 30, paddingHorizontal: 10, paddingVertical: 5, borderRadius: 15, marginRight: 10, - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, justifyContent: "center", alignItems: "center", } diff --git a/mobile/src/route/screens/route_preview.tsx b/mobile/src/route/screens/route_preview.tsx index a30e32c07a5357e9d61c5a669c5f22adb7f6f037..3dc00e2bdb35d9e016e8d2966d0e100a33646ec5 100644 --- a/mobile/src/route/screens/route_preview.tsx +++ b/mobile/src/route/screens/route_preview.tsx @@ -5,7 +5,7 @@ import { FullPageLoader } from "../../common/components/full_page_loader"; import { RouteActivityTile } from "../components/route_activity_tile"; import { TouchableOpacity } from "react-native-gesture-handler"; import { router } from "expo-router"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { FloatingBackButton } from "../../common/components/floating_back_button"; import { FloatingEndActionButton } from "../../common/components/floating_end_action_button"; diff --git a/mobile/src/screens/activity_description/activity_description_page.tsx b/mobile/src/screens/activity_description/activity_description_page.tsx index 24dcc11b6e2a640cf98917ffa29d4121c3bbd7f8..77a0a9ed19f0db0927e6ba53c4b2cb4dff5286a6 100644 --- a/mobile/src/screens/activity_description/activity_description_page.tsx +++ b/mobile/src/screens/activity_description/activity_description_page.tsx @@ -16,7 +16,7 @@ import { Ionicons } from "@expo/vector-icons"; import { useCallback, useEffect, useRef, useState } from "react"; import { ActivityBottomSheet } from "../../components/activity_bottom_sheet/activity_bottom_sheet"; import * as ScreenOrientation from "expo-screen-orientation"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { useScreenOrientation } from "../../hooks/useScreenOrientation"; import { useRotationEnabled } from "../../hooks/useRotationEnabled"; import { FloatingBackButton } from "../../common/components/floating_back_button"; @@ -100,7 +100,7 @@ const styles = StyleSheet.create({ container: { height: "100%", width: "100%", - backgroundColor: LIGTHT_THEME.color.black, + backgroundColor: LIGHT_THEME.color.black, alignItems: "center", justifyContent: "flex-start", }, diff --git a/mobile/src/screens/activity_point/activity_point.tsx b/mobile/src/screens/activity_point/activity_point.tsx index d0f7254860d7558f6abaeeab62c3da0797b400dd..7035470f028a8776cdc46daceca0bc1886602673 100644 --- a/mobile/src/screens/activity_point/activity_point.tsx +++ b/mobile/src/screens/activity_point/activity_point.tsx @@ -5,7 +5,7 @@ import { useGetActivityPoint } from "../../hooks/useGetActivityPoint"; import { ScrollView } from "react-native-gesture-handler"; import { AudioPlayer } from "../../common/components/audio_player"; import { TouchableOpacity } from "@gorhom/bottom-sheet"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; import { useAudio } from "../../common/contexts/audio_context"; import { memo, useEffect } from "react"; @@ -115,7 +115,7 @@ const styles = StyleSheet.create({ width: "70%", }, endActivityButton: { - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, padding: 10, borderRadius: 25, alignItems: "center", @@ -124,7 +124,7 @@ const styles = StyleSheet.create({ height: 50 }, endActivityButtonText: { - color: LIGTHT_THEME.color.white, + color: LIGHT_THEME.color.white, fontWeight: "bold", fontSize: 16, } diff --git a/mobile/src/screens/edit_profile/edit_profile_page.tsx b/mobile/src/screens/edit_profile/edit_profile_page.tsx index 4cd987f0c9892c8e510bcec28ba8482c0d483a0c..701b0e0d97c3d79a3cf2c7e7653b3f16a32e5a81 100644 --- a/mobile/src/screens/edit_profile/edit_profile_page.tsx +++ b/mobile/src/screens/edit_profile/edit_profile_page.tsx @@ -6,7 +6,7 @@ import { CustomTextInput } from "../../common/components/form/text_input"; import Checkbox from "expo-checkbox"; import { useState } from "react"; import { TouchableOpacity } from "@gorhom/bottom-sheet"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { CircleAvatar } from "../../common/components/circle_avatar"; import { MaterialIcons } from "@expo/vector-icons"; import { ScrollView } from "react-native-gesture-handler"; @@ -26,7 +26,7 @@ export const EditProfilePage = () => { alignItems: "center", gap: 20, padding: 20, - backgroundColor: LIGTHT_THEME.color.white, + backgroundColor: LIGHT_THEME.color.white, }} > @@ -34,10 +34,11 @@ export const EditProfilePage = () => { source={profileImage ? { uri: profileImage } : avatarSource} size={100} /> + { formState: { errors }, }) => ( )} rules={{ required: "Name is required" }} @@ -72,11 +77,15 @@ export const EditProfilePage = () => { formState: { errors }, }) => ( )} rules={{ required: "Last name is required" }} @@ -91,7 +100,7 @@ export const EditProfilePage = () => { const styles = StyleSheet.create({ saveBtn: { - backgroundColor: LIGTHT_THEME.color.primary, + backgroundColor: LIGHT_THEME.color.primary, height: 40, width: 100, padding: 10, diff --git a/mobile/src/screens/page_styles.tsx b/mobile/src/screens/page_styles.tsx index a89fd2f43531dcf4dee74df59b11a5af496bf5c0..90ee7303d3a1182b211689525d8ace31ee41e308 100644 --- a/mobile/src/screens/page_styles.tsx +++ b/mobile/src/screens/page_styles.tsx @@ -1,11 +1,11 @@ import { StyleSheet } from "react-native" -import { LIGTHT_THEME } from "../common/constants/theme"; +import { LIGHT_THEME } from "../common/constants/theme"; export const pageStyles = StyleSheet.create({ page_container: { flex: 1, alignItems: 'center', justifyContent: 'center', - backgroundColor: LIGTHT_THEME.color.background + backgroundColor: LIGHT_THEME.color.background } }); \ No newline at end of file diff --git a/mobile/src/screens/town_activities/town_activities_page.tsx b/mobile/src/screens/town_activities/town_activities_page.tsx index 19aa221f43725de16868c53fdbba3b583ac36d0d..5cfa1a3aab5feafc11e53c6a9a979b8ca52e7672 100644 --- a/mobile/src/screens/town_activities/town_activities_page.tsx +++ b/mobile/src/screens/town_activities/town_activities_page.tsx @@ -11,7 +11,7 @@ import { FullPageLoader } from "../../common/components/full_page_loader"; import { ApiRequestStatus } from "../../common/constants/api_request_states"; import { useGetActivities } from "../../hooks/useGetActivities"; import { ActivityTile } from "../../components/activity_tile/activity_tile"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; import { FloatingEndActionButton } from "../../common/components/floating_end_action_button"; import { useState } from "react"; diff --git a/mobile/src/screens/travel_history/travel_history_page.tsx b/mobile/src/screens/travel_history/travel_history_page.tsx index 7a52c7092d1ddd490dadd3cc4a63887a57ff690b..5dd1d2a6b484a93090c918ca01c609401644dd1e 100644 --- a/mobile/src/screens/travel_history/travel_history_page.tsx +++ b/mobile/src/screens/travel_history/travel_history_page.tsx @@ -6,7 +6,7 @@ import { import { ApiRequestStatus } from "../../common/constants/api_request_states"; import { FullPageLoader } from "../../common/components/full_page_loader"; import { CustomTileButton } from "../../common/components/custom_tile_button"; -import { LIGTHT_THEME } from "../../common/constants/theme"; +import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; export const TravelHistoryPage = () => { @@ -38,7 +38,7 @@ export const TravelHistoryPage = () => { scrollEnabled={true} keyExtractor={(item, index) => item.id.toString() + index} renderItem={({ item, section }) => { - switch (section.title) { + switch (section.type) { case TravelHistorySection.ACTIVE: return (