From d762bd3e2418fac957539752e7c30b2e81a57f62 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:44:02 -0600 Subject: [PATCH 01/19] ... --- backend/src/email/email.service.ts | 2 +- .../admin_panel_place_register.tsx | 30 +++++++--- .../assets/css/styles.css | 10 +++- .../geocoding/assets/css/styles.css | 22 +++++++ web/src/components/geocoding/geocoding.tsx | 60 +++++++++++++++++++ .../loading_spinner/assets/css/styles.css | 6 ++ web/src/components/map/map.tsx | 55 +++++++++-------- .../data/datasources/prod/place_datasource.ts | 2 + web/src/data/models/prod/PlaceModel.ts | 4 +- web/src/hooks/usePlace.tsx | 13 +++- web/src/infraestructure/entities/place.ts | 2 + 11 files changed, 168 insertions(+), 38 deletions(-) create mode 100644 web/src/components/geocoding/assets/css/styles.css create mode 100644 web/src/components/geocoding/geocoding.tsx diff --git a/backend/src/email/email.service.ts b/backend/src/email/email.service.ts index 9a975c85..621bed1f 100644 --- a/backend/src/email/email.service.ts +++ b/backend/src/email/email.service.ts @@ -13,7 +13,7 @@ export class EmailService { const mailOptions = { to: email, subject: 'Reset your password', - text: `Your reset code is ${resetCode}`, + html: `

Your reset code is ${resetCode}

`, }; try { await this.mailerService.sendMail(mailOptions); diff --git a/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx b/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx index fe958171..2b123a85 100644 --- a/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx +++ b/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx @@ -1,14 +1,18 @@ import { faWindowClose } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Dispatch, SetStateAction, useEffect, useState} from "react"; +import { useEffect, useState} from "react"; import "./assets/css/styles.css"; -import { MapComponent } from "../../map/map"; +import { MapComponent, Position } from "../../map/map"; import { usePlace } from "../../../hooks/usePlace"; import { languaguesList } from "../../../constants/languages"; import { LoadingScreen } from "../../loading_screen/loading_screen"; import { MultipleImagesDropzone } from "../../multiple_images_dropzone/multiple_images_dropzone"; import { AvailableDays, availableDaysList, EmptyPlace, Place } from "../../../infraestructure/entities/place"; import { Category } from "../../../infraestructure/entities/category"; +import { Geocoding } from "../../geocoding/geocoding"; +import { APIProvider } from "@vis.gl/react-google-maps"; +import { REACT_APP_GOOGLE_API_KEY } from "../../../constants/api_keys"; +import { LoadingSpinner } from "../../loading_spinner/loading_spinner"; interface props { setWindowVisibility: (visibility: boolean) => void; @@ -38,7 +42,8 @@ export const AdminPanelPlaceRegister = ({setWindowVisibility, idTown, categories getPlaceById, onSubmitRegister, onSubmitUpdate, - clearErrors + clearErrors, + getValues } = usePlace(forceRenderList, setWindowVisibility); const [clickedCategories, setClickedCategories] = useState(new Array(categoriesList.length).fill(false)); const [isLoading, setIsLoading] = useState(false); @@ -46,6 +51,10 @@ export const AdminPanelPlaceRegister = ({setWindowVisibility, idTown, categories const [openHourInput, setOpenHourInput] = useState(''); const [closeHourInput, setCloseHourInput] = useState(''); + //Maps + const [position, setPosition] = useState(null); + const [ isSearching , setIsSearching] = useState(false); + const onClickCategory = (idCategory: number) => { const index = categoriesId.indexOf(idCategory); const indexList = categoriesList.findIndex(category => category.idCategory === idCategory); @@ -88,6 +97,8 @@ export const AdminPanelPlaceRegister = ({setWindowVisibility, idTown, categories setValue('closeAt', placeGetted.closeAt); setValue('available', placeGetted.available); setAvailableDays(placeGetted.available); + setPosition({latitude: Number(placeGetted.latitude), longitude: Number(placeGetted.longitude)}); + setValue('address', placeGetted.address); const clickedCategoriesBackup : boolean[] = []; categoriesList.forEach((category) => { if(placeGetted.categoriesId.indexOf(category.idCategory) > -1){ @@ -273,10 +284,15 @@ export const AdminPanelPlaceRegister = ({setWindowVisibility, idTown, categories
-
- +
+ + + {isSearching && } +
+ +
+

{errors.latitude?.message}

diff --git a/web/src/components/admin_panel_places/admin_panel_place_register/assets/css/styles.css b/web/src/components/admin_panel_places/admin_panel_place_register/assets/css/styles.css index 48eeeb9e..b34ebca7 100644 --- a/web/src/components/admin_panel_places/admin_panel_place_register/assets/css/styles.css +++ b/web/src/components/admin_panel_places/admin_panel_place_register/assets/css/styles.css @@ -58,10 +58,18 @@ flex-direction: column; } -.map{ +.google_map{ height: 95%; width: 100%; padding: 10px; + display: flex; + flex-direction: column; + position: relative; +} + +.map_component{ + width: 100%; + flex-grow: 1; } .map_error_cnt{ diff --git a/web/src/components/geocoding/assets/css/styles.css b/web/src/components/geocoding/assets/css/styles.css new file mode 100644 index 00000000..dac47c5a --- /dev/null +++ b/web/src/components/geocoding/assets/css/styles.css @@ -0,0 +1,22 @@ +.g_map_cnt{ + width: 100%; + height: 100%; + display: flex; + flex-direction: column; +} + +.address_input_cnt{ + width: 100%; + display: flex; + flex-direction: column; +} + +.address_locate_cnt{ + width: 100%; + display: flex; + flex-direction: row-reverse; +} + +.address_locate_cnt input{ + flex-grow: 1; +} \ No newline at end of file diff --git a/web/src/components/geocoding/geocoding.tsx b/web/src/components/geocoding/geocoding.tsx new file mode 100644 index 00000000..888f7ed7 --- /dev/null +++ b/web/src/components/geocoding/geocoding.tsx @@ -0,0 +1,60 @@ +import { useMapsLibrary } from "@vis.gl/react-google-maps"; +import { useState, useEffect, Dispatch, SetStateAction, useRef } from "react"; +import { UseFormGetValues, UseFormRegister, FieldErrors } from "react-hook-form"; +import { Place } from "../../infraestructure/entities/place"; +import { Position } from "../map/map"; +import './assets/css/styles.css'; + +interface props{ + getValues: UseFormGetValues; + register: UseFormRegister; + errors: FieldErrors; + setPosition: Dispatch> + setLoading: Dispatch> +} + +export const Geocoding = ({ getValues, register, errors, setPosition, setLoading}: props) => { + const geocodingApiLoaded = useMapsLibrary('geocoding'); + const [geocodingService, setGeocodingService] = useState(); + const [geocodingResult, setGeocodingResult] = useState(); + + const getPositionByAddress = () => { + const address = getValues('address'); + if(!geocodingService || !address) return; + setLoading(true); + geocodingService?.geocode({address}, (results, status) => { + if(results && status=="OK"){ + setGeocodingResult(results[0]); + } + }); + setLoading(false); + } + + + useEffect(()=> { + if(!geocodingApiLoaded) return; + setGeocodingService(new window.google.maps.Geocoder()); + },[geocodingApiLoaded]) + + useEffect(() => { + if(!geocodingResult) return; + setPosition({latitude: geocodingResult.geometry.location.lat(), longitude: geocodingResult.geometry.location.lng()}) + }, [geocodingResult]) + + return ( +
+ +
+ + { + if(event.key === 'Enter'){ + getPositionByAddress(); + } + }} + /> +
+

{errors.address?.message}

+
+ ) +} \ No newline at end of file diff --git a/web/src/components/loading_spinner/assets/css/styles.css b/web/src/components/loading_spinner/assets/css/styles.css index bf6048a2..f690fb0c 100644 --- a/web/src/components/loading_spinner/assets/css/styles.css +++ b/web/src/components/loading_spinner/assets/css/styles.css @@ -1,5 +1,6 @@ .spinner{ z-index: 999; + position: absolute; width: 150px; padding: 20px; aspect-ratio: 1; @@ -13,5 +14,10 @@ -webkit-mask-composite: source-out; mask-composite: subtract; animation: l3 1s infinite linear; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; } @keyframes l3 {to{transform: rotate(1turn)}} \ No newline at end of file diff --git a/web/src/components/map/map.tsx b/web/src/components/map/map.tsx index 01fbedb4..e88eecc0 100644 --- a/web/src/components/map/map.tsx +++ b/web/src/components/map/map.tsx @@ -1,15 +1,14 @@ -import { useState, Dispatch, SetStateAction, useEffect } from "react"; -import { REACT_APP_GOOGLE_API_KEY } from "../../constants/api_keys"; +import { Dispatch, SetStateAction, useEffect } from "react"; import { UseFormClearErrors, UseFormSetValue } from "react-hook-form"; import { Place } from "../../infraestructure/entities/place"; -import { APIProvider, Map, Marker } from "@vis.gl/react-google-maps"; +import { Map, Marker, useMap } from "@vis.gl/react-google-maps"; interface props{ setValue: UseFormSetValue; setIsLoading: Dispatch>; clearErrors: UseFormClearErrors; - latitude?: number; - longitude?: number; + position: Position | null; + setPosition: Dispatch>; } export interface Position{ @@ -17,35 +16,39 @@ export interface Position{ longitude: number; } -export const MapComponent = ({setValue, setIsLoading, latitude, longitude, clearErrors}: props) => { - const [position, setPosition] = useState({latitude: 0.0, longitude: 0.0}); - const center = {lat: 23.687, lng: -102.74}; - useEffect(() => { - if(latitude && longitude){ - setPosition({latitude, longitude}); - } - }, [latitude]); +export const MapComponent = ({setValue, setIsLoading, position, setPosition, clearErrors}: props) => { + const defaultCenter = {lat: 23.687, lng: -102.74}; + const mapRef = useMap(); useEffect(() => { - setValue('latitude',position.latitude); - setValue('longitude',position.longitude); - clearErrors('latitude'); - clearErrors('longitude'); + if(position && position.latitude!==0 && position.longitude!==0){ + setValue('latitude',position.latitude); + setValue('longitude',position.longitude); + if(mapRef){ + mapRef.setCenter({lat: position.latitude, lng: position.longitude}); + mapRef.setZoom(16); + } + clearErrors('latitude'); + clearErrors('longitude'); + } },[position]); return ( - setIsLoading(false)}> -
- { +
+ { const lat = event.detail.latLng?.lat || 0.0; const lng = event.detail.latLng?.lng || 0.0; setPosition({latitude: lat, longitude: lng}); - }}> - - -
- + }} + + > + {position && } +
+
); } \ No newline at end of file diff --git a/web/src/data/datasources/prod/place_datasource.ts b/web/src/data/datasources/prod/place_datasource.ts index 7703c47f..299676c5 100644 --- a/web/src/data/datasources/prod/place_datasource.ts +++ b/web/src/data/datasources/prod/place_datasource.ts @@ -18,6 +18,7 @@ export class PlaceDatasourceProd implements PlaceDatasourceInf{ formToSend.append('longitude', String(form.longitude)); formToSend.append('openAt', String(form.openAt)); formToSend.append('closeAt', String(form.closeAt)); + formToSend.append('address', form.address); if(form.available === AvailableDays.CUSTOM){ formToSend.append('startDate', String(form.startDate)); @@ -77,6 +78,7 @@ export class PlaceDatasourceProd implements PlaceDatasourceInf{ formToSend.append('longitude', String(place.longitude)); formToSend.append('openAt', String(place.openAt)); formToSend.append('closeAt', String(place.closeAt)); + formToSend.append('address', place.address); if(place.available === AvailableDays.CUSTOM){ formToSend.append('startDate', String(place.startDate)); diff --git a/web/src/data/models/prod/PlaceModel.ts b/web/src/data/models/prod/PlaceModel.ts index 4adb0593..5e4ea3e4 100644 --- a/web/src/data/models/prod/PlaceModel.ts +++ b/web/src/data/models/prod/PlaceModel.ts @@ -15,6 +15,7 @@ export interface PlaceModel { closeAt: number; startDate?: Date; endDate?: Date; + address: string; } export const placeModelToEntity = (model: PlaceModel) =>{ @@ -47,7 +48,8 @@ export const placeModelToEntity = (model: PlaceModel) =>{ openAt: model.openAt, closeAt: model.closeAt, startDate: model.startDate, - endDate: model.endDate + endDate: model.endDate, + address: model.address } return place; } \ No newline at end of file diff --git a/web/src/hooks/usePlace.tsx b/web/src/hooks/usePlace.tsx index 69a8e095..550365e1 100644 --- a/web/src/hooks/usePlace.tsx +++ b/web/src/hooks/usePlace.tsx @@ -22,14 +22,14 @@ const resolver: Resolver = async (data) => { } } - if(!data.openAt && data.openAt!=0){ + if(!data.openAt && data.openAt!==0){ errors.openAt = { type: "required", message: "La hora de apertura es requerida" }; } - if(!data.closeAt && data.closeAt!=0){ + if(!data.closeAt && data.closeAt!==0){ errors.closeAt = { type: "required", message: "La hora de cierre es requerida" @@ -64,6 +64,13 @@ const resolver: Resolver = async (data) => { } } + if(!data.address){ + errors.address = { + type: "required", + message: "Debe de ingresar la dirección al lugar" + } + } + for(var index = languaguesList.length-1; index>=0; index--){ if(!data.descriptions || !data.descriptions[index]){ errors.descriptions = { @@ -136,6 +143,7 @@ setIsWindowActive?: (visibility: boolean) => void) => { formState: {errors}, clearErrors, resetField, + getValues } = useForm({resolver}); const [errorMessage, setErrorMessage] = useState(""); const [languageDescriptionIndexSelected, setLanguageDescriptionIndexSelected] = useState(0); @@ -285,5 +293,6 @@ setIsWindowActive?: (visibility: boolean) => void) => { categoriesId, setCategoriesId, getPlaceById, + getValues }; } diff --git a/web/src/infraestructure/entities/place.ts b/web/src/infraestructure/entities/place.ts index 46fe46ba..ca43cd08 100644 --- a/web/src/infraestructure/entities/place.ts +++ b/web/src/infraestructure/entities/place.ts @@ -12,6 +12,7 @@ export interface Place{ imagesList?: File[] | string[]; startDate?: Date; endDate?: Date; + address: string; } export enum AvailableDays { @@ -44,4 +45,5 @@ export const EmptyPlace : Place = { openAt: 0, closeAt: 0, available: AvailableDays.WEEKEND, + address: '' } \ No newline at end of file -- GitLab From d48777b4d9715a1bf8498709ca55db9f4d37b9a2 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:47:31 -0600 Subject: [PATCH 02/19] =?UTF-8?q?Reestructuraci=C3=B3n=20de=20la=20aplicac?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[townId]/activity/[activityId]/index.tsx | 2 +- .../[townId]/activity/[activityId]/travel.tsx | 2 +- mobile/src/common/contexts/data_context.tsx | 7 +- .../activity_bottom_sheet.tsx | 139 ------------------ .../activity_tile/activity_tile.tsx | 62 -------- .../domain/datasources/activity_datasource.ts | 5 - .../domain/datasources/route_datasource.ts | 3 +- .../domain/datasources/state_datasource.ts | 2 +- .../domain/entities/activity_info_entity.ts | 21 --- .../domain/entities/activity_place_entity.ts | 19 --- .../repositories/activity_repository.ts | 5 - mobile/src/hooks/useGenerateRoute.ts | 2 +- mobile/src/hooks/useGetActivityPoint.ts | 2 +- .../datasource/dev/activity_datasource.ts | 7 +- .../datasource/prod/activity_datasource.ts | 7 +- .../datasource/prod/state_datasource.ts | 2 +- .../models/prod/activity_model.ts | 8 +- .../models/prod/route_activity_model.ts | 16 ++ .../infrastructure/models/prod/tag_model.ts | 5 + .../repositories/activity_repository.ts | 9 +- .../infrastructure/utils/activity_utils.ts | 2 +- .../route/components/route_activity_tile.tsx | 4 +- .../activity_description_page.tsx | 128 ---------------- .../screens/activity_point/activity_point.tsx | 138 ----------------- .../town_activities/town_activities_page.tsx | 2 +- 25 files changed, 55 insertions(+), 544 deletions(-) delete mode 100644 mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx delete mode 100644 mobile/src/components/activity_tile/activity_tile.tsx delete mode 100644 mobile/src/domain/datasources/activity_datasource.ts delete mode 100644 mobile/src/domain/entities/activity_info_entity.ts delete mode 100644 mobile/src/domain/entities/activity_place_entity.ts delete mode 100644 mobile/src/domain/repositories/activity_repository.ts create mode 100644 mobile/src/infrastructure/models/prod/route_activity_model.ts create mode 100644 mobile/src/infrastructure/models/prod/tag_model.ts delete mode 100644 mobile/src/screens/activity_description/activity_description_page.tsx delete mode 100644 mobile/src/screens/activity_point/activity_point.tsx diff --git a/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/index.tsx b/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/index.tsx index 40d153ab..aeee210c 100644 --- a/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/index.tsx +++ b/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/index.tsx @@ -1,5 +1,5 @@ import { useLocalSearchParams } from "expo-router"; -import { ActivityDescriptionPage } from "../../../../../../../src/screens/activity_description/activity_description_page"; +import { ActivityDescriptionPage } from "../../../../../../../src/activity/screens/activity_description_page"; export default function ActivitySelectionScreen() { const { activityId, stateId, townId } = useLocalSearchParams<{activityId: string, stateId: string, townId: string}>(); diff --git a/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/travel.tsx b/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/travel.tsx index e75e4675..3d1967ca 100644 --- a/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/travel.tsx +++ b/mobile/app/state/[stateId]/town/[townId]/activity/[activityId]/travel.tsx @@ -1,6 +1,6 @@ import { useLocalSearchParams } from "expo-router"; import { View, Text } from "react-native"; -import { ActivityPointScreen } from "../../../../../../../src/screens/activity_point/activity_point"; +import { ActivityPointScreen } from "../../../../../../../src/activity/screens/activity_point"; export default function Travel() { diff --git a/mobile/src/common/contexts/data_context.tsx b/mobile/src/common/contexts/data_context.tsx index 1dc6dc08..c64a8a9c 100644 --- a/mobile/src/common/contexts/data_context.tsx +++ b/mobile/src/common/contexts/data_context.tsx @@ -6,7 +6,6 @@ import { AuthRepository } from "../../auth/domain/repositories/auth_repository"; import { AuthDataSourceDev } from '../../auth/infrastructure/dev/datasources/auth_datasource'; import { AuthRepositoryImpl } from "../../auth/infrastructure/prod/repositories/auth_repository"; import { AuthDatasourceProd } from '../../auth/infrastructure/prod/datasources/auth_datasource'; -import { ActivityRepository } from "../../domain/repositories/activity_repository"; import { ActivityDatasourceDev } from "../../infrastructure/datasource/dev/activity_datasource"; import { ActivityRepositoryDev } from '../../infrastructure/repositories/activity_repository'; import { TravelDatasourceDev } from "../../infrastructure/datasource/dev/travel_datasource"; @@ -22,6 +21,8 @@ import { ProfileRepositoryImpl } from "../../profile/infrastructure/repositories import { ActivityDatasourceProd } from "../../infrastructure/datasource/prod/activity_datasource"; import { useTranslation } from "react-i18next"; import { ProfileDataSourceProd } from "../../profile/infrastructure/datasources/prod/profile_datasource"; +import { ActivityRepository } from "../../activity/domain/repositories/activity_repository"; +import { RouteDatasourceProd } from "../../infrastructure/datasource/prod/route_datasource"; type DataContextType = { statesRepository: StateRepository | null; @@ -49,7 +50,7 @@ const getProductionContext = (language: string): DataContextType => { authRepository: new AuthRepositoryImpl(new AuthDatasourceProd()), activityRepository: new ActivityRepositoryDev(new ActivityDatasourceProd()), travelRepository: new TravelRepositoryImpl(new TravelDatasourceDev()), - routeRepository: new RouteRepositoryImpl(new RouteDataSourceDev()), + routeRepository: new RouteRepositoryImpl(new RouteDatasourceProd(language)), profileRepository: new ProfileRepositoryImpl(new ProfileDataSourceProd(language)) }; } @@ -68,7 +69,7 @@ const getDevelopmentContext = (): DataContextType => { export const DataContextProvider = ({ children }: DataContextProviderProps) => { const { i18n:{ language } } = useTranslation(); - const value = getDevelopmentContext(); + const value = getProductionContext(language); return ( diff --git a/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx b/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx deleted file mode 100644 index ae97e81a..00000000 --- a/mobile/src/components/activity_bottom_sheet/activity_bottom_sheet.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { useRef, useState } from "react"; -import BottomSheet, { - BottomSheetFlatList, - BottomSheetScrollView, - BottomSheetView, -} from "@gorhom/bottom-sheet"; -import { - Text, - StyleSheet, - ScrollView, - View, - TouchableOpacity, -} from "react-native"; -import { ActivityInfoEntity } from "../../domain/entities/activity_info_entity"; -import { LIGHT_THEME } from "../../common/constants/theme"; -import { router } from "expo-router"; - -interface ActivityBottomSheetProps { - startSnapPoint: number; - snapPoints: string[]; - onSnapPointChange?: (index: number) => void; - activity: ActivityInfoEntity; -} - -export const ActivityBottomSheet = ({ - activity, - startSnapPoint, - snapPoints, - onSnapPointChange, -}: ActivityBottomSheetProps) => { - const sheetRef = useRef(null); - const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false); - - return ( - - - - {activity.name} - { - router.push("/scan"); - }} - style={styles.do_activity_button} - > - Do Activity - - - {activity.tags && ( - item} - ItemSeparatorComponent={() => } - renderItem={({ item }) => ( - - {item} - - )} - /> - )} - - Description - - {activity.description} - - setIsDescriptionExpanded(!isDescriptionExpanded)} - > - - {isDescriptionExpanded ? "Show less" : "Show more..."} - - - - - - ); -}; - -const styles = StyleSheet.create({ - activity_info_container: { - borderTopLeftRadius: 20, - borderTopRightRadius: 20, - borderWidth: 5, - padding: 20, - }, - activity_name_container: { - flexDirection: "row", - justifyContent: "space-between", - }, - name_text: { - fontSize: 24, - fontWeight: "bold", - width: "70%", - }, - do_activity_button: { - height: 40, - elevation: 5, - backgroundColor: LIGHT_THEME.color.primary, - padding: 10, - borderRadius: 20, - justifyContent: "center", - alignItems: "center", - paddingHorizontal: 20, - }, - do_activity_text: { - color: LIGHT_THEME.color.white, - fontWeight: "bold", - }, - description_container: { - marginTop: 20, - gap: 5, - }, - description_text: { - fontSize: 18, - fontWeight: "bold", - }, - show_more_text: { - fontWeight: "600", - }, -}); diff --git a/mobile/src/components/activity_tile/activity_tile.tsx b/mobile/src/components/activity_tile/activity_tile.tsx deleted file mode 100644 index 73471a4d..00000000 --- a/mobile/src/components/activity_tile/activity_tile.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { View, Text, StyleSheet, Image, TouchableOpacity } from "react-native"; -import { ActivityInfoEntity } from "../../domain/entities/activity_info_entity"; -import { LIGHT_THEME } from "../../common/constants/theme"; -import { ScrollView } from "react-native-gesture-handler"; - -interface ActivityTileProps { - activity: ActivityInfoEntity; - onPress?: (id: number) => void; -} - -export const ActivityTile = ({ activity, onPress }: ActivityTileProps) => { - return ( - { - onPress && onPress(activity.id); - }} activeOpacity={0.7} style={styles.container}> - - - - - {activity.name} - {activity.location} - - { - activity.tags?.map(tag => {tag}) - } - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - height: 320, - width: "100%", - backgroundColor: LIGHT_THEME.color.white, - elevation: 5, - borderWidth: 1, - borderRadius: 10, - overflow: "hidden", - }, - info_container: { - padding: 10, - gap: 5, - }, - activity_name: { - fontSize: 18, - fontWeight: "bold", - }, - tag: { - backgroundColor: LIGHT_THEME.color.primary, - color: LIGHT_THEME.color.white, - height: 30, - paddingVertical: 5, - paddingHorizontal: 10, - borderRadius: 15, - marginHorizontal: 5, - }, -}); diff --git a/mobile/src/domain/datasources/activity_datasource.ts b/mobile/src/domain/datasources/activity_datasource.ts deleted file mode 100644 index 9ae21e7a..00000000 --- a/mobile/src/domain/datasources/activity_datasource.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ActivityPlaceEntity } from "../entities/activity_place_entity"; - -export interface ActivityDataSource { - getPlaceActivity(activityId: number, townId: number, stateId: number, placeNumber: number): Promise; -} \ No newline at end of file diff --git a/mobile/src/domain/datasources/route_datasource.ts b/mobile/src/domain/datasources/route_datasource.ts index 78a312b9..38fcd2aa 100644 --- a/mobile/src/domain/datasources/route_datasource.ts +++ b/mobile/src/domain/datasources/route_datasource.ts @@ -1,4 +1,5 @@ -import { ActivityRouteEntity } from "../entities/activity_info_entity"; +import { ActivityRouteEntity } from "../../activity/domain/entities/activity_info_entity"; + export interface RouteDataSource { generateRoute: (townId: number) => Promise; diff --git a/mobile/src/domain/datasources/state_datasource.ts b/mobile/src/domain/datasources/state_datasource.ts index 548186a9..460a0110 100644 --- a/mobile/src/domain/datasources/state_datasource.ts +++ b/mobile/src/domain/datasources/state_datasource.ts @@ -1,4 +1,4 @@ -import { ActivityInfoEntity } from "../entities/activity_info_entity"; +import { ActivityInfoEntity } from "../../activity/domain/entities/activity_info_entity"; import { StateEntity } from "../entities/state_entity"; import { TownEntity } from "../entities/town_entity"; diff --git a/mobile/src/domain/entities/activity_info_entity.ts b/mobile/src/domain/entities/activity_info_entity.ts deleted file mode 100644 index 2631049a..00000000 --- a/mobile/src/domain/entities/activity_info_entity.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { PlaceInfoEntity } from "./place_info_entity"; - -export interface ActivityInfoEntity extends PlaceInfoEntity { - available: string; - townId: number; - location: string; - tags?: string[]; -} - -export interface ActivityRouteEntity extends PlaceInfoEntity { - townId: number; - location: string; - coordinates: { - latitude: number; - longitude: number; - }; - tags?: string[]; - startTime: Date; - endTime: Date; - done: boolean; -} \ No newline at end of file diff --git a/mobile/src/domain/entities/activity_place_entity.ts b/mobile/src/domain/entities/activity_place_entity.ts deleted file mode 100644 index e23bfddc..00000000 --- a/mobile/src/domain/entities/activity_place_entity.ts +++ /dev/null @@ -1,19 +0,0 @@ -export interface ActivityPlaceEntity { - idPlaceActivity: number; - name: string; - number: number; - idPlace: number; - imageUrl: string; - directions?: DirectionEntity; - content: ContentEntity -} - -interface DirectionEntity { - content: string; - speakUrl: string; -} - -interface ContentEntity { - content: string; - speakUrl: string; -} \ No newline at end of file diff --git a/mobile/src/domain/repositories/activity_repository.ts b/mobile/src/domain/repositories/activity_repository.ts deleted file mode 100644 index 45706508..00000000 --- a/mobile/src/domain/repositories/activity_repository.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ActivityPlaceEntity } from "../entities/activity_place_entity"; - -export interface ActivityRepository { - getPlaceActivity(activityId: number, townId: number, stateId: number, placeNumber: number): Promise; -} \ No newline at end of file diff --git a/mobile/src/hooks/useGenerateRoute.ts b/mobile/src/hooks/useGenerateRoute.ts index 59c93281..0694c2aa 100644 --- a/mobile/src/hooks/useGenerateRoute.ts +++ b/mobile/src/hooks/useGenerateRoute.ts @@ -1,5 +1,5 @@ +import { ActivityRouteEntity } from "../activity/domain/entities/activity_info_entity"; import { useDataContext } from "../common/contexts/data_context"; -import { ActivityRouteEntity } from "../domain/entities/activity_info_entity"; import { useGet } from "./useGet"; export const useGenerateRoute = (townId: number) => { diff --git a/mobile/src/hooks/useGetActivityPoint.ts b/mobile/src/hooks/useGetActivityPoint.ts index 10a57b61..91816d2d 100644 --- a/mobile/src/hooks/useGetActivityPoint.ts +++ b/mobile/src/hooks/useGetActivityPoint.ts @@ -1,5 +1,5 @@ import { useDataContext } from "../common/contexts/data_context" -import { ActivityPlaceEntity } from "../domain/entities/activity_place_entity"; +import { ActivityPlaceEntity } from "../activity/domain/entities/activity_place_entity"; import { useGet } from "./useGet"; interface UseGetActivityPointProps { diff --git a/mobile/src/infrastructure/datasource/dev/activity_datasource.ts b/mobile/src/infrastructure/datasource/dev/activity_datasource.ts index 21e70976..e6731af7 100644 --- a/mobile/src/infrastructure/datasource/dev/activity_datasource.ts +++ b/mobile/src/infrastructure/datasource/dev/activity_datasource.ts @@ -1,7 +1,10 @@ -import { ActivityDataSource } from "../../../domain/datasources/activity_datasource"; -import { ActivityPlaceEntity } from "../../../domain/entities/activity_place_entity"; +import { ActivityDataSource } from "../../../activity/domain/datasources/activity_datasource"; +import { ActivityPlaceEntity } from "../../../activity/domain/entities/activity_place_entity"; export class ActivityDatasourceDev implements ActivityDataSource { + async rankActivity(activityId: number, rank: number): Promise { + + } async getPlaceActivity(activityId: number, townId: number, stateId: number, placeNumber: number): Promise { return new Promise((resolve) => { resolve(placeActivities.find(place => place.idPlace === activityId && place.number === placeNumber) as ActivityPlaceEntity); diff --git a/mobile/src/infrastructure/datasource/prod/activity_datasource.ts b/mobile/src/infrastructure/datasource/prod/activity_datasource.ts index 4bd9cb84..45bf6d02 100644 --- a/mobile/src/infrastructure/datasource/prod/activity_datasource.ts +++ b/mobile/src/infrastructure/datasource/prod/activity_datasource.ts @@ -1,13 +1,16 @@ import axios from "axios"; -import { ActivityDataSource } from "../../../domain/datasources/activity_datasource"; -import { ActivityPlaceEntity } from "../../../domain/entities/activity_place_entity"; +import { ActivityPlaceEntity } from "../../../activity/domain/entities/activity_place_entity"; import { API_URL } from "../../../common/constants/api"; import { ActivityPlaceModel } from "../../models/prod/activity_place_model"; import { activityPlaceModelToEntity } from "../../utils/activity_utils"; import { Languages } from "../../../lang/translations"; +import { ActivityDataSource } from "../../../activity/domain/datasources/activity_datasource"; export class ActivityDatasourceProd implements ActivityDataSource { constructor(private lang: string = Languages.SPANISH) {} + async rankActivity(activityId: number, rank: number): Promise { + throw new Error("Method not implemented."); + } async getPlaceActivity(activityId: number, townId: number, stateId: number, placeNumber: number): Promise { const { data, status } = await axios.get(`${API_URL}/point/${placeNumber}lang?lang=${this.lang}`); if (status !== 200) { diff --git a/mobile/src/infrastructure/datasource/prod/state_datasource.ts b/mobile/src/infrastructure/datasource/prod/state_datasource.ts index d3940f85..6f7380f4 100644 --- a/mobile/src/infrastructure/datasource/prod/state_datasource.ts +++ b/mobile/src/infrastructure/datasource/prod/state_datasource.ts @@ -1,6 +1,5 @@ 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"; @@ -10,6 +9,7 @@ import { TownModel } from "../../models/prod/town_model"; import { townModelToEntity } from "../../utils/town_utils"; import { ActivityModel } from "../../models/prod/activity_model"; import { placeModelToEntity } from "../../utils/place_utils"; +import { ActivityInfoEntity } from "../../../activity/domain/entities/activity_info_entity"; export class StateDataSourceProd implements StateDataSource { private lang: string; diff --git a/mobile/src/infrastructure/models/prod/activity_model.ts b/mobile/src/infrastructure/models/prod/activity_model.ts index 6327e300..9d14e09c 100644 --- a/mobile/src/infrastructure/models/prod/activity_model.ts +++ b/mobile/src/infrastructure/models/prod/activity_model.ts @@ -1,3 +1,5 @@ +import { TagModel } from "./tag_model"; + export interface ActivityModel { idTown: number; idPlace: number; @@ -12,9 +14,3 @@ export interface ActivityModel { endDate: Date | null; categories?: TagModel[]; } - -export interface TagModel { - idCategory: number; - language: string; - name: string; -} diff --git a/mobile/src/infrastructure/models/prod/route_activity_model.ts b/mobile/src/infrastructure/models/prod/route_activity_model.ts new file mode 100644 index 00000000..6a35ae09 --- /dev/null +++ b/mobile/src/infrastructure/models/prod/route_activity_model.ts @@ -0,0 +1,16 @@ +import { TagModel } from "./tag_model"; + +export interface ActivityRouteModel { + address: string; + available: string; + categories: TagModel[]; + closeAt: number; + description: string; + idPlace: number; + idTown: number; + imageName: string; + latitude: string; + longitude: string; + name: string; + openAt: number; +} diff --git a/mobile/src/infrastructure/models/prod/tag_model.ts b/mobile/src/infrastructure/models/prod/tag_model.ts new file mode 100644 index 00000000..9b11378e --- /dev/null +++ b/mobile/src/infrastructure/models/prod/tag_model.ts @@ -0,0 +1,5 @@ +export interface TagModel { + idCategory: number; + language: string; + name: string; +} \ No newline at end of file diff --git a/mobile/src/infrastructure/repositories/activity_repository.ts b/mobile/src/infrastructure/repositories/activity_repository.ts index 3c4e2083..eb51e198 100644 --- a/mobile/src/infrastructure/repositories/activity_repository.ts +++ b/mobile/src/infrastructure/repositories/activity_repository.ts @@ -1,11 +1,14 @@ -import { ActivityDataSource } from "../../domain/datasources/activity_datasource"; -import { ActivityPlaceEntity } from "../../domain/entities/activity_place_entity"; -import { ActivityRepository } from "../../domain/repositories/activity_repository"; +import { ActivityDataSource } from "../../activity/domain/datasources/activity_datasource"; +import { ActivityPlaceEntity } from "../../activity/domain/entities/activity_place_entity"; +import { ActivityRepository } from "../../activity/domain/repositories/activity_repository"; export class ActivityRepositoryDev implements ActivityRepository { constructor( private activityDataSource: ActivityDataSource ) {} + async rankActivity(activityId: number, rank: number): Promise { + return this.activityDataSource.rankActivity(activityId, rank); + } async getPlaceActivity(activityId: number, townId: number, stateId: number, placeNumber: number): Promise { return this.activityDataSource.getPlaceActivity(activityId, townId, stateId, placeNumber); } diff --git a/mobile/src/infrastructure/utils/activity_utils.ts b/mobile/src/infrastructure/utils/activity_utils.ts index 2ce6415a..04ec0601 100644 --- a/mobile/src/infrastructure/utils/activity_utils.ts +++ b/mobile/src/infrastructure/utils/activity_utils.ts @@ -1,4 +1,4 @@ -import { ActivityPlaceEntity } from "../../domain/entities/activity_place_entity"; +import { ActivityPlaceEntity } from "../../activity/domain/entities/activity_place_entity"; import { ActivityPlaceModel } from "../models/prod/activity_place_model"; export const activityPlaceModelToEntity = (activity: ActivityPlaceModel): ActivityPlaceEntity => { diff --git a/mobile/src/route/components/route_activity_tile.tsx b/mobile/src/route/components/route_activity_tile.tsx index a94fc48c..5ee8cacc 100644 --- a/mobile/src/route/components/route_activity_tile.tsx +++ b/mobile/src/route/components/route_activity_tile.tsx @@ -1,8 +1,8 @@ import { View, StyleSheet, Text, Image } from "react-native"; -import { ActivityRouteEntity } from "../../domain/entities/activity_info_entity"; import { Entypo } from "@expo/vector-icons"; import { LIGHT_THEME } from "../../common/constants/theme"; import { FlatList } from "react-native-gesture-handler"; +import { ActivityRouteEntity } from "../../activity/domain/entities/activity_info_entity"; interface RouteActivityTileProps { activity: ActivityRouteEntity; @@ -40,7 +40,7 @@ export const RouteActivityTile = ({ /> {activity.name} - {activity.startTime.getTime().toString()} + {activity.startTime.toISOString()} {activity.location} { - 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 || activityInfo === null) { - 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: LIGHT_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", - }, -}); diff --git a/mobile/src/screens/activity_point/activity_point.tsx b/mobile/src/screens/activity_point/activity_point.tsx deleted file mode 100644 index 1a6ebe75..00000000 --- a/mobile/src/screens/activity_point/activity_point.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { Image, Text, View, StyleSheet, BackHandler } from "react-native"; -import { FullPageLoader } from "../../common/components/full_page_loader"; -import { ApiRequestStatus } from "../../common/constants/api_request_states"; -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 { LIGHT_THEME } from "../../common/constants/theme"; -import { router } from "expo-router"; -import { useAudio } from "../../common/contexts/audio_context"; -import { memo, useEffect } from "react"; - -interface ActivityPointScreenProps { - stateId: number; - townId: number; - activityId: number; - id: number; -} - -export const ActivityPointScreen = memo(({ - stateId, - townId, - activityId, - id, -}: ActivityPointScreenProps) => { - const { data, requestStatus } = useGetActivityPoint({ - activityId, - townId, - stateId, - placeNumber: id, - }); - - const { onUnmount } = useAudio(); - - useEffect(() => { - const backAction = () => { - onUnmount(); - router.back(); - return true; - } - - const backHandler = BackHandler.addEventListener('hardwareBackPress', backAction); - - return () => backHandler.remove(); - }, []); - - if (requestStatus === ApiRequestStatus.LOADING) { - return ; - } - - if (requestStatus === ApiRequestStatus.ERROR || !data) { - return null; - } - - return ( - - - {data.name} - - - - - {data.content.content} - - { - data.directions && ( - <> - Directions - {data.directions.content} - - ) - } - {!data.directions && ( - - End Activity - - )} - - - - - ); -}); - -const styles = StyleSheet.create({ - container: { - flex: 1, - gap: 15, - justifyContent: "space-between", - }, - placeContainer: { - flex: 1, - gap: 20, - padding: 20, - alignItems: "center", - }, - title: { - fontSize: 24, - fontWeight: "400", - textAlign: "center", - }, - contentText: { - fontSize: 18, - lineHeight: 30, - textAlign: "justify", - }, - imageContainer: { - width: "100%", - height: 300, - backgroundColor: "lightgrey", - padding: 10, - borderRadius: 10, - overflow: "hidden", - borderWidth: 2, - }, - image: { - height: "70%", - width: "70%", - }, - endActivityButton: { - backgroundColor: LIGHT_THEME.color.primary, - padding: 10, - borderRadius: 25, - alignItems: "center", - justifyContent: "center", - width: 200, - height: 50 - }, - endActivityButtonText: { - color: LIGHT_THEME.color.white, - fontWeight: "bold", - fontSize: 16, - } -}); diff --git a/mobile/src/screens/town_activities/town_activities_page.tsx b/mobile/src/screens/town_activities/town_activities_page.tsx index 5cfa1a3a..f21fe167 100644 --- a/mobile/src/screens/town_activities/town_activities_page.tsx +++ b/mobile/src/screens/town_activities/town_activities_page.tsx @@ -10,7 +10,7 @@ import { 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 { ActivityTile } from "../../activity/components/activity_tile"; import { LIGHT_THEME } from "../../common/constants/theme"; import { router } from "expo-router"; import { FloatingEndActionButton } from "../../common/components/floating_end_action_button"; -- GitLab From 72bca7de9dbfa8ee50dddc781a62fe1ed8554b28 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:48:34 -0600 Subject: [PATCH 03/19] Se eliminaron los datos de prueba al obtener el preview de la ruta --- mobile/src/route/screens/route_preview.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mobile/src/route/screens/route_preview.tsx b/mobile/src/route/screens/route_preview.tsx index 3dc00e2b..4c60d997 100644 --- a/mobile/src/route/screens/route_preview.tsx +++ b/mobile/src/route/screens/route_preview.tsx @@ -24,8 +24,6 @@ export const RoutePreviewPage = ({ townId }: RoutePreviewPageProps) => { return Something went wrong; } - //TODO: Remove this mock data - const data = [...routeActivities, ...routeActivities, ...routeActivities]; //TODO: Implement save route functionality const saveRoute = () => { @@ -36,16 +34,16 @@ export const RoutePreviewPage = ({ townId }: RoutePreviewPageProps) => { Route Preview - {`Start: ${data[0].startTime}`} - {`End: ${data[data.length - 1].endTime}`} + {`Start: ${routeActivities[0].startTime}`} + {`End: ${routeActivities[routeActivities.length - 1].endTime}`} } renderItem={({ item, index }) => { const isFirst = index === 0; - const isLast = index === data.length - 1; + const isLast = index === routeActivities.length - 1; return ( Date: Sun, 8 Sep 2024 11:49:20 -0600 Subject: [PATCH 04/19] =?UTF-8?q?Se=20agreg=C3=B3=20una=20funcion=20para?= =?UTF-8?q?=20convertir=20un=20modelo=20a=20una=20entidad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/infrastructure/utils/route_utils.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 mobile/src/infrastructure/utils/route_utils.ts diff --git a/mobile/src/infrastructure/utils/route_utils.ts b/mobile/src/infrastructure/utils/route_utils.ts new file mode 100644 index 00000000..6daa75f9 --- /dev/null +++ b/mobile/src/infrastructure/utils/route_utils.ts @@ -0,0 +1,25 @@ +import { ActivityRouteEntity } from "../../activity/domain/entities/activity_info_entity"; +import { ActivityRouteModel } from "../models/prod/route_activity_model"; + +export const activityRouteModelToActivityRouteEntity = (activity: ActivityRouteModel): ActivityRouteEntity => { + const startTime = new Date(activity.openAt); + startTime.setHours(activity.openAt); + const endTime = new Date(activity.closeAt); + endTime.setHours(activity.closeAt); + return { + id: 1, // TODO: Implement this + name: activity.name, + imageUri: activity.imageName, + description: activity.description, + townId: activity.idTown, + location: activity.address, + coordinates: { + latitude: parseFloat(activity.latitude), + longitude: parseFloat(activity.longitude), + }, + tags: activity.categories.map((category) => category.name), + startTime: startTime, + endTime: endTime, + done: false, + } +}; \ No newline at end of file -- GitLab From f2f189942866dfa125eb72bf1bc1ad492e7264ee Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:50:16 -0600 Subject: [PATCH 05/19] =?UTF-8?q?Se=20cre=C3=B3=20una=20implementaci=C3=B3?= =?UTF-8?q?n=20del=20datasource=20de=20ruta=20del=20contexto=20de=20produc?= =?UTF-8?q?ci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/prod/route_datasource.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 mobile/src/infrastructure/datasource/prod/route_datasource.ts diff --git a/mobile/src/infrastructure/datasource/prod/route_datasource.ts b/mobile/src/infrastructure/datasource/prod/route_datasource.ts new file mode 100644 index 00000000..fa9735d0 --- /dev/null +++ b/mobile/src/infrastructure/datasource/prod/route_datasource.ts @@ -0,0 +1,27 @@ +import axios from "axios"; +import { ActivityRouteEntity } from "../../../activity/domain/entities/activity_info_entity"; +import { RouteDataSource } from "../../../domain/datasources/route_datasource"; +import { API_URL } from "../../../common/constants/api"; +import { ActivityRouteModel } from "../../models/prod/route_activity_model"; +import { activityRouteModelToActivityRouteEntity } from "../../utils/route_utils"; + +export class RouteDatasourceProd implements RouteDataSource { + private readonly language: string; + constructor(language: string) { + this.language = language; + } + async generateRoute(townId: number): Promise{ + const {data, status} = await axios.get(`${API_URL}/route/recommend/${townId}?lang=${this.language}`); + if (status !== 200) { + throw new Error('Error fetching route'); + } + + return data.map(activityRouteModelToActivityRouteEntity); + }; + async getRoute(routeId: number): Promise { + throw new Error('Method not implemented.'); + } + +} + +// /state/state_id/town/town_id/activity/activity_id/travel?id=id_point_of_interest \ No newline at end of file -- GitLab From b3ab09b976f524c50a2802320dc77e5d473d100b Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:50:49 -0600 Subject: [PATCH 06/19] =?UTF-8?q?Se=20cre=C3=B3=20el=20componente=20para?= =?UTF-8?q?=20hacer=20el=20rating=20de=20una=20actividad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rating_page/star_rating_form.tsx | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 mobile/src/common/components/rating_page/star_rating_form.tsx diff --git a/mobile/src/common/components/rating_page/star_rating_form.tsx b/mobile/src/common/components/rating_page/star_rating_form.tsx new file mode 100644 index 00000000..260be2c5 --- /dev/null +++ b/mobile/src/common/components/rating_page/star_rating_form.tsx @@ -0,0 +1,94 @@ +import AntDesign from "@expo/vector-icons/AntDesign"; +import { View, StyleSheet, Animated } from "react-native"; +import { TouchableOpacity } from "react-native-gesture-handler"; +import { LIGHT_THEME } from "../../constants/theme"; +import { useEffect, useRef, useState } from "react"; +import { use } from "i18next"; + +interface StarRatingFormProps { + maxRating: number; + onRatingChange: (rating: number) => void; +} + +export const StarRatingForm = ({ + maxRating, + onRatingChange, +}: StarRatingFormProps) => { + const [rating, setRating] = useState(0); + const danceRef = useRef(new Animated.Value(0)).current; + + useEffect(() => { + Animated.sequence([ + Animated.timing(danceRef, { + toValue: 10, + duration: 100, + useNativeDriver: true, + }), + Animated.timing(danceRef, { + toValue: -10, + duration: 100, + useNativeDriver: true, + }), + Animated.timing(danceRef, { + toValue: 0, + duration: 100, + useNativeDriver: true, + }), + ]).start(); + }, [rating]); + + + const handleOnPress = (index: number) => { + setRating(index + 1); + onRatingChange(index + 1); + }; + return ( + + {Array.from({ length: maxRating }).map((_, index) => { + return ( + handleOnPress(index)}> + + onRatingChange(index + 1)} + /> + + + ); + })} + + ); +}; + +const styles = StyleSheet.create({ + mainView: { + display: "flex", + flexDirection: "row", + justifyContent: "space-around", + alignItems: "center", + width: "80%", + alignSelf: "center", + height: 70, + zIndex: 10, + }, +}); -- GitLab From 34f5a85bcc17f1831d232e81b2658c737d242b46 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:52:00 -0600 Subject: [PATCH 07/19] =?UTF-8?q?Se=20cre=C3=B3=20una=20p=C3=A1gina=20comp?= =?UTF-8?q?leta=20para=20hacer=20el=20rating=20de=20una=20actividad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rating_page/full_page_rating.tsx | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 mobile/src/common/components/rating_page/full_page_rating.tsx diff --git a/mobile/src/common/components/rating_page/full_page_rating.tsx b/mobile/src/common/components/rating_page/full_page_rating.tsx new file mode 100644 index 00000000..eab089b6 --- /dev/null +++ b/mobile/src/common/components/rating_page/full_page_rating.tsx @@ -0,0 +1,103 @@ +import { useEffect, useRef, useState } from "react"; +import { StyleSheet, View, Animated, Text } from "react-native"; +import { StarRatingForm } from "./star_rating_form"; +import AntDesign from "@expo/vector-icons/AntDesign"; +import { FloatingEndActionButton } from "../floating_end_action_button"; + +interface FullPageRatingProps { + onClose: () => void; + onSubmitted: (rating: number) => void; +} + +export const FullPageRating = ({ onClose, onSubmitted }: FullPageRatingProps) => { + const [rating, setRating] = useState(0); + const opacityRef = useRef(new Animated.Value(0)).current; + useEffect(() => { + Animated.timing(opacityRef, { + toValue: 0.7, + duration: 300, + useNativeDriver: false, + }).start(); + }, []); + + const handleOnClose = (callback: () => void) => { + Animated.timing(opacityRef, { + toValue: 0, + duration: 300, + useNativeDriver: false, + }).start(() => { + callback(); + }); + }; + + return ( + + + + + ¿Te gustó esta actividad? Califícala + + handleOnClose(onClose)} + /> + {setRating(rating)}} /> + handleOnClose(() => onSubmitted(rating))} /> + + + ); +}; + +const styles = StyleSheet.create({ + mainContainer: { + position: "absolute", + justifyContent: "center", + alignItems: "center", + width: "100%", + height: "100%", + }, + opacityContainer: { + width: "100%", + height: "100%", + position: "absolute", + backgroundColor: "rgb(0,0,0)", + }, + ratingContainer: { + aspectRatio: "1/1", + backgroundColor: "white", + zIndex: 2, + paddingTop: 30, + borderRadius: 10, + }, + closeButton: { + position: "absolute", + top: 10, + right: 10, + zIndex: 3, + }, + messageText: { + fontSize: 18, + fontWeight: "700", + textAlign: "center", + margin: 20, + }, +}); -- GitLab From 6554f3eff9fb68d33cfc1306b881e33400dbfa67 Mon Sep 17 00:00:00 2001 From: Lorenzo Trujillo Date: Sun, 8 Sep 2024 11:53:26 -0600 Subject: [PATCH 08/19] =?UTF-8?q?Se=20hizo=20opcional=20la=20opci=C3=B3n?= =?UTF-8?q?=20de=20regresar=20en=20un=20conjunto=20de=20slides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/common/components/slide_control.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/src/common/components/slide_control.tsx b/mobile/src/common/components/slide_control.tsx index 7a768812..1d52ae96 100644 --- a/mobile/src/common/components/slide_control.tsx +++ b/mobile/src/common/components/slide_control.tsx @@ -4,7 +4,7 @@ import { FontAwesome, MaterialIcons } from "@expo/vector-icons"; interface SlideControlProps { onNext: () => void; - onPrevious: () => void; + onPrevious?: () => void; onFinish: () => void; isLast: boolean; isFirst: boolean; @@ -19,7 +19,7 @@ export const SlideControl = ({ }: SlideControlProps) => { return ( - {isFirst ? : ( + {isFirst || !onPrevious ? : ( Date: Sun, 8 Sep 2024 11:54:15 -0600 Subject: [PATCH 09/19] =?UTF-8?q?Se=20cambi=C3=B3=20el=20lugar=20de=20posi?= =?UTF-8?q?cion=20del=20boton=20de=20registro?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mobile/src/auth/pages/login_page.tsx | 1 - mobile/src/auth/pages/sign_up_page.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/mobile/src/auth/pages/login_page.tsx b/mobile/src/auth/pages/login_page.tsx index 45518bf8..976a123f 100644 --- a/mobile/src/auth/pages/login_page.tsx +++ b/mobile/src/auth/pages/login_page.tsx @@ -29,7 +29,6 @@ export const LoginPage = () => { -