From 00f2d610a596a43cd6037e15f00c6f40a5e78685 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:40:12 -0600 Subject: [PATCH 01/37] =?UTF-8?q?Se=20agregaron=20las=20funciones=20para?= =?UTF-8?q?=20cambiar=20entre=20p=C3=A1ginas=20en=20el=20caroussel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screens/state_selection/state_selection_page.tsx | 10 +++++++++- .../src/screens/town_selection/town_selection_page.tsx | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mobile/src/screens/state_selection/state_selection_page.tsx b/mobile/src/screens/state_selection/state_selection_page.tsx index b0d4497e..7078b4c6 100644 --- a/mobile/src/screens/state_selection/state_selection_page.tsx +++ b/mobile/src/screens/state_selection/state_selection_page.tsx @@ -3,9 +3,12 @@ import { pageStyles } from '../page_styles'; import { useGetStates } from "../../hooks/useGetStates"; import { ApiRequestStatus } from "../../constants/api_request_states"; import { Caroussel } from "../../components/caroussel/caroussel"; +import { useCallback } from "react"; +import { router, useNavigation } from "expo-router"; export const StateSelectionPage = () => { const { data, requestStatus } = useGetStates(); + if (requestStatus === ApiRequestStatus.LOADING) { return ( @@ -13,9 +16,14 @@ export const StateSelectionPage = () => { ); } + + const handleOnPress = (id: number) => { + router.push(`/state?id=${id}`); + }; + return ( - + ); } \ No newline at end of file diff --git a/mobile/src/screens/town_selection/town_selection_page.tsx b/mobile/src/screens/town_selection/town_selection_page.tsx index 24fff635..17e7d0ee 100644 --- a/mobile/src/screens/town_selection/town_selection_page.tsx +++ b/mobile/src/screens/town_selection/town_selection_page.tsx @@ -4,6 +4,7 @@ import { useGetStates } from "../../hooks/useGetStates"; import { ApiRequestStatus } from "../../constants/api_request_states"; import { Caroussel } from "../../components/caroussel/caroussel"; import { useGetTowns } from "../../hooks/useGetTowns"; +import { router } from "expo-router"; interface TownSelectionPageProps { stateId: number; @@ -18,9 +19,14 @@ export const TownSelectionPage = ({ stateId }: TownSelectionPageProps) => { ); } + + const handleTownSelection = (townId: number) => { + router.push(`/state/${stateId}/town?townId=${townId}`); + } + return ( - + ); } \ No newline at end of file -- GitLab From 9d9b93a234c4a1fae02098fe62ea84fb74c70919 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:41:11 -0600 Subject: [PATCH 02/37] =?UTF-8?q?Se=20agreg=C3=B3=20el=20background=20anim?= =?UTF-8?q?ado=20a=20las=20paginas=20con=20caroussel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../state_selection/state_selection_page.tsx | 53 ++++++----- .../town_selection/town_selection_page.tsx | 88 ++++++++++++++----- 2 files changed, 100 insertions(+), 41 deletions(-) diff --git a/mobile/src/screens/state_selection/state_selection_page.tsx b/mobile/src/screens/state_selection/state_selection_page.tsx index 7078b4c6..0e7bca16 100644 --- a/mobile/src/screens/state_selection/state_selection_page.tsx +++ b/mobile/src/screens/state_selection/state_selection_page.tsx @@ -1,29 +1,40 @@ -import { View, Text, ActivityIndicator } from "react-native"; -import { pageStyles } from '../page_styles'; +import { View, ActivityIndicator } from "react-native"; +import { pageStyles } from "../page_styles"; import { useGetStates } from "../../hooks/useGetStates"; import { ApiRequestStatus } from "../../constants/api_request_states"; import { Caroussel } from "../../components/caroussel/caroussel"; -import { useCallback } from "react"; -import { router, useNavigation } from "expo-router"; +import { router } from "expo-router"; +import { useAnimatedSelectedIndex } from "../../hooks/useAnimatedSelectedIndex"; +import { AnimatedBackground } from "../../components/animated_background/animated_background"; export const StateSelectionPage = () => { - const { data, requestStatus } = useGetStates(); - - if (requestStatus === ApiRequestStatus.LOADING) { - return ( - - - - ); - } - - const handleOnPress = (id: number) => { - router.push(`/state?id=${id}`); - }; + const { data, requestStatus } = useGetStates(); + const { selectedStateIndex, onIndexChange, backgroundImageAnimation } = + useAnimatedSelectedIndex(200, 200); + if (requestStatus === ApiRequestStatus.LOADING) { return ( - - - + + + ); -} \ No newline at end of file + } + + const handleOnPress = (id: number) => { + router.push(`/state?id=${id}`); + }; + + return ( + + + + + ); +}; diff --git a/mobile/src/screens/town_selection/town_selection_page.tsx b/mobile/src/screens/town_selection/town_selection_page.tsx index 17e7d0ee..aea752ee 100644 --- a/mobile/src/screens/town_selection/town_selection_page.tsx +++ b/mobile/src/screens/town_selection/town_selection_page.tsx @@ -1,32 +1,80 @@ -import { View, Text, ActivityIndicator } from "react-native"; -import { pageStyles } from '../page_styles'; +import { View, Text, ActivityIndicator, StyleSheet } from "react-native"; +import { pageStyles } from "../page_styles"; import { useGetStates } from "../../hooks/useGetStates"; import { ApiRequestStatus } from "../../constants/api_request_states"; import { Caroussel } from "../../components/caroussel/caroussel"; import { useGetTowns } from "../../hooks/useGetTowns"; import { router } from "expo-router"; +import { useCallback, useState } from "react"; +import { useAnimatedSelectedIndex } from "../../hooks/useAnimatedSelectedIndex"; +import { AnimatedBackground } from "../../components/animated_background/animated_background"; +import BottomSheet, { BottomSheetView } from "@gorhom/bottom-sheet"; interface TownSelectionPageProps { - stateId: number; -}; + stateId: number; +} + +const snapPoints = ["15%", "50%"]; export const TownSelectionPage = ({ stateId }: TownSelectionPageProps) => { - const { data, requestStatus } = useGetTowns(stateId); - if (requestStatus === ApiRequestStatus.LOADING) { - return ( - - - - ); - } - - const handleTownSelection = (townId: number) => { - router.push(`/state/${stateId}/town?townId=${townId}`); - } + const { data, requestStatus } = useGetTowns(stateId); + const { selectedStateIndex, onIndexChange, backgroundImageAnimation } = + useAnimatedSelectedIndex(200, 200); + + if (requestStatus === ApiRequestStatus.LOADING) { + return ( + + + + ); + } + if (data.length === 0) { return ( - - - + + No towns found + ); -} \ No newline at end of file + } + + const handleTownSelection = (townId: number) => { + router.push(`/state/${stateId}/town?townId=${townId}`); + }; + + return ( + + + + {data[selectedStateIndex].description && ( + + + Description + {data[selectedStateIndex].description} + + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + paddingHorizontal: 20, + gap: 20, + }, + description_text: { + fontSize: 20, + fontWeight: "bold", + }, + description_content_text: { + fontSize: 16, + }, +}); -- GitLab From a027a79846b466b9dd9f9ed8011b5a046c08b305 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:41:43 -0600 Subject: [PATCH 03/37] =?UTF-8?q?Se=20cre=C3=B3=20la=20pagina=20donde=20se?= =?UTF-8?q?=20muestran=20las=20actividades=20que=20estan=20disponibles=20e?= =?UTF-8?q?n=20un=20pueblo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../town_activities/town_activities_page.tsx | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 mobile/src/screens/town_activities/town_activities_page.tsx diff --git a/mobile/src/screens/town_activities/town_activities_page.tsx b/mobile/src/screens/town_activities/town_activities_page.tsx new file mode 100644 index 00000000..ff96af23 --- /dev/null +++ b/mobile/src/screens/town_activities/town_activities_page.tsx @@ -0,0 +1,76 @@ +import { + View, + Text, + FlatList, + Button, + StyleSheet, + Touchable, + TouchableOpacity, +} from "react-native"; +import { FullPageLoader } from "../../components/full_page_loader/full_page_loader"; +import { ApiRequestStatus } from "../../constants/api_request_states"; +import { useGetActivities } from "../../hooks/useGetActivities"; +import { ActivityTile } from "../../components/activity_tile/activity_tile"; +import { LIGTHT_THEME } from "../../constants/theme"; +import { router } from "expo-router"; + +interface TownActivitiesPageProps { + townId: number; + stateId: number; +} + +export const TownActivitiesPage = ({ townId, stateId }: TownActivitiesPageProps) => { + const { activities, requestStatus } = useGetActivities(townId); + + if (requestStatus === ApiRequestStatus.LOADING) { + return ; + } + + const handleViewActivity = (activityId: number) =>{ + router.push(`/state/${stateId}/activity?townId=${townId}&activityId=${activityId}`); + } + + return ( + + } + ItemSeparatorComponent={() => } + ListFooterComponent={() => } + keyExtractor={(item) => item.id.toString()} + /> + + Generate Route + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: "center", + padding: 10, + }, + activities_container: { + flex: 1, + width: "100%", + }, + generate_route_button: { + position: "absolute", + justifyContent: "center", + alignItems: "center", + backgroundColor: LIGTHT_THEME.color.primary, + borderRadius: 25, + bottom: 10, + width: 200, + height: 50, + }, + generate_router_button_text: { + color: LIGTHT_THEME.color.white, + }, +}); -- GitLab From f4bfc2d0048539ff450245c3f0dcdcb15609870f Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:43:49 -0600 Subject: [PATCH 04/37] =?UTF-8?q?Se=20cre=C3=B3=20la=20p=C3=A1gina=20donde?= =?UTF-8?q?=20se=20muestra=20la=20descripci=C3=B3n=20de=20una=20actividad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../activity_description_page.tsx | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 mobile/src/screens/activity_description/activity_description_page.tsx diff --git a/mobile/src/screens/activity_description/activity_description_page.tsx b/mobile/src/screens/activity_description/activity_description_page.tsx new file mode 100644 index 00000000..2e02b8ac --- /dev/null +++ b/mobile/src/screens/activity_description/activity_description_page.tsx @@ -0,0 +1,128 @@ +import { + View, + Text, + TouchableOpacity, + StyleSheet, + Image, + Animated, + ScrollView, + Dimensions, +} from "react-native"; +import { FullPageLoader } from "../../components/full_page_loader/full_page_loader"; +import { ApiRequestStatus } from "../../constants/api_request_states"; +import { useGetActivityInfo } from "../../hooks/useGetActivityInfo"; +import { router } from "expo-router"; +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 "../../constants/theme"; +import { useScreenOrientation } from "../../hooks/useScreenOrientation"; +import { useRotationEnabled } from "../../hooks/useRotationEnabled"; +import { FloatingBackButton } from "../../components/floating_back_button/floating_back_button"; +interface ActivityDescriptionPageProps { + activityId: number; +} + +const startSnapPoint = 2; +const revertedSnapPoints = [0.9, 0.5, 0.3]; +const snapPoints = ["10%", "50%", "70%"]; +const heigth = Dimensions.get("window").height; + +export const ActivityDescriptionPage = ({ + activityId, +}: ActivityDescriptionPageProps) => { + const { isPortrait } = useScreenOrientation(); + const { activityInfo, requestStatus } = useGetActivityInfo(activityId); + useRotationEnabled(); + + const animationRef = useRef( + new Animated.Value(heigth * revertedSnapPoints[startSnapPoint]) + ).current; + + useEffect(() => { + Animated.timing(animationRef, { + toValue: + Dimensions.get("window").height * revertedSnapPoints[startSnapPoint], + duration: 100, + useNativeDriver: false, + }).start(); + }, [isPortrait]); + + if (requestStatus === ApiRequestStatus.LOADING) { + return ; + } + if (activityInfo === undefined) { + return ( + + Activity not found + + ); + } + + const handleSnapPointChange = (index: number) => { + Animated.timing(animationRef, { + toValue: heigth * revertedSnapPoints[index], + duration: 100, + useNativeDriver: false, + }).start(); + }; + + //TODO: Check if description is available + if (!activityInfo.description) { + activityInfo.description = "No description available"; + } + + return ( + + + + {isPortrait && ( + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + height: "100%", + width: "100%", + backgroundColor: LIGTHT_THEME.color.black, + alignItems: "center", + justifyContent: "flex-start", + }, + activity_info_container: { + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + borderWidth: 5, + padding: 20, + }, + name_text: { + fontSize: 24, + fontWeight: "bold", + }, + description_container: { + marginTop: 10, + gap: 5, + }, + description_text: { + fontSize: 18, + fontWeight: "bold", + }, + show_more_text: { + fontWeight: "600", + }, +}); -- GitLab From 0886b052fb8912db710901806085847dcb183be2 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:44:35 -0600 Subject: [PATCH 05/37] =?UTF-8?q?Se=20cre=C3=B3=20la=20p=C3=A1gina=20para?= =?UTF-8?q?=20editar=20el=20perfil=20del=20usuario?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../edit_profile/edit_profile_page.tsx | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 mobile/src/screens/edit_profile/edit_profile_page.tsx diff --git a/mobile/src/screens/edit_profile/edit_profile_page.tsx b/mobile/src/screens/edit_profile/edit_profile_page.tsx new file mode 100644 index 00000000..975199a1 --- /dev/null +++ b/mobile/src/screens/edit_profile/edit_profile_page.tsx @@ -0,0 +1,106 @@ +import { View, Text, StyleSheet } from "react-native"; +import { useEditProfile } from "../../hooks/useEditProfile"; +import { Controller } from "react-hook-form"; +import { useAuth } from "../../contexts/auth_context"; +import { CustomTextInput } from "../../components/text_input/text_input"; +import Checkbox from "expo-checkbox"; +import { useState } from "react"; +import { ChangePasswordForm } from "../../components/change_password_form/change_password_form"; +import { TouchableOpacity } from "@gorhom/bottom-sheet"; +import { LIGTHT_THEME } from "../../constants/theme"; +import { CircleAvatar } from "../../components/circle_avatar/circle_avatar"; +import { MaterialIcons } from "@expo/vector-icons"; +import { ScrollView } from "react-native-gesture-handler"; +//TODO: delete this line and import the correct CircleAvatar component +const avatarSource = require("../../../assets/avatar.png"); + +export const EditProfilePage = () => { + const { user } = useAuth(); + const { onSubmit, control, pickProfileImage, profileImage } = + useEditProfile(); + + const { name, lastName } = user!; + + return ( + + + + + + + ( + + )} + rules={{ required: "Name is required" }} + defaultValue={name} + /> + ( + + )} + rules={{ required: "Last name is required" }} + defaultValue={lastName} + /> + + Save + + + ); +}; + +const styles = StyleSheet.create({ + saveBtn: { + backgroundColor: LIGTHT_THEME.color.primary, + height: 40, + width: 100, + padding: 10, + borderRadius: 20, + alignItems: "center", + }, + saveBtnText: { + color: "white", + fontWeight: "bold", + }, +}); -- GitLab From ff40e1f6356816467ab8e23f62d7150c6daa7d02 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:46:25 -0600 Subject: [PATCH 06/37] =?UTF-8?q?Se=20separ=C3=B3=20el=20componente=20en?= =?UTF-8?q?=20un=20archivo=20aparte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom_tile_button/custom_tile_button.tsx | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 mobile/src/components/custom_tile_button/custom_tile_button.tsx diff --git a/mobile/src/components/custom_tile_button/custom_tile_button.tsx b/mobile/src/components/custom_tile_button/custom_tile_button.tsx new file mode 100644 index 00000000..197cfc3c --- /dev/null +++ b/mobile/src/components/custom_tile_button/custom_tile_button.tsx @@ -0,0 +1,44 @@ +import { ReactNode } from "react"; +import { TouchableOpacity, View, Text, StyleSheet } from "react-native"; +import { MaterialIcons } from "@expo/vector-icons"; +import { LIGTHT_THEME } from "../../constants/theme"; + +interface CustomTileButtonProps { + leadingIcon: ReactNode; + title: string; + onPress?: () => void; +} + +export const CustomTileButton = ({ + title, + onPress, + leadingIcon, +}: CustomTileButtonProps) => { + return ( + + + {leadingIcon} + {title} + + + + ); +}; + +const styles = StyleSheet.create({ + account_option: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + height: 55, + paddingHorizontal: 10, + borderTopWidth: 2, + borderTopColor: "#ccc", + backgroundColor: LIGTHT_THEME.color.white, + borderRadius: 5, + width: "100%", + }, + title: { + fontSize: 16, + } +}); -- GitLab From 93813eecef63eb2575d259bc0a331ea0bf8ebbb2 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:47:35 -0600 Subject: [PATCH 07/37] =?UTF-8?q?Se=20detall=C3=B3=20la=20p=C3=A1gina=20de?= =?UTF-8?q?=20edici=C3=B3n=20de=20perfil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/screens/account/account_page.tsx | 90 +++++++++++---------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/mobile/src/screens/account/account_page.tsx b/mobile/src/screens/account/account_page.tsx index 586d2a4f..8af8921c 100644 --- a/mobile/src/screens/account/account_page.tsx +++ b/mobile/src/screens/account/account_page.tsx @@ -8,9 +8,13 @@ import { } from "react-native"; import { useAuth } from "../../contexts/auth_context"; import { CircleAvatar } from "../../components/circle_avatar/circle_avatar"; -import { MaterialIcons } from "@expo/vector-icons"; -import { LIGTHT_THEME } from "../../constants/theme"; -import { ReactNode } from "react"; +import { + MaterialIcons, + MaterialCommunityIcons, + FontAwesome, +} from "@expo/vector-icons"; +import { CustomTileButton } from "../../components/custom_tile_button/custom_tile_button"; +import { router } from "expo-router"; //TODO: Add source to CircleAvatar const source = require("../../../assets/avatar.png"); @@ -21,37 +25,41 @@ export const AccountPage = () => { - {user?.name + " " + user?.lastName} + + {user?.name + " " + user?.lastName} + - - } - /> - - ); -}; - -interface CustomTileButtonProps { - leadingIcon: ReactNode; - title: string; - onPress: () => void; -} -const CustomTileButton = ({ - title, - onPress, - leadingIcon, -}: CustomTileButtonProps) => { - return ( - - - {leadingIcon} - {title} + + + } + onPress={() => router.push("/profile/edit")} + /> + } + /> + - - + + } + /> + ); }; @@ -60,22 +68,16 @@ const styles = StyleSheet.create({ flex: 1, alignItems: "center", padding: 20, - gap: 5, backgroundColor: "#f5f5f5", }, - account_option: { - flexDirection: "row", + profilePhotoContainer: { alignItems: "center", - justifyContent: "space-between", - height: 50, - paddingHorizontal: 10, - borderTopWidth: 1, - borderTopColor: "#ccc", - backgroundColor: LIGTHT_THEME.color.white, - borderRadius: 5, + justifyContent: "center", width: "100%", + flex: 1 + }, + user_name: { + fontSize: 18, + fontWeight: "bold", }, - profilePhotoContainer: { - alignItems: 'center' - } }); -- GitLab From cae21b359eaffdf9f8de2f305c62999a463c3121 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:49:00 -0600 Subject: [PATCH 08/37] =?UTF-8?q?Se=20utiliz=C3=B3=20el=20tema=20en=20los?= =?UTF-8?q?=20estios=20por=20defecto=20de=20la=20p=C3=A1gina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/screens/page_styles.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mobile/src/screens/page_styles.tsx b/mobile/src/screens/page_styles.tsx index b0093309..badaa113 100644 --- a/mobile/src/screens/page_styles.tsx +++ b/mobile/src/screens/page_styles.tsx @@ -1,10 +1,11 @@ import { StyleSheet } from "react-native" +import { LIGTHT_THEME } from "../constants/theme"; export const pageStyles = StyleSheet.create({ page_container: { flex: 1, alignItems: 'center', justifyContent: 'center', - backgroundColor: '#f5f5f5' + backgroundColor: LIGTHT_THEME.color.background } }); \ No newline at end of file -- GitLab From 579153c93ecc66ea4f305bc8164e33ce86f62eb1 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:52:15 -0600 Subject: [PATCH 09/37] Se crearon funciones para convertir la respuesta de la api --- mobile/src/infrastructure/utils/prod/user_util.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 mobile/src/infrastructure/utils/prod/user_util.ts diff --git a/mobile/src/infrastructure/utils/prod/user_util.ts b/mobile/src/infrastructure/utils/prod/user_util.ts new file mode 100644 index 00000000..5ba2220c --- /dev/null +++ b/mobile/src/infrastructure/utils/prod/user_util.ts @@ -0,0 +1,12 @@ +import { RegisterInfoEntity } from "../../../domain/entities/register_info"; +import { RegisterUserModel } from "../../models/prod/register_user_model"; + +export const userRegisterEntityToUserRegisterModel: (user: RegisterInfoEntity) => RegisterUserModel = (user) => { + return { + email: user.email, + password: user.password, + name: user.name, + lastName: user.lastName, + birthDate: user.birthdate + } +} \ No newline at end of file -- GitLab From 1fa2c166aefe8c1b6551e7e8d5c77701bd7b554a Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:56:19 -0600 Subject: [PATCH 10/37] =?UTF-8?q?Se=20actualizaron=20los=20m=C3=A9todos=20?= =?UTF-8?q?de=20conexion=20con=20las=20fuentes=20de=20datos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/domain/datasources/auth_datasource.ts | 8 ++++++++ mobile/src/domain/datasources/state_datasource.ts | 3 +++ mobile/src/domain/repositories/auth_repository.ts | 8 ++++++++ mobile/src/domain/repositories/state_repository.ts | 3 +++ 4 files changed, 22 insertions(+) create mode 100644 mobile/src/domain/datasources/auth_datasource.ts create mode 100644 mobile/src/domain/repositories/auth_repository.ts diff --git a/mobile/src/domain/datasources/auth_datasource.ts b/mobile/src/domain/datasources/auth_datasource.ts new file mode 100644 index 00000000..c573f251 --- /dev/null +++ b/mobile/src/domain/datasources/auth_datasource.ts @@ -0,0 +1,8 @@ +import { LoginInfoEntity } from "../entities/login_info_entity"; +import { RegisterInfoEntity } from "../entities/register_info"; +import { UserInfoEntity } from "../entities/user_info_entity"; + +export interface AuthDataSource { + login: (email: string, password: string) => Promise; + register: (user: RegisterInfoEntity) => Promise; +} \ No newline at end of file diff --git a/mobile/src/domain/datasources/state_datasource.ts b/mobile/src/domain/datasources/state_datasource.ts index 313fdd77..548186a9 100644 --- a/mobile/src/domain/datasources/state_datasource.ts +++ b/mobile/src/domain/datasources/state_datasource.ts @@ -1,7 +1,10 @@ +import { ActivityInfoEntity } from "../entities/activity_info_entity"; import { StateEntity } from "../entities/state_entity"; import { TownEntity } from "../entities/town_entity"; export interface StateDataSource { getStates(): Promise; getTowns(stateId: number): Promise; + getTownActivities(townId: number): Promise; + getActivityInfo(activityId: number): Promise; } \ No newline at end of file diff --git a/mobile/src/domain/repositories/auth_repository.ts b/mobile/src/domain/repositories/auth_repository.ts new file mode 100644 index 00000000..3dbf840f --- /dev/null +++ b/mobile/src/domain/repositories/auth_repository.ts @@ -0,0 +1,8 @@ +import { LoginInfoEntity } from "../entities/login_info_entity"; +import { RegisterInfoEntity } from "../entities/register_info"; +import { UserInfoEntity } from '../entities/user_info_entity'; + +export interface AuthRepository { + login: (email: string, password: string) => Promise; + register: (user: RegisterInfoEntity) => Promise; +} \ No newline at end of file diff --git a/mobile/src/domain/repositories/state_repository.ts b/mobile/src/domain/repositories/state_repository.ts index d0d8578e..9c145089 100644 --- a/mobile/src/domain/repositories/state_repository.ts +++ b/mobile/src/domain/repositories/state_repository.ts @@ -1,7 +1,10 @@ +import { ActivityInfoEntity } from "../entities/activity_info_entity"; import { StateEntity } from "../entities/state_entity"; import { TownEntity } from "../entities/town_entity"; export interface StateRepository { getStates(): Promise; getTowns(stateId: number): Promise; + getTownActivities(townId: number): Promise; + getActivityInfo(activityId: number): Promise; } \ No newline at end of file -- GitLab From 1cab2fbf8e948cffbc5731991cee9c939ae61da1 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:57:13 -0600 Subject: [PATCH 11/37] Se aplicaron los cambios de los datasources --- .../domain/entities/activity_info_entity.ts | 8 ++ .../src/domain/entities/login_info_entity.ts | 6 ++ mobile/src/domain/entities/register_info.ts | 8 ++ .../src/domain/entities/user_info_entity.ts | 2 +- .../datasource/dev/auth_datasource.ts | 33 +++++++ .../datasource/dev/state_datasource.ts | 97 +++++++++++++++++++ .../datasource/prod/auth_datasource.ts | 47 +++++++++ .../datasource/state_datasource.ts | 70 ------------- .../models/prod/login_user_model.ts | 4 + .../models/prod/register_user_model.ts | 7 ++ .../repositories/auth_repository.ts | 14 +++ .../repositories/state_repository.ts | 8 +- 12 files changed, 232 insertions(+), 72 deletions(-) create mode 100644 mobile/src/domain/entities/activity_info_entity.ts create mode 100644 mobile/src/domain/entities/login_info_entity.ts create mode 100644 mobile/src/domain/entities/register_info.ts create mode 100644 mobile/src/infrastructure/datasource/dev/auth_datasource.ts create mode 100644 mobile/src/infrastructure/datasource/dev/state_datasource.ts create mode 100644 mobile/src/infrastructure/datasource/prod/auth_datasource.ts delete mode 100644 mobile/src/infrastructure/datasource/state_datasource.ts create mode 100644 mobile/src/infrastructure/models/prod/login_user_model.ts create mode 100644 mobile/src/infrastructure/models/prod/register_user_model.ts create mode 100644 mobile/src/infrastructure/repositories/auth_repository.ts diff --git a/mobile/src/domain/entities/activity_info_entity.ts b/mobile/src/domain/entities/activity_info_entity.ts new file mode 100644 index 00000000..26e1468b --- /dev/null +++ b/mobile/src/domain/entities/activity_info_entity.ts @@ -0,0 +1,8 @@ +import { PlaceInfoEntity } from "./place_info_entity"; + +export interface ActivityInfoEntity extends PlaceInfoEntity { + available: string; + townId: number; + location: string; + tags?: string[]; +} \ No newline at end of file diff --git a/mobile/src/domain/entities/login_info_entity.ts b/mobile/src/domain/entities/login_info_entity.ts new file mode 100644 index 00000000..b57d1448 --- /dev/null +++ b/mobile/src/domain/entities/login_info_entity.ts @@ -0,0 +1,6 @@ +import { UserInfoEntity } from "./user_info_entity"; + +export interface LoginInfoEntity { + user: UserInfoEntity; + token: string; +} \ No newline at end of file diff --git a/mobile/src/domain/entities/register_info.ts b/mobile/src/domain/entities/register_info.ts new file mode 100644 index 00000000..15c05f67 --- /dev/null +++ b/mobile/src/domain/entities/register_info.ts @@ -0,0 +1,8 @@ +export interface RegisterInfoEntity { + name: string; + lastName: string; + email: string; + password: string; + confirmPassword: string; + birthdate: string; +} \ No newline at end of file diff --git a/mobile/src/domain/entities/user_info_entity.ts b/mobile/src/domain/entities/user_info_entity.ts index 3482cd56..c527930a 100644 --- a/mobile/src/domain/entities/user_info_entity.ts +++ b/mobile/src/domain/entities/user_info_entity.ts @@ -3,5 +3,5 @@ export interface UserInfoEntity { name: string; lastName: string; email: string; - birthDate: string; + birthDate?: Date; } \ No newline at end of file diff --git a/mobile/src/infrastructure/datasource/dev/auth_datasource.ts b/mobile/src/infrastructure/datasource/dev/auth_datasource.ts new file mode 100644 index 00000000..63f9b8e2 --- /dev/null +++ b/mobile/src/infrastructure/datasource/dev/auth_datasource.ts @@ -0,0 +1,33 @@ +import { AuthDataSource } from '../../../domain/datasources/auth_datasource'; +import { LoginInfoEntity } from '../../../domain/entities/login_info_entity'; +import { RegisterInfoEntity } from '../../../domain/entities/register_info'; +import { UserInfoEntity } from '../../../domain/entities/user_info_entity'; +export class AuthDataSourceDev implements AuthDataSource { + async login(email: string, password: string): Promise{ + return new Promise((resolve) => { + resolve({ + user: { + id: 1, + email: email, + name: 'John', + lastName: 'Doe', + birthDate: new Date('1990-01-01'), + }, + token: 'token' + })}); + } + async register(user: RegisterInfoEntity): Promise{ + return new Promise((resolve) => { + resolve({ + user: { + id: 1, + email: user.email, + name: user.name, + lastName: user.lastName, + birthDate: new Date('1990-01-01'), + }, + token: 'token' + })}); + } + +} diff --git a/mobile/src/infrastructure/datasource/dev/state_datasource.ts b/mobile/src/infrastructure/datasource/dev/state_datasource.ts new file mode 100644 index 00000000..555dda5c --- /dev/null +++ b/mobile/src/infrastructure/datasource/dev/state_datasource.ts @@ -0,0 +1,97 @@ +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'; + +export class StateDataSourceDev implements StateDataSource { + getTowns(stateId: number): Promise { + return new Promise((resolve) => { + resolve(towns.filter(town => town.stateId === stateId)); + }); + } + getStates(): Promise { + return new Promise((resolve) => { + resolve(states); + }); + } + getTownActivities(townId: number): Promise { + return new Promise((resolve) => { + resolve(activities.filter(activity => activity.townId === townId)); + }); + } + getActivityInfo(activityId: number): Promise { + return new Promise((resolve) => { + resolve(activities.find(activity => activity.id === activityId)); + }); + } +} + +const states: StateEntity[] = [ + { + id: 1, + name: 'Zacatecas', + imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg' + }, + { + id: 2, + name: 'Aguascalientes', + imageUri: 'https://www.gob.mx/cms/uploads/article/main_image/103003/fundacion-ags.jpg' + }, + { + id: 3, + name: 'Durango', + imageUri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/7/78/Panoramica_plaza_de_armas_Durango.jpg/288px-Panoramica_plaza_de_armas_Durango.jpg' + } +]; + +// Towns es una lista de pueblos mágicos de cada estado +const towns: TownEntity[] = [ + { + id: 1, + name: 'Jerez', + imageUri: 'https://www.lugaresturisticosenmexico.com/wp-content/uploads/2022/04/Jerez-Zacatecas-Pueblo-Magico-2.jpg', + description: 'Jerez es un municipio del estado de Zacatecas, México. Es uno de los 58 municipios del estado y su cabecera es la ciudad de Jerez de García Salinas. Jerez es conocido por su arquitectura colonial y su gastronomía.', + stateId: 1, + }, + { + id: 2, + name: 'Calvillo', + imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2014/04/aguascalientes_pueblo_magico_calvillo_plaza_principal_ig.jpg', + stateId: 2, + }, + { + id: 3, + name: 'Mapimí', + imageUri: 'https://www.debate.com.mx/__export/1689796560699/sites/debate/img/2023/07/19/mapimx.jpg_759710130.jpg', + stateId: 3, + }, + { + id: 4, + name: 'Jalpa', + imageUri: 'https://www.liderempresarial.com/wp-content/uploads/2022/12/Jalpa-1140x570.jpg', + stateId: 1, + } +]; + +// Activities es una lista de actividades turísticas de cada pueblo mágico + +const activities: ActivityInfoEntity[] = [ + { + id: 1, + name: 'Feria de la primavera', + description: 'Feria de la primavera en Jerez', + townId: 1, + available: 'Primavera', + location: 'Jerez, Zacatecas', + imageUri: 'https://www.liderempresarial.com/wp-content/uploads/2022/03/Feria-de-Primavera-Jerez-2022-1024x1024.jpg' + }, + { + id: 2, + name: 'Feria de la tostada', + description: 'Feria de la tostada en Jerez', + townId: 1, + available: 'Septiembre', + location: 'Jerez, Zacatecas', + imageUri: 'https://www.liderempresarial.com/wp-content/uploads/2022/08/WhatsApp-Image-2022-08-03-at-4.14.35-PM-856x570.jpeg' + } +] \ No newline at end of file diff --git a/mobile/src/infrastructure/datasource/prod/auth_datasource.ts b/mobile/src/infrastructure/datasource/prod/auth_datasource.ts new file mode 100644 index 00000000..123b1890 --- /dev/null +++ b/mobile/src/infrastructure/datasource/prod/auth_datasource.ts @@ -0,0 +1,47 @@ +import axios from "axios"; +import { AuthDataSource } from "../../../domain/datasources/auth_datasource"; +import { LoginInfoEntity } from "../../../domain/entities/login_info_entity"; +import { RegisterInfoEntity } from "../../../domain/entities/register_info"; +import { userRegisterEntityToUserRegisterModel } from "../../utils/prod/user_util"; +import { API_URL } from "../../../constants/api"; +import { LoginUserModel } from "../../models/prod/login_user_model"; +import { UserInfoEntity } from "../../../domain/entities/user_info_entity"; + +export class AuthDatasourceProd implements AuthDataSource { + login: (email: string, password: string) => Promise = async (email, password) => { + const loginInfo: LoginUserModel = { + email, + password + }; + //TODO: Hacer el login info model y el user info model cuando se termine la documentación + const { data, status } = await axios.post<{ token: string, user: UserInfoEntity }>(`${API_URL}/user/signin`, loginInfo); + if (status !== 200) { + throw new Error("Error logging in"); + } + const loginResponse: LoginInfoEntity = { + token: data.token, + user: data.user + } + return loginResponse; + }; + + register: (user: RegisterInfoEntity) => Promise = async (user) => { + const newUser = userRegisterEntityToUserRegisterModel(user); + const { data, status } = await axios.post<{ token: string }>(`${API_URL}/user/signup`, newUser); + //TODO: Falta regresar el id del usuario + if (status !== 201) { + throw new Error("Error registering user"); + } + const registeredUser: LoginInfoEntity = { + token: data.token, + user: { + id: 1, + email: newUser.email, + name: newUser.name, + lastName: newUser.lastName, + birthDate: new Date(newUser.birthDate) + } + } + return registeredUser; + }; +} \ No newline at end of file diff --git a/mobile/src/infrastructure/datasource/state_datasource.ts b/mobile/src/infrastructure/datasource/state_datasource.ts deleted file mode 100644 index c3e70c36..00000000 --- a/mobile/src/infrastructure/datasource/state_datasource.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { StateDataSource } from '../../domain/datasources/state_datasource'; -import { StateEntity } from '../../domain/entities/state_entity'; -import { TownEntity } from '../../domain/entities/town_entity'; - -export class StateDataSourceImpl implements StateDataSource { - getTowns(stateId: number): Promise { - return new Promise((resolve) => { - resolve(towns.filter(town => town.stateId === stateId)); - }); - } - getStates(): Promise { - return new Promise((resolve) => { - resolve(states); - }); - } -} - -const states: StateEntity[] = [ - { - id: 1, - name: 'Zacatecas', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - description: 'Zacatecas es una ciudad colonial que se encuentra en el centro de México. Es conocida por su arquitectura barroca, como la catedral del siglo XVIII, que se encuentra en la plaza principal, la Plaza de Armas. El Palacio de Gobierno, que data del siglo XVIII, alberga murales históricos de José Clemente Orozco. El Museo Rafael Coronel, ubicado en un antiguo convento, exhibe una colección de máscaras mexicanas. El Cerro de la Bufa, un cerro cercano, ofrece vistas panorámicas de la ciudad.' - }, - { - id: 2, - name: 'San Miguel de Allende', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - description: 'San Miguel de Allende es una ciudad colonial en el estado de Guanajuato, en el centro de México. Es conocida por su arquitectura barroca, sus iglesias bien conservadas y sus plazas pintorescas. El Santuario de Atotonilco, a 14 km al norte, es un importante lugar de peregrinación con frescos y esculturas religiosas. La ciudad también alberga el Museo Histórico de San Miguel de Allende, que exhibe arte y arte popular mexicano.' - }, - { - id: 3, - name: 'San Miguel de Allende', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - description: 'San Miguel de Allende es una ciudad colonial en el estado de Guanajuato, en el centro de México. Es conocida por su arquitectura barroca, sus iglesias bien conservadas y sus plazas pintorescas. El Santuario de Atotonilco, a 14 km al norte, es un importante lugar de peregrinación con frescos y esculturas religiosas. La ciudad también alberga el Museo Histórico de San Miguel de Allende, que exhibe arte y arte popular mexicano.' - }, - { - id: 4, - name: 'San Miguel de Allende', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - description: 'San Miguel de Allende es una ciudad colonial en el estado de Guanajuato, en el centro de México. Es conocida por su arquitectura barroca, sus iglesias bien conservadas y sus plazas pintorescas. El Santuario de Atotonilco, a 14 km al norte, es un importante lugar de peregrinación con frescos y esculturas religiosas. La ciudad también alberga el Museo Histórico de San Miguel de Allende, que exhibe arte y arte popular mexicano.' - } -]; - -const towns: TownEntity[] = [ - { - id: 1, - name: 'Zacatecas', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - stateId: 1 - }, - { - id: 2, - name: 'Guanajuato', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - stateId: 1 - }, - { - id: 3, - name: 'San Miguel de Allende', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - stateId: 1 - }, - { - id: 4, - name: 'Guanajuato', - imageUri: 'https://www.mexicodesconocido.com.mx/wp-content/uploads/2010/07/Catedral-_Plaza-de-armas-scaled.jpg', - stateId: 1 - } -]; \ No newline at end of file diff --git a/mobile/src/infrastructure/models/prod/login_user_model.ts b/mobile/src/infrastructure/models/prod/login_user_model.ts new file mode 100644 index 00000000..657cc5e6 --- /dev/null +++ b/mobile/src/infrastructure/models/prod/login_user_model.ts @@ -0,0 +1,4 @@ +export interface LoginUserModel { + email: string; + password: string; +} \ No newline at end of file diff --git a/mobile/src/infrastructure/models/prod/register_user_model.ts b/mobile/src/infrastructure/models/prod/register_user_model.ts new file mode 100644 index 00000000..259450eb --- /dev/null +++ b/mobile/src/infrastructure/models/prod/register_user_model.ts @@ -0,0 +1,7 @@ +export interface RegisterUserModel { + email: string; + password: string; + name: string; + lastName: string; + birthDate: string; +} \ No newline at end of file diff --git a/mobile/src/infrastructure/repositories/auth_repository.ts b/mobile/src/infrastructure/repositories/auth_repository.ts new file mode 100644 index 00000000..21ec1df1 --- /dev/null +++ b/mobile/src/infrastructure/repositories/auth_repository.ts @@ -0,0 +1,14 @@ +import { AuthDataSource } from '../../domain/datasources/auth_datasource'; +import { RegisterInfoEntity } from '../../domain/entities/register_info'; +import { UserInfoEntity } from '../../domain/entities/user_info_entity'; +import { AuthRepository } from '../../domain/repositories/auth_repository'; +export class AuthRepositoryImpl implements AuthRepository { + constructor(private authDataSource: AuthDataSource) { + } + async login(email: string, password: string) { + return await this.authDataSource.login(email, password); + } + async register(user: RegisterInfoEntity) { + return await this.authDataSource.register(user); + } +} \ No newline at end of file diff --git a/mobile/src/infrastructure/repositories/state_repository.ts b/mobile/src/infrastructure/repositories/state_repository.ts index 721f2303..87ab8568 100644 --- a/mobile/src/infrastructure/repositories/state_repository.ts +++ b/mobile/src/infrastructure/repositories/state_repository.ts @@ -1,4 +1,5 @@ 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 { StateRepository } from "../../domain/repositories/state_repository"; @@ -13,5 +14,10 @@ export class StateRepositoryImpl implements StateRepository { getStates(): Promise { return this.datasource.getStates(); } - + getTownActivities(townId: number): Promise { + return this.datasource.getTownActivities(townId); + } + getActivityInfo(activityId: number): Promise { + return this.datasource.getActivityInfo(activityId); + } } \ No newline at end of file -- GitLab From bfa8fe3a4a16e3bf5a31dd4dd89316ebea9ca5f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:57:52 -0600 Subject: [PATCH 12/37] =?UTF-8?q?Se=20cre=C3=B3=20el=20hook=20que=20realiz?= =?UTF-8?q?a=20una=20petici=C3=B3n=20get=20a=20los=20datasources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useGet.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 mobile/src/hooks/useGet.ts diff --git a/mobile/src/hooks/useGet.ts b/mobile/src/hooks/useGet.ts new file mode 100644 index 00000000..63644ffe --- /dev/null +++ b/mobile/src/hooks/useGet.ts @@ -0,0 +1,23 @@ +import { useEffect, useState } from "react"; +import { ApiRequestStatus } from "../constants/api_request_states"; + +export const useGet = (callback: () => Promise) => { + const [data, setData] = useState({} as T); + const [requestStatus, setRequestStatus] = useState(ApiRequestStatus.LOADING); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await callback(); + setData(response); + setRequestStatus(ApiRequestStatus.SUCCESS); + } catch (error) { + console.error(error); + setRequestStatus(ApiRequestStatus.ERROR); + } + }; + fetchData(); + }, []); + + return { data, requestStatus }; +} \ No newline at end of file -- GitLab From 0f3c12da8f23c319043e1203d3c1f6954001af4c Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:58:45 -0600 Subject: [PATCH 13/37] =?UTF-8?q?Se=20cre=C3=B3=20el=20hoom=20que=20realiz?= =?UTF-8?q?a=20la=20l=C3=B3gica=20del=20signup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useSignUp.ts | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 mobile/src/hooks/useSignUp.ts diff --git a/mobile/src/hooks/useSignUp.ts b/mobile/src/hooks/useSignUp.ts new file mode 100644 index 00000000..fde3786b --- /dev/null +++ b/mobile/src/hooks/useSignUp.ts @@ -0,0 +1,51 @@ +import { useForm } from "react-hook-form" +import { useDataContext } from "../contexts/data_context"; +import { useAuth } from "../contexts/auth_context"; +import { router } from "expo-router"; + +interface SignUpForm { + name: string; + lastName: string; + email: string; + password: string; + confirmPassword: string; + dateOfBirth: string; +} + +export const useSignUp = () => { + const { control, setError, handleSubmit } = useForm(); + const { authRepository } = useDataContext(); + const { login } = useAuth(); + + const validSubmit = async (data: SignUpForm) => { + try { + if (data.password !== data.confirmPassword) { + setError("confirmPassword", { type: "manual", message: "Passwords don't match" }); + return; + } + const userToRegister = { + name: data.name, + lastName: data.lastName, + email: data.email, + password: data.password, + confirmPassword: data.confirmPassword, + birthdate: data.dateOfBirth + } + const { user, token } = await authRepository!.register(userToRegister); + await login(user, token); + router.replace("/(tabs)"); + } catch (error) { + console.log(error); + } + } + + const invalidSubmit = (errors: any) => { + console.log(errors); + } + + const onSubmit = async () => { + await handleSubmit(validSubmit, invalidSubmit)(); + } + + return { control, onSubmit }; +} \ No newline at end of file -- GitLab From 66e7d44a2f68610f62bbec86d314aa3157bf145b Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:59:22 -0600 Subject: [PATCH 14/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20que=20verifi?= =?UTF-8?q?ca=20la=20orientaci=C3=B3n=20del=20telefono?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useScreenOrientation.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 mobile/src/hooks/useScreenOrientation.ts diff --git a/mobile/src/hooks/useScreenOrientation.ts b/mobile/src/hooks/useScreenOrientation.ts new file mode 100644 index 00000000..687484c1 --- /dev/null +++ b/mobile/src/hooks/useScreenOrientation.ts @@ -0,0 +1,22 @@ +import { useEffect, useState } from "react"; +import * as ScreenOrientation from "expo-screen-orientation"; + +export const useScreenOrientation = () => { + const [isPortrait, setIsPortrait] = useState(true); + useEffect(() => { + const listener = ScreenOrientation.addOrientationChangeListener((event) => { + if ( + event.orientationInfo.orientation === + ScreenOrientation.Orientation.PORTRAIT_UP + ) { + setIsPortrait(true); + } else { + setIsPortrait(false); + } + }); + return () => { + ScreenOrientation.removeOrientationChangeListener(listener); + }; + }, []); + return { isPortrait }; +}; -- GitLab From 642360deed12263f8333bb43d4b6ca457fc657c6 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 09:59:49 -0600 Subject: [PATCH 15/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20que=20habili?= =?UTF-8?q?ta=20y=20deshabilita=20la=20rotaci=C3=B3n=20del=20telefono?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useRotationEnabled.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 mobile/src/hooks/useRotationEnabled.ts diff --git a/mobile/src/hooks/useRotationEnabled.ts b/mobile/src/hooks/useRotationEnabled.ts new file mode 100644 index 00000000..0841e114 --- /dev/null +++ b/mobile/src/hooks/useRotationEnabled.ts @@ -0,0 +1,14 @@ +import { useEffect } from "react"; +import * as ScreenOrientation from "expo-screen-orientation"; + +export const useRotationEnabled = () => { + useEffect(() => { + const lock = async () => { + await ScreenOrientation.unlockAsync(); + }; + lock(); + return () => { + ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT); + }; + }, []); +}; -- GitLab From 0cfe9f3e284b85617c4fd4f53154b6f6fa80e884 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:00:19 -0600 Subject: [PATCH 16/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20que=20maneja?= =?UTF-8?q?=20la=20lectura=20de=20c=C3=B3digos=20QR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useQRScanner.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 mobile/src/hooks/useQRScanner.ts diff --git a/mobile/src/hooks/useQRScanner.ts b/mobile/src/hooks/useQRScanner.ts new file mode 100644 index 00000000..ab550480 --- /dev/null +++ b/mobile/src/hooks/useQRScanner.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from "react"; +import * as SecureStore from "expo-secure-store"; +import { Camera, PermissionResponse } from "expo-camera"; +import { BarCodeScannerResult } from "expo-barcode-scanner"; + +export const useQRScanner = () => { + const [status, requestPermission] = Camera.useCameraPermissions(); + const [hasPermission, setHasPermission] = useState(false); + const [qrData, setQRData] = useState(null); + const [scanning, setScanning] = useState(qrData === null); + const getPermission = async () => { + const permission = await requestPermission(); + if (permission.granted) { + setHasPermission(true); + } + }; + + const onQRScanned = (data: BarCodeScannerResult) => { + console.log(data.data); + setQRData(data.data); + setScanning(false); + }; + useEffect(() => { + if (status?.granted) { + setHasPermission(true); + } + }, [status]); + return { hasPermission, getPermission, scanning, qrData, onQRScanned}; +}; -- GitLab From 3831121f5771d221be0c2ac33ebb3890b4154922 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:00:51 -0600 Subject: [PATCH 17/37] =?UTF-8?q?Se=20conect=C3=B3=20el=20login=20con=20lo?= =?UTF-8?q?s=20repositorios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useLoggin.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mobile/src/hooks/useLoggin.ts b/mobile/src/hooks/useLoggin.ts index bc647263..8154a496 100644 --- a/mobile/src/hooks/useLoggin.ts +++ b/mobile/src/hooks/useLoggin.ts @@ -1,6 +1,7 @@ import { useForm } from "react-hook-form" import { useAuth } from "../contexts/auth_context"; import { Navigator, Redirect, router } from "expo-router"; +import { useDataContext } from "../contexts/data_context"; export type LoginFormValues = { email: string; @@ -9,17 +10,17 @@ export type LoginFormValues = { export const useLoggin = () => { const { control, handleSubmit, formState: { errors } } = useForm(); + const { authRepository } = useDataContext(); const { login } = useAuth(); const validSubmit = async (data: LoginFormValues) => { - await login({ - id: 1, - email: data.email, - name: 'John', - lastName: 'Doe', - birthDate: '1990-01-01' - }, 'hola'); - router.replace('/(tabs)'); + try { + const { user, token } = await authRepository!.login(data.email, data.password); + await login(user, token); + router.replace('/(tabs)'); + } catch (error) { + console.log(error); + } } const invalidSubmit = (errors: any) => { -- GitLab From 441650112f065faff5d578f030293faa56885f8a Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:01:20 -0600 Subject: [PATCH 18/37] Se cambio useGetList por useGet --- mobile/src/hooks/useGetList.ts | 23 ----------------------- mobile/src/hooks/useGetStates.ts | 4 ++-- mobile/src/hooks/useGetTowns.ts | 4 ++-- 3 files changed, 4 insertions(+), 27 deletions(-) delete mode 100644 mobile/src/hooks/useGetList.ts diff --git a/mobile/src/hooks/useGetList.ts b/mobile/src/hooks/useGetList.ts deleted file mode 100644 index 803ddc96..00000000 --- a/mobile/src/hooks/useGetList.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useEffect, useState } from "react"; -import { ApiRequestStatus } from "../constants/api_request_states"; - -export const useGetList = (callback: () => Promise) => { - const [data, setData] = useState([]); - const [requestStatus, setRequestStatus] = useState(ApiRequestStatus.LOADING); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await callback(); - setData(response); - setRequestStatus(ApiRequestStatus.SUCCESS); - } catch (error) { - console.error(error); - setRequestStatus(ApiRequestStatus.ERROR); - } - }; - fetchData(); - }, []); - - return { data, requestStatus }; -} \ No newline at end of file diff --git a/mobile/src/hooks/useGetStates.ts b/mobile/src/hooks/useGetStates.ts index 719e1f55..788aeefc 100644 --- a/mobile/src/hooks/useGetStates.ts +++ b/mobile/src/hooks/useGetStates.ts @@ -1,6 +1,6 @@ import { useDataContext } from "../contexts/data_context"; import { StateEntity } from '../domain/entities/state_entity'; -import { useGetList } from "./useGetList" +import { useGet } from "./useGet" export const useGetStates = () => { const { statesRepository } = useDataContext(); @@ -8,7 +8,7 @@ export const useGetStates = () => { const callback = async () =>{ return await statesRepository?.getStates() || []; } - const { requestStatus, data } = useGetList(callback); + const { requestStatus, data } = useGet(callback); return { requestStatus, data }; } \ No newline at end of file diff --git a/mobile/src/hooks/useGetTowns.ts b/mobile/src/hooks/useGetTowns.ts index 867f795e..19b233bb 100644 --- a/mobile/src/hooks/useGetTowns.ts +++ b/mobile/src/hooks/useGetTowns.ts @@ -1,7 +1,7 @@ import { useDataContext } from "../contexts/data_context"; import { StateEntity } from '../domain/entities/state_entity'; import { TownEntity } from "../domain/entities/town_entity"; -import { useGetList } from "./useGetList" +import { useGet } from "./useGet" export const useGetTowns = (stateId: number) => { const { statesRepository } = useDataContext(); @@ -9,7 +9,7 @@ export const useGetTowns = (stateId: number) => { const callback = async () =>{ return await statesRepository?.getTowns(stateId) || []; } - const { requestStatus, data } = useGetList(callback); + const { requestStatus, data } = useGet(callback); return { requestStatus, data }; } \ No newline at end of file -- GitLab From 157df8e32548da4a82977b659d9bd45c5d4a2c59 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:03:21 -0600 Subject: [PATCH 19/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20que=20obtien?= =?UTF-8?q?e=20la=20lista=20de=20actividades=20de=20un=20pueblo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useGetActivities.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 mobile/src/hooks/useGetActivities.ts diff --git a/mobile/src/hooks/useGetActivities.ts b/mobile/src/hooks/useGetActivities.ts new file mode 100644 index 00000000..a71737b3 --- /dev/null +++ b/mobile/src/hooks/useGetActivities.ts @@ -0,0 +1,12 @@ +import { useDataContext } from "../contexts/data_context"; +import { ActivityInfoEntity } from "../domain/entities/activity_info_entity"; +import { useGet } from "./useGet" + +export const useGetActivities = (townId: number) => { + const { statesRepository } = useDataContext(); + const callback = async () =>{ + return await statesRepository?.getTownActivities(townId) || []; + } + const { data, requestStatus } = useGet(callback); + return { activities: data, requestStatus }; +} \ No newline at end of file -- GitLab From cfa53aa75815534fa0cdcbedd10b68316a23b5ed Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:05:03 -0600 Subject: [PATCH 20/37] =?UTF-8?q?Se=20creo=20un=20hoom=20que=20obtiene=20l?= =?UTF-8?q?a=20informaci=C3=B3n=20de=20una=20actividad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useGetActivityInfo.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 mobile/src/hooks/useGetActivityInfo.ts diff --git a/mobile/src/hooks/useGetActivityInfo.ts b/mobile/src/hooks/useGetActivityInfo.ts new file mode 100644 index 00000000..3c50756c --- /dev/null +++ b/mobile/src/hooks/useGetActivityInfo.ts @@ -0,0 +1,12 @@ +import { useDataContext } from "../contexts/data_context"; +import { ActivityInfoEntity } from "../domain/entities/activity_info_entity"; +import { useGet } from "./useGet"; + +export const useGetActivityInfo = (activityId: number) => { + const { statesRepository } = useDataContext(); + const callback = async () =>{ + return await statesRepository!.getActivityInfo(activityId) || undefined; + } + const { data, requestStatus } = useGet(callback); + return { activityInfo: data, requestStatus }; +} \ No newline at end of file -- GitLab From 4db3065c9c116408d90af5c41dbfd8d6a2038bf0 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:06:05 -0600 Subject: [PATCH 21/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20para=20manej?= =?UTF-8?q?ar=20la=20edici=C3=B3n=20del=20perfil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useEditProfile.ts | 50 ++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 mobile/src/hooks/useEditProfile.ts diff --git a/mobile/src/hooks/useEditProfile.ts b/mobile/src/hooks/useEditProfile.ts new file mode 100644 index 00000000..0efe1bbc --- /dev/null +++ b/mobile/src/hooks/useEditProfile.ts @@ -0,0 +1,50 @@ +import { useState } from "react"; +import { set, useForm } from "react-hook-form"; +import * as ImagePicker from "expo-image-picker"; + +export type EditProfileFormValues = { + name: string; + lastName: string; + profileImage?: File | null; +}; + +export const useEditProfile = () => { + const { control, handleSubmit, setValue } = useForm(); + const [profileImage, setProfileImage] = useState(null); + + const pickProfileImage = async () => { + const permissions = await ImagePicker.requestMediaLibraryPermissionsAsync(); + if (!permissions.granted) { + return; + } + let result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ImagePicker.MediaTypeOptions.All, + allowsEditing: true, + aspect: [1, 1], + quality: 1, + }); + + if (!result.canceled) { + console.log(result.assets[0].uri); + setProfileImage(result.assets[0].uri); + } + }; + + const onValidSubmit = async (data: EditProfileFormValues) => { + if (profileImage) { + data.profileImage = new File([profileImage], "profileImage"); + setValue("profileImage", data.profileImage); + } + //TODO: Send data to the server + console.log(data); + }; + + const onInvalidSubmit = (errors: any) => { + console.log(errors); + }; + + const onSubmit = async () => { + await handleSubmit(onValidSubmit, onInvalidSubmit)(); + }; + return { onSubmit, control, pickProfileImage, profileImage }; +}; -- GitLab From 678c029eb445a55a096f80f1f7a543991181cd06 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:06:52 -0600 Subject: [PATCH 22/37] =?UTF-8?q?Se=20cre=C3=B3=20un=20hook=20para=20manej?= =?UTF-8?q?ar=20las=20transiciones=20del=20background=20del=20carrusel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/hooks/useAnimatedSelectedIndex.ts | 33 ++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mobile/src/hooks/useAnimatedSelectedIndex.ts diff --git a/mobile/src/hooks/useAnimatedSelectedIndex.ts b/mobile/src/hooks/useAnimatedSelectedIndex.ts new file mode 100644 index 00000000..4f56c218 --- /dev/null +++ b/mobile/src/hooks/useAnimatedSelectedIndex.ts @@ -0,0 +1,33 @@ +import { useCallback, useEffect, useRef, useState } from "react"; +import { Animated } from "react-native"; + +export const useAnimatedSelectedIndex = (startMilliseconds: number = 500, endMilliseconds: number = 500) => { + const selectedState = useRef(0); + const [selectedStateIndex, setSelectedStateIndex] = useState(0); + + const backgroundImageAnimation = useRef(new Animated.Value(-300)).current; + + const onIndexChange = useCallback((index: number) => { + if (index !== selectedState.current) { + console.log("Index changed to: ", index); + selectedState.current = index; + Animated.timing(backgroundImageAnimation, { + toValue: -300, + duration: endMilliseconds, + useNativeDriver: true, + }).start(() => { + setSelectedStateIndex(index); + }); + } + }, []); + + useEffect(() => { + Animated.timing(backgroundImageAnimation, { + toValue: 0, + duration: startMilliseconds, + useNativeDriver: true, + }).start(); + }, [selectedStateIndex]); + + return { onIndexChange, selectedStateIndex, backgroundImageAnimation }; +}; -- GitLab From 8aa31606a1289aca5af4604dd83ccce877c45ccc Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:08:11 -0600 Subject: [PATCH 23/37] Se cambiaron las fuentes de datos por las de produccion --- mobile/src/contexts/data_context.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/mobile/src/contexts/data_context.tsx b/mobile/src/contexts/data_context.tsx index e50f5262..8ec516ce 100644 --- a/mobile/src/contexts/data_context.tsx +++ b/mobile/src/contexts/data_context.tsx @@ -1,24 +1,34 @@ import { createContext, PropsWithChildren, useContext } from "react"; import { StateRepository } from "../domain/repositories/state_repository"; import { StateRepositoryImpl } from "../infrastructure/repositories/state_repository"; -import { StateDataSourceImpl } from "../infrastructure/datasource/state_datasource"; +import { StateDataSourceDev } from "../infrastructure/datasource/dev/state_datasource"; +import { AuthRepository } from "../domain/repositories/auth_repository"; +import { AuthDataSourceDev } from "../infrastructure/datasource/dev/auth_datasource"; +import { AuthRepositoryImpl } from "../infrastructure/repositories/auth_repository"; +import { AuthDatasourceProd } from "../infrastructure/datasource/prod/auth_datasource"; type DataContextType = { statesRepository: StateRepository | null; + authRepository: AuthRepository | null; }; type DataContextProviderProps = PropsWithChildren<{}>; const DataContext = createContext({ - statesRepository: null + statesRepository: null, + authRepository: null }); export const DataContextProvider = ({ children }: DataContextProviderProps) => { - const statesDataSource = new StateDataSourceImpl(); + const statesDataSource = new StateDataSourceDev(); const statesRepository = new StateRepositoryImpl(statesDataSource); + const authDataSource = new AuthDataSourceDev(); + const authRepository = new AuthRepositoryImpl(authDataSource); + const value = { - statesRepository + statesRepository, + authRepository }; return ( -- GitLab From 990fde98961b4be50fabee31501a043e72c8ff74 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Tue, 16 Apr 2024 10:09:06 -0600 Subject: [PATCH 24/37] =?UTF-8?q?Se=20cre=C3=B3=20el=20layout=20de=20la=20?= =?UTF-8?q?aplicaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/app/(tabs)/_layout.tsx | 7 ++ mobile/app/_layout.tsx | 30 +++-- mobile/app/profile/_layout.tsx | 12 ++ mobile/app/profile/edit.tsx | 7 ++ mobile/app/scan.tsx | 113 ++++++++++++++++++ mobile/app/state/[id]/activity.tsx | 19 +++ mobile/app/state/[id]/town.tsx | 18 +++ mobile/app/state/_layout.tsx | 34 ++++++ .../app/{(modal)/[id].tsx => state/index.tsx} | 2 + 9 files changed, 233 insertions(+), 9 deletions(-) create mode 100644 mobile/app/profile/_layout.tsx create mode 100644 mobile/app/profile/edit.tsx create mode 100644 mobile/app/scan.tsx create mode 100644 mobile/app/state/[id]/activity.tsx create mode 100644 mobile/app/state/[id]/town.tsx create mode 100644 mobile/app/state/_layout.tsx rename mobile/app/{(modal)/[id].tsx => state/index.tsx} (92%) diff --git a/mobile/app/(tabs)/_layout.tsx b/mobile/app/(tabs)/_layout.tsx index 55ed70f3..acbdee43 100644 --- a/mobile/app/(tabs)/_layout.tsx +++ b/mobile/app/(tabs)/_layout.tsx @@ -17,7 +17,14 @@ export default function Layout() { screenOptions={{ tabBarActiveTintColor: LIGTHT_THEME.color.primary, tabBarInactiveTintColor: LIGTHT_THEME.color.secondary, + headerStyle: { + backgroundColor: LIGTHT_THEME.color.primary, + }, + headerTitleStyle: { + color: LIGTHT_THEME.color.white, + }, headerTitleAlign: "center", + }} > - - - - ; + return ( + + + + + + + + ); } const MainLayout = () => { @@ -20,12 +25,12 @@ const MainLayout = () => { } return ( - - + + @@ -44,6 +49,13 @@ const MainLayout = () => { } } /> + ); }; diff --git a/mobile/app/profile/_layout.tsx b/mobile/app/profile/_layout.tsx new file mode 100644 index 00000000..d6a99319 --- /dev/null +++ b/mobile/app/profile/_layout.tsx @@ -0,0 +1,12 @@ +import { Stack } from "expo-router"; + +export default function Layout() { + return ( + + + + ); +} \ No newline at end of file diff --git a/mobile/app/profile/edit.tsx b/mobile/app/profile/edit.tsx new file mode 100644 index 00000000..bc3f55f0 --- /dev/null +++ b/mobile/app/profile/edit.tsx @@ -0,0 +1,7 @@ +import { EditProfilePage } from "../../src/screens/edit_profile/edit_profile_page"; + +export default function EditProfileScreen() { + return ( + + ); +} \ No newline at end of file diff --git a/mobile/app/scan.tsx b/mobile/app/scan.tsx new file mode 100644 index 00000000..7f00020b --- /dev/null +++ b/mobile/app/scan.tsx @@ -0,0 +1,113 @@ +import { View, Text, Button, StyleSheet, Animated } from "react-native"; +import { useQRScanner } from "../src/hooks/useQRScanner"; +import { CameraView } from "expo-camera/next"; +import { BarCodeScanningResult } from "expo-camera"; +import { useEffect, useRef } from "react"; + +export default function ScanScreen() { + const { hasPermission, getPermission, scanning, onQRScanned, qrData } = + useQRScanner(); + + const qrAnimation = useRef(new Animated.Value(0)).current; + + const startAnimation = () => { + Animated.loop( + Animated.sequence([ + Animated.timing(qrAnimation, { + toValue: 1, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(qrAnimation, { + toValue: 0, + duration: 1000, + useNativeDriver: true, + }), + ]) + ).start(); + }; + + useEffect(() => { + return () => { + qrAnimation.stopAnimation(); + }; + }, []); + + if (!hasPermission) { + return ( + + No permission +