diff --git a/web/src/components/admin_panel_navbar/admin_navbar.tsx b/web/src/components/admin_panel_navbar/admin_navbar.tsx
deleted file mode 100644
index 81e61e3d..00000000
--- a/web/src/components/admin_panel_navbar/admin_navbar.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faEye, faEyeSlash, faSignOut, faUser, faWindowClose } from "@fortawesome/free-solid-svg-icons";
-import { Link } from "react-router-dom";
-import './assets/styles/style.css';
-import { UserRole } from "../../constants/roles";
-import { useUserData } from "../../hooks/useUserData";
-import { Dispatch, SetStateAction, useState } from "react";
-import { useAdminChangePassword } from "../../hooks/useAdminChangePassword";
-import { usePasswoordVisibility } from "../../hooks/usePasswordVisibility";
-
-interface props{
- isWindowActive: boolean;
- setIsWindowActive: Dispatch
>;
-}
-
-export const AdminPanelNavBar = ({isWindowActive, setIsWindowActive}:props) => {
- const {user, handleLogout, setToggle, toggle, userData} = useUserData();
- const [changePasswordWindowActive, setChangePasswordWindowActive] = useState(false);
- const setChangePasswordWindowVisibility = (visibility: boolean) => {
- setIsWindowActive(visibility);
- setChangePasswordWindowActive(visibility);
- }
- const {register, handleSubmit, errors, onSubmit} = useAdminChangePassword(setChangePasswordWindowVisibility);
- const {
- values: valuesPrevPassword,
- handleClickShowPassword: handleClickShowPrevPassword,
- handleMouseDownPassword: handleMouseDownPrevPassword
- } = usePasswoordVisibility();
- const {
- values: valuesNewPassword,
- handleClickShowPassword: handleClickShowNewPassword,
- handleMouseDownPassword: handleMouseDownNewPassword
- } = usePasswoordVisibility();
- const {
- values: valuesNewPasswordConfirm,
- handleClickShowPassword: handleClickShowNewPasswordConfirm,
- handleMouseDownPassword: handleMouseDownNewPasswordConfirm
- } = usePasswoordVisibility();
-
-
- if(!user ){
- return null;
- }else{
- if(user.role !== UserRole.ADMIN && user.role !== UserRole.SUPERADMIN){
- return null;
- }
- }
-
- return (
-
-
-
{
- isWindowActive
- ?
- setToggle(false)
- :
- setToggle(!toggle)
- }}
- style={
- isWindowActive
- ?
- {cursor: "auto"}
- :
- {cursor: "pointer"}
- }
- />
- {toggle &&
-
-
-
-
-
{userData?.name}
-
-
-
-
{setChangePasswordWindowVisibility(true); setToggle(false);}} className="sub-menu-link">
-
-
Cambiar contraseña
-
-
-
-
-
Cerrar sesión
-
-
-
- }
-
- {
- changePasswordWindowActive &&
-
-
- Cambio de contraseña
- setChangePasswordWindowVisibility(false)}/>
-
-
-
-
- }
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx b/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx
deleted file mode 100644
index 94aa6d31..00000000
--- a/web/src/components/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import DataTable, { TableColumn } from 'react-data-table-component';
-import { usePlace } from '../../../hooks/usePlace';
-import './assets/css/styles.css';
-import { Place } from '../../../infraestructure/entities/place';
-import { LoadingSpinner } from '../../loading_spinner/loading_spinner';
-import { faEdit } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Dispatch, SetStateAction, useEffect } from 'react';
-
-interface props{
- idTown: number;
- isWindowActive: boolean;
- setWindowVisibility: (visibility: boolean) => void;
- setActualPlace: Dispatch>;
- setIsRegisterPane: Dispatch>;
-}
-
-export const AdminPanelPlaceList = ({idTown, isWindowActive, setWindowVisibility, setActualPlace, setIsRegisterPane}: props) => {
- const {
- placeList,
- pending,
- updatePlacesByTown
- } = usePlace();
-
- const handleEditSelectedCategory = (place: Place) => {
- setIsRegisterPane(false);
- setActualPlace(place);
- setWindowVisibility(true);
- }
-
- useEffect(() => {
- updatePlacesByTown(idTown);
- },[]);
-
- const columns : TableColumn[] = [
- {
- name: "Identificador",
- selector: row => row.idPlace || 0
- },
- {
- name: "Nombre",
- selector: row => row.name,
- sortable: true
- },
- {
- name: "Estado",
- selector: row => row.available
- },
- {
- name: "Acciones",
- cell: (row) => {
- return (
- {
- if(!isWindowActive){
- handleEditSelectedCategory(row);
- }
- }}
- />
- );
- }
- }
- ];
-
- return (
-
-
- }
- columns={columns} data={placeList} className="data_table"/>
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx
deleted file mode 100644
index 8250307c..00000000
--- a/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import DataTable, { TableColumn } from 'react-data-table-component';
-import { usePlace } from '../../../hooks/usePlace';
-import './assets/css/styles.css';
-import { LoadingSpinner } from '../../loading_spinner/loading_spinner';
-import { faEye } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Dispatch, SetStateAction, useEffect, useState } from 'react';
-import { usePointOfInterest } from '../../../hooks/usePointOfInterest';
-import { PointOfInterest } from '../../../infraestructure/entities/poi';
-import { LoadingScreen } from '../../loading_screen/loading_screen';
-
-interface props{
- idTown: number;
- isWindowActive: boolean;
- setActualPoint: Dispatch>;
- setWindowVisibilityViewer: (visibility: boolean) => void;
- setBinaryData: Dispatch>;
- setIsPDFViewerActive: Dispatch>;
-}
-
-export const AdminPanelPoiList = ({idTown, isWindowActive, setActualPoint, setWindowVisibilityViewer, setBinaryData,
- setIsPDFViewerActive
-}: props) => {
- const [isLoading, setIsLoading] = useState(false);
- const [isPDFLoading, setIsPDFLoading] = useState(false);
- const [printButtonActive, setPrintButtonActive] = useState(false);
- const [selectedRows, setSelectedRows] = useState([]);
- const [actualPlaceId, setActualPlaceId] = useState(0);
- const {getPdfById} = usePointOfInterest();
-
- const handleRowSelected = (selected: { allSelected: boolean; selectedCount: number; selectedRows: PointOfInterest[];}) => {
- setSelectedRows(selected.selectedRows.map((element)=>{return element.idPoint || -1}));
- }
-
- useEffect(()=>{
- if(selectedRows.length>0){
- setPrintButtonActive(true);
- }else{
- setPrintButtonActive(false);
- }
- },[selectedRows]);
-
- const handleClickPrintButton = () => {
- const fetchPdf = async () => {
- setIsPDFLoading(true);
- const res = await getPdfById(actualPlaceId, selectedRows);
- if(res!==null){
- setIsPDFViewerActive(true);
- setBinaryData(res);
- }
- setIsPDFLoading(false);
- }
- fetchPdf();
- }
-
- const {
- placeList,
- updatePlacesByTown
- } = usePlace();
-
- const {
- pending,
- updatePOIByPlace,
- poiList
- } = usePointOfInterest();
-
- const handleViewSelectedPoint = (point: PointOfInterest) => {
- setActualPoint(point);
- setWindowVisibilityViewer(true);
- }
-
- const columns : TableColumn[] = [
- {
- name: "Identificador",
- selector: row => row.idPoint || -1,
- sortable: true
- },
- {
- name: "Nombre",
- selector: row => row.name.substring(0,40),
- sortable: true
- },
- {
- name: "Acciones",
- cell: (row) => {
- return (
- {
- if(!isWindowActive){
- handleViewSelectedPoint(row);
- }
- }}
- />
- );
- }
- }
- ];
-
- useEffect(() => {
- setIsLoading(true);
- updatePlacesByTown(idTown);
- setIsLoading(false);
- },[]);
-
- const refreshList = (idPlace: number) => {
- updatePOIByPlace(idPlace)
- };
-
-
- if(isLoading) return
-
- return (
-
-
- Lugar
-
-
-
-
-
- }
- onSelectedRowsChange={handleRowSelected}
- columns={columns} data={poiList} selectableRows className="data_table"
- />
-
- {
- isPDFLoading &&
- }
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx
deleted file mode 100644
index 25b25c85..00000000
--- a/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx
+++ /dev/null
@@ -1,205 +0,0 @@
-import { faWindowClose } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { useEffect, useState} from "react";
-import "./assets/css/styles.css";
-import { languaguesList } from "../../../constants/languages";
-import { LoadingScreen } from "../../loading_screen/loading_screen";
-import { usePointOfInterest } from "../../../hooks/usePointOfInterest";
-import { EmptyPointOfInterest, PointOfInterest } from "../../../infraestructure/entities/poi";
-import { ImageDropzone } from "../../image_dropzone/image_dropzone";
-import { usePlace } from "../../../hooks/usePlace";
-
-interface props {
- setWindowVisibility: (visibility: boolean) => void;
- idTown: number;
- forceRenderList: () => void;
- isRegister: boolean;
- form?: PointOfInterest;
-}
-
-export const AdminPanelPoiRegister = ({setWindowVisibility, idTown,forceRenderList, isRegister, form}: props) => {
- const {
- register,
- errors,
- setDescriptions,
- setDirections,
- descriptions,
- directions,
- setLanguageDescriptionIndexSelected,
- handleSubmit,
- onSubmitRegister,
- getPointById,
- setValue,
- languageDescriptionIndexSelected,
- languageDirectionsIndexSelected,
- setLanguageDirectionsIndexSelected,
- } = usePointOfInterest(forceRenderList, setWindowVisibility);
- const [isLoading, setIsLoading] = useState(false);
- const [preview, setPreview] = useState(null);
- const [image, setImage] = useState(null);
- const {
- placeList,
- updatePlacesByTown
- } = usePlace();
-
- useEffect(() => {
- if(image){
- setValue('image', image, {shouldValidate: true});
- }
- },[image]);
-
- useEffect(() => {
- setIsLoading(true);
- const fetchData = async () => {
- await updatePlacesByTown(idTown);
- if (!isRegister && form) {
- const pointGetted = await getPointById(form.idPoint || 0);
- if(pointGetted){
- setValue('idPoint', pointGetted.idPlace);
- setValue('name', pointGetted.name);
- setValue('contentEN', pointGetted.contentEN);
- setValue('contentES', pointGetted.contentES);
- setValue('directionsEN', pointGetted.directionsEN);
- setValue('directionsES', pointGetted.directionsES);
- }
- }
- };
- fetchData();
- setIsLoading(false);
- },[]);
-
- return (
-
-
- Registra el punto de interés
- setWindowVisibility(false)}/>
-
-
- {isLoading
- ?
-
- :
-
- }
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx
deleted file mode 100644
index 48c0763e..00000000
--- a/web/src/components/admin_panel_poi/admin_panel_poi_screen/admin_panel_poi_screen.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-import { Dispatch, SetStateAction, useEffect, useState } from "react";
-import { AdminPanelPoiRegister } from "../admin_panel_poi_register/admin_panel_poi_register";
-import "./assets/css/styles.css";
-import { AdminPanelPoiList } from "../admin_panel_poi_list/admin_panel_poi_list";
-import { Town } from "../../../infraestructure/entities/town";
-import { PointOfInterest } from "../../../infraestructure/entities/poi";
-import { AdminPanelPoiViewer } from "../admin_panel_poi_viewer/admin_panel_poi_viewer";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faWindowClose } from "@fortawesome/free-solid-svg-icons";
-
-interface props {
- isWindowActive: boolean;
- setIsWindowActive: Dispatch>;
- town: Town | undefined;
-}
-
-export const AdminPanelPoiScreen = ({isWindowActive,setIsWindowActive, town}: props) => {
- const [renderCount, setRenderCount] = useState(0);
- const [isRegisterPane, setIsRegisterPane] = useState(true);
- const [actualPoint, setActualPoint] = useState();
- const [isRegisterWindowActive, setIsRegisterWindowActive] = useState(false);
- const [isViewerWindowActive, setIsViewerWindowActive] = useState(false);
- const [isPDFViewerActive, setIsPDFViewerActive] = useState(false);
- const [binaryData, setBinaryData] = useState('');
-
- const forceRenderList = () =>{
- setRenderCount(prevCount => prevCount + 1);
- setIsWindowActive(false);
- }
-
- const setWindowVisibilityRegister = (visibility: boolean) => {
- setIsRegisterWindowActive(visibility);
- setIsWindowActive(visibility);
- }
-
- const setWindowVisibilityViewer = (visibility: boolean) => {
- setIsViewerWindowActive(visibility);
- setIsWindowActive(visibility);
- }
-
- return (
-
-
- Administrar puntos de interés dentro de un lugar
-
-
-
- {
- isRegisterWindowActive &&
- }
- {
- isViewerWindowActive &&
- }
-
- {
- isPDFViewerActive &&
-
-
- {
- setIsPDFViewerActive(false);
- setBinaryData('');
- }}/>
-
-
-
-
-
- }
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx b/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx
deleted file mode 100644
index e06694a0..00000000
--- a/web/src/components/admin_panel_poi/admin_panel_poi_viewer/admin_panel_poi_viewer.tsx
+++ /dev/null
@@ -1,176 +0,0 @@
-import { useEffect, useState } from "react";
-import { PointOfInterest } from "../../../infraestructure/entities/poi";
-import { usePointOfInterest } from "../../../hooks/usePointOfInterest";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faWindowClose } from "@fortawesome/free-solid-svg-icons";
-import { LoadingScreen } from "../../loading_screen/loading_screen";
-import { languaguesList } from "../../../constants/languages";
-import { usePlace } from "../../../hooks/usePlace";
-import './assets/css/styles.css';
-
-interface props{
- pointId: number;
- setWindowVisibility: (visibility: boolean) => void;
-}
-
-export const AdminPanelPoiViewer = ({pointId, setWindowVisibility}: props) => {
- const [point, setPoint] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [languageDescriptionIndexSelected, setLanguageDescriptionIndexSelected] = useState(0);
- const [languageDirectionsIndexSelected, setLanguageDirectionsIndexSelected] = useState(0);
- const [descriptions, setDescriptions] = useState(new Array(languaguesList.length).fill(""));
- const [directions, setDirections] = useState(new Array(languaguesList.length).fill(""));
- const [placeName, setPlaceName] = useState('');
-
- const {
- getPointById
- } = usePointOfInterest();
-
- const{
- getPlaceById
- } = usePlace();
-
- useEffect(()=>{
- fetchData();
- },[]);
-
- const fetchData = async () => {
- setIsLoading(true);
- const result = await getPointById(pointId);
- if(result){
- setPoint(result);
- const newDescriptions = descriptions.map((element, index) => {
- if(index===0){
- return result.contentES;
- }else if(index === 1){
- return result.contentEN;
- }else{
- return element;
- }
- });
- setDescriptions(newDescriptions);
-
- const newDirections = directions.map((element, index) => {
- if(index===0){
- return result.directionsES;
- }else if(index === 1){
- return result.directionsEN;
- }else{
- return element;
- }
- });
- setDirections(newDirections);
-
- const place = await getPlaceById(result.idPlace);
- if(place){
- setPlaceName(place.name);
- }
- }
- setIsLoading(false);
- }
-
- return (
-
-
- Información del punto de interés
- setWindowVisibility(false)}/>
-
- {isLoading || point === null
- ?
-
- :
-
-
-
-
- Nombre del punto de interés
-
-
-
-
-
- Descripción del punto de interés
-
-
- {
- languaguesList.map((language, index) => {
- if(index===languageDescriptionIndexSelected){
- return (
-
- );
- }
- })
- }
-
-
-
-
- Direcciones hacia el siguiente punto de interés
-
-
- {
- languaguesList.map((language, index) => {
- if(index===languageDirectionsIndexSelected){
- return (
-
- );
- }
- })
- }
-
-
-
-
- Nombre del lugar al que pertenece el punto de interés
-
-
-
-
-
-
- Nombre del punto de interés
-
-
-
-
-
-
- }
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/admin_town_info/admin_town_info.tsx b/web/src/components/admin_town_info/admin_town_info.tsx
deleted file mode 100644
index 22b72931..00000000
--- a/web/src/components/admin_town_info/admin_town_info.tsx
+++ /dev/null
@@ -1,119 +0,0 @@
-import { Dispatch, SetStateAction, useState} from "react";
-import { Town } from "../../infraestructure/entities/town";
-import "./assets/css/styles.css";
-import { faEdit, faLanguage } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { LoadingScreen } from "../loading_screen/loading_screen";
-import { useAdminTownInfo } from "../../hooks/useAdminTownInfo";
-import { SuperadminPanelTownRegister } from "../sa_panel_town/sa_panel_town_register/sa_panel_town_register";
-
-interface props {
- isWindowActive: boolean;
- setIsWindowActive: Dispatch>;
- town: Town | undefined;
- updateTown: () => Promise;
-}
-
-export const AdminTownInfo = ({updateTown, isWindowActive, setIsWindowActive, town}: props) => {
- const {
- isEnglish,
- isLoading,
- setIsEnglish,
- setIsLoading,
- renderCount,
- forceRenderList,
- statesList
- } = useAdminTownInfo(updateTown);
- const [isTownRegisterWindowActive, setIsTownRegisterWindowActive] = useState(false);
-
- const setWindowVisibility = (visibility: boolean) => {
- setIsTownRegisterWindowActive(visibility);
- setIsWindowActive(visibility);
- }
-
- if(!town){
- return (
-
- No tienes un pueblo asignado
-
- );
- }
-
- return (
-
- {isTownRegisterWindowActive &&
-
- }
-
- {isLoading &&
-
-
-
- }
-
-
-
-
-
setIsLoading(false)}/>
-
-
-
-
-
-
- {
- if(!isWindowActive){
- setIsEnglish(!isEnglish);
- }
- }
- }
- />
-
-
{
- if(!isWindowActive){
- setWindowVisibility(true);
- }
- }
- }
- />
-
- {
- isEnglish ?
-
- :
-
- }
-
- {town.state}
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx b/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx
deleted file mode 100644
index 9cc98917..00000000
--- a/web/src/components/confirmation_dialog_box/confirmation_dialog.tsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Dispatch, SetStateAction } from 'react';
-import './assets/css/styles.css';
-
-interface props{
- hangleToClose: () => void;
- setAnswer?: Dispatch>;
- title?: string;
- message: string;
-}
-
-export const ConfirmationDialog = ({hangleToClose, setAnswer, title, message}:props) => {
- return (
-
-
-
{title || 'Confirmar acción'}
-
-
-
-
-
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/image_dropzone/image_dropzone.tsx b/web/src/components/image_dropzone/image_dropzone.tsx
deleted file mode 100644
index cb55cf7c..00000000
--- a/web/src/components/image_dropzone/image_dropzone.tsx
+++ /dev/null
@@ -1,57 +0,0 @@
-import { toast } from 'react-toastify';
-import { useDropzone } from "react-dropzone";
-import './assets/css/styles.css';
-import { Dispatch, SetStateAction } from 'react';
-import "react-toastify/dist/ReactToastify.css";
-
-interface props {
- setImage: Dispatch>;
- preview : string | ArrayBuffer | null;
- setPreview: Dispatch>;
-}
-
-export const ImageDropzone = ({setImage, preview, setPreview}: props) => {
- const MAX_SIZE = 10485760;
- const {getRootProps, getInputProps} = useDropzone(
- {
- multiple: false,
- maxSize: MAX_SIZE,
- accept: {
- 'image/jpeg': [],
- 'image/png': []
- },
- onDrop(acceptedFiles, fileRejections) {
- fileRejections.map(({file, errors}) => (
- toast.error(errors[0].message, {
- position: "bottom-right",
- autoClose: 1500,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: false,
- draggable: true,
- progress: undefined,
- theme: "colored"
- })));
-
- acceptedFiles.forEach((file)=>{
- const preview = URL.createObjectURL(file);
- setImage(file);
- setPreview(preview);
- });
- }
- }
- );
-
- return (
-
-
-
- {preview ? (
-
- ) : (
-
Arrastra tu imagen o seleccionala dando click aquí.
- )}
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/loading_screen/loading_screen.tsx b/web/src/components/loading_screen/loading_screen.tsx
deleted file mode 100644
index 42c89426..00000000
--- a/web/src/components/loading_screen/loading_screen.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import './assets/css/styles.css';
-
-export const LoadingScreen = () => {
- return (
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx b/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx
deleted file mode 100644
index 9b0eef09..00000000
--- a/web/src/components/multiple_images_dropzone/multiple_images_dropzone.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import { UseFormSetValue } from "react-hook-form";
-import { Place } from "../../infraestructure/entities/place";
-import { useDropzoneMultiplesImages } from "../../hooks/useDropzoneMultiplesImages";
-import "./assets/css/styles.css";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faTimesCircle } from "@fortawesome/free-solid-svg-icons";
-
-interface props{
- setValue: UseFormSetValue;
- imagesList?: File[] | string[];
-}
-
-export const MultipleImagesDropzone = ({setValue, imagesList}:props) => {
- const {
- getRootProps,
- getInputProps,
- imagesFiles,
- removeImage,
- } = useDropzoneMultiplesImages(setValue, imagesList);
-
- return (
-
-
-
-
Arrastra tu imagen o seleccionala dando click aquí.
-
-
- {
- imagesFiles.map((image, index) => {
- return (
-
-
-
{URL.revokeObjectURL(image.preview)}}
- />
-
-
removeImage(index)}
- />
-
- );
- })
- }
-
-
- );
-}
-
diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx
deleted file mode 100644
index f4ca3657..00000000
--- a/web/src/components/sa_panel_admin/sa_panel_admin_list/sa_panel_admin_list.tsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import DataTable, { TableColumn } from 'react-data-table-component';
-import './assets/css/styles.css';
-import { LoadingSpinner } from '../../loading_spinner/loading_spinner';
-import { useState } from 'react';
-import { Admin } from '../../../infraestructure/entities/admin_form_values';
-import { State } from '../../../infraestructure/entities/state';
-import { useTown } from '../../../hooks/useTown';
-import axios, { AxiosError } from 'axios';
-import { showErrorAxios } from '../../../utils/Messages';
-import { useAdmin } from '../../../hooks/useAdmin';
-
-interface props{
- isWindowActive: boolean;
- statesList: State[];
-}
-
-export const SuperAdminPanelAdminList = ({isWindowActive, statesList}: props) => {
- const [isLoading, setIsLoading] = useState(false);
- const {
- townsList,
- getTownsByState
- } = useTown();
-
- const {
- adminList,
- getAdminListByTown
- } = useAdmin();
-
- const columns : TableColumn[] = [
- {
- name: "Email",
- selector: row => row.email,
- sortable: true
- },
- {
- name: "Nombre",
- selector: row => row.name.substring(0,40),
- sortable: true
- },
- {
- name: "Apellido",
- selector: row => row.lastName.substring(0,40),
- sortable: true
- },
- {
- name: "Estatus",
- selector: row => row.status?.substring(0,40) ?? "",
- sortable: true
- }
- ];
-
- const refreshListTown = (stateId: number, name: string) => {
- setIsLoading(true);
- const getTownsList = async () => {
- try {
- getTownsByState(stateId, name);
- } catch (error: any) {
- if (axios.isAxiosError(error)) {
- error as AxiosError;
- showErrorAxios(error);
- }
- }
- }
- getTownsList();
- setIsLoading(false);
- };
-
- const refreshListAdmins = (idTown: number) => {
- setIsLoading(true);
- const getAdminsList = async () => {
- try {
- getAdminListByTown(idTown);
- } catch (error: any) {
- if (axios.isAxiosError(error)) {
- error as AxiosError;
- showErrorAxios(error);
- }
- }
- }
- getAdminsList();
- setIsLoading(false);
- };
-
- if(isLoading) return
-
- return (
-
-
- Estado
-
-
- Pueblo mágico
-
-
-
-
-
- }
- columns={columns} data={adminList} selectableRows className="data_table"
- />
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx
deleted file mode 100644
index 5eb361a5..00000000
--- a/web/src/components/sa_panel_admin/sa_panel_admin_register/sa_panel_admin_register.tsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import { Dispatch, SetStateAction } from "react";
-import './assets/css/styles.css'
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faWindowClose, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
-import { useAdmin } from "../../../hooks/useAdmin";
-import { usePasswoordVisibility } from "../../../hooks/usePasswordVisibility";
-import { State } from "../../../infraestructure/entities/state";
-import { useTown } from "../../../hooks/useTown";
-
-interface props {
- handleClickToClose: () => void;
- forceRenderList: () => void;
- statesList : State[];
-}
-
-export const SuperadminPanelAdminRegister = ({handleClickToClose, forceRenderList, statesList}:props) => {
- const {
- register,
- errors,
- handleSubmit,
- onSubmit,
- } = useAdmin(forceRenderList, handleClickToClose);
-
- const {
- values,
- handleClickShowPassword,
- handleMouseDownPassword
- } = usePasswoordVisibility();
-
- const {townsList, getTownsByState} = useTown();
-
- return (
-
-
- Registra el administrador
- handleClickToClose()}/>
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx b/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx
deleted file mode 100644
index efc62d5e..00000000
--- a/web/src/components/sa_panel_admin/sa_panel_admin_screen/sa_panel_admin_screen.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { Dispatch, SetStateAction, useState } from 'react';
-import './assets/css/styles.css';
-import { SuperadminPanelAdminRegister } from '../sa_panel_admin_register/sa_panel_admin_register';
-import { State } from '../../../infraestructure/entities/state';
-import { SuperAdminPanelAdminList } from '../sa_panel_admin_list/sa_panel_admin_list';
-
-interface props {
- isWindowActive: boolean;
- setIsWindowActive: Dispatch>;
- statesList: State[];
-}
-
-export const SuperadminPanelAdminScreen = ({isWindowActive, setIsWindowActive, statesList}:props) => {
- const [showRegisterPanel, setShowRegisterPanel] = useState(false);
- const [renderCount, setRenderCount] = useState(0);
-
- const handleClickToClose = () => {
- setIsWindowActive(false);
- setShowRegisterPanel(false);
- }
-
- const forceRenderList = () =>{
- setRenderCount(prevCount => prevCount + 1);
- }
-
- return (
-
-
- Administrar administradores
-
-
-
- {showRegisterPanel
- &&
-
- }
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx b/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx
deleted file mode 100644
index 9d74d986..00000000
--- a/web/src/components/sa_panel_category/sa_panel_category_list/sa_panel_category_list.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import DataTable, { TableColumn } from 'react-data-table-component';
-import './assets/css/styles.css';
-import { LoadingSpinner } from '../../loading_spinner/loading_spinner';
-import { useCategory } from '../../../hooks/useCategory';
-import { Category } from '../../../infraestructure/entities/category';
-import { faTrash } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Dispatch, SetStateAction, useEffect, useState } from 'react';
-import { ConfirmationDialog } from '../../confirmation_dialog_box/confirmation_dialog';
-import { toast } from 'react-toastify';
-
-interface props {
- isWindowActive: boolean;
- setIsWindowActive: Dispatch>;
-}
-
-export const SuperAdminPanelCategoryList = ({isWindowActive, setIsWindowActive}:props) => {
- const {
- categoriesList,
- pending,
- deleteCategory,
- } = useCategory();
- const [isDialogOpen, setIsDialogOpen] = useState(false);
- const [dialogMessage, setDialogMessage] = useState('');
- const [categoryDeleted, setCategoryDeleted] = useState(null);
- const [deleteCategoryBool, setDeleteCategoryBool] = useState(false);
-
- const deleteSelectedCategory = (category: Category) => {
- toast.promise(
- deleteCategory(category),{
- pending: "Eliminando categoría...",
- success: "La categoría se ha eliminado correctamente",
- error: "No se pudo eliminar la categoría"
- }
- )
- }
-
- useEffect(() => {
- if(deleteCategoryBool && categoryDeleted){
- deleteSelectedCategory(categoryDeleted);
- setDeleteCategoryBool(false);
- }
- }, [deleteCategoryBool]);
-
- const handleDeleteSelectedCategory = (category: Category) => {
- setDialogMessage(`¿Desea eliminar la categoría ${category.nameES}?`)
- setCategoryDeleted(category);
- setIsDialogOpen(true);
- setIsWindowActive(true);
- }
-
- const handleToClose = () => {
- setIsWindowActive(false);
- setIsDialogOpen(false)
- }
-
- const columns : TableColumn[] = [
- {
- name: "Identificador",
- selector: row => row.idCategory || 0,
- sortable: true
- },
- {
- name: "Nombre en español",
- selector: row => row.nameES,
- sortable: true
- },
- {
- name: "Nombre en Inglés",
- selector: row => row.nameEN,
- sortable: true
- },
- {
- name: "Acciones",
- cell: (row) => {
- return (
- {
- if(!isWindowActive){
- handleDeleteSelectedCategory(row);
- }
- }}
- />
- );
- }
- }
- ];
-
- return (
-
-
- }
- disabled={isWindowActive}
- columns={columns} data={categoriesList} className="data_table"/>
- {
- isDialogOpen &&
- }
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx b/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx
deleted file mode 100644
index 675d0d68..00000000
--- a/web/src/components/sa_panel_category/sa_panel_category_register/sa_panel_category_register.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { faWindowClose } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Dispatch, SetStateAction} from "react";
-import "./assets/css/styles.css";
-import { useCategory } from "../../../hooks/useCategory";
-
-interface props {
- handleClickToClose: () => void;
- forceRenderList: () => void;
-}
-
-export const SuperAdminPanelCategoryRegister = ({handleClickToClose, forceRenderList}: props) => {
- const {
- register,
- handleSubmit,
- errors,
- onSubmit,
- } = useCategory(forceRenderList, handleClickToClose);
-
- return (
-
-
- Registra la categoría
- handleClickToClose()}/>
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx b/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx
deleted file mode 100644
index 5717fed5..00000000
--- a/web/src/components/sa_panel_town/sa_panel_town_register/sa_panel_town_register.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import { faWindowClose, faLanguage } from "@fortawesome/free-solid-svg-icons";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import './css/styles.css'
-import { ImageDropzone } from "../../image_dropzone/image_dropzone";
-import { Dispatch, SetStateAction, useEffect, useState } from "react";
-import { useTown } from "../../../hooks/useTown";
-import { State } from "../../../infraestructure/entities/state";
-import { Town } from "../../../infraestructure/entities/town";
-
-interface props {
- setWindowActive: Dispatch>,
- setActualWindowActive: Dispatch>,
- statesList: State[] | null;
- forceRenderList: () => void;
- isRegister: boolean;
- form?: Town;
-}
-
-export const SuperadminPanelTownRegister = ({setWindowActive, statesList, forceRenderList, isRegister, form,
- setActualWindowActive
-}:props) => {
- const [isEnglish, setIsEnglish] = useState(false);
- const [spanishDescription, setSpanishDescription] = useState("");
- const [englishDescription, setEnglishDescription] = useState("");
- const [preview, setPreview] = useState(null);
- const [image, setImage] = useState(null);
- const [actualWindowVisibility, setActualWindowVisibility] = useState(true);
-
- const closeActualWindow = () => {
- setWindowActive(false);
- setActualWindowActive(false);
- }
-
- const {
- register,
- setValue,
- errors,
- handleSubmit,
- onSubmitRegister,
- onSubmitUpdate,
- } = useTown(forceRenderList, closeActualWindow);
-
- useEffect(()=> {
- if(!isRegister && form){
- const setData = async () => {
- setValue('idTown', form.idTown);
- setValue('name',form.name);
- setSpanishDescription(form?.descriptionES || '');
- setValue('descriptionES',form.descriptionES);
- setEnglishDescription(form?.descriptionEN || '');
- setValue('descriptionEN',form.descriptionEN);
- setValue('idState',form.idState);
- setPreview(form.imageURL as string);
-
- const response = await fetch(form.imageURL as string);
- const blob = await response.blob();
- const file = new File([blob],'image.jpg',{type: blob.type});
- setValue('imageURL', file);
- }
- setData();
- }
- },[])
-
- useEffect(() => {
- if(image){
- setValue('imageURL', image, {shouldValidate: true});
- }
- },[image]);
-
- return (
-
-
- {isRegister ? "Registra el pueblo mágico": "Actualiza tu pueblo mágico"}
- closeActualWindow()}/>
-
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx b/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx
deleted file mode 100644
index 4deeb58a..00000000
--- a/web/src/components/sa_panel_town/sa_panel_town_screen/sa_panel_town_screen.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { Dispatch, SetStateAction, useState } from 'react';
-import { SuperadminPanelTownRegister } from '../sa_panel_town_register/sa_panel_town_register';
-import './css/styles.css'
-import { State } from '../../../infraestructure/entities/state';
-import { SuperadminPanelTownList } from '../sa_panel_town_list/sa_panel_town_list';
-
-interface props {
- windowActive: boolean;
- setWindowActive: Dispatch>;
- statesList: State[];
-}
-
-export const SuperadminPanelTownScreen = ({windowActive,setWindowActive, statesList}:props) => {
- const [showRegisterPanel, setShowRegisterPanel] = useState(false);
- const [renderCount, setRenderCount] = useState(0);
-
- const forceRenderList = () =>{
- setRenderCount(prevCount => prevCount + 1);
- }
-
- return (
-
-
- Administrar pueblos mágicos
-
-
-
-
-
- {showRegisterPanel
- &&
- }
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/components/sidebar_header/sidebar_header.tsx b/web/src/components/sidebar_header/sidebar_header.tsx
deleted file mode 100644
index f23c496b..00000000
--- a/web/src/components/sidebar_header/sidebar_header.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { UserRole } from '../../constants/roles';
-import { useAuth } from '../../context/auth_context';
-import './assets/css/styles.css';
-
-export const SidebarHeader = () => {
- const {user} = useAuth();
- if(!user){
- return null;
- }
-
- return (
-
-
-
{user.role==UserRole.SUPERADMIN ? 'Superadmin': 'Admin'} Panel
-
-
- );
-}
\ No newline at end of file
diff --git a/web/src/constants/images_nuber.ts b/web/src/constants/images_nuber.ts
deleted file mode 100644
index d9b2beb7..00000000
--- a/web/src/constants/images_nuber.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const MIN_NUMBER_PLACE_IMAGES = 1;
\ No newline at end of file
diff --git a/web/src/constants/languages.ts b/web/src/constants/languages.ts
deleted file mode 100644
index 770db8d7..00000000
--- a/web/src/constants/languages.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export const languaguesList: string[] = [
- 'Español',
- 'Inglés',
-]
\ No newline at end of file
diff --git a/web/src/constants/roles.ts b/web/src/constants/roles.ts
deleted file mode 100644
index dd45c329..00000000
--- a/web/src/constants/roles.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export enum UserRole {
- ADMIN = "admin",
- SUPERADMIN = "superadmin",
-}
-
-export const SUPERADMIN_ROLE = UserRole.SUPERADMIN;
-export const ADMIN_ROLE = UserRole.ADMIN;
\ No newline at end of file
diff --git a/web/src/constants/selected_panel.ts b/web/src/constants/selected_panel.ts
deleted file mode 100644
index 0c2ef85c..00000000
--- a/web/src/constants/selected_panel.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export enum AdminSelectedPanel {
- TOWN_INFO = "town_info",
- PLACES = "places",
- POINT_OF_INTEREST = "point_of_interest"
-}
-
-export enum SuperAdminSelectedPanel {
- TOWNS = "towns",
- ADMINS = "admins",
- CATEGORIES = "categories"
-}
\ No newline at end of file
diff --git a/web/src/context/auth_context.tsx b/web/src/context/auth_context.tsx
deleted file mode 100644
index 0a777141..00000000
--- a/web/src/context/auth_context.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { UserEntity } from "../infraestructure/entities/user";
-import axios from "axios";
-import { UserRole } from "../constants/roles";
-import { ReactNode, createContext, useContext, useEffect, useState } from "react";
-
-type AuthContextType = {
- user: UserEntity | null;
- login: (user: UserEntity, token: string) => void;
- logout: () => void;
-};
-
-const AuthContext = createContext({
- user: null,
- login: () => {},
- logout: () => {}
-});
-
-type AuthContextProviderProps = {
- children: ReactNode;
-}
-
-export const AuthContextProvider = ({children} : AuthContextProviderProps) => {
- const [user, setUser] = useState(null);
- const saveSession = async (user: UserEntity, token: string) => {
- setUser(user);
- localStorage.setItem("token",token);
- localStorage.setItem("user",JSON.stringify(user));
- axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
- }
-
- const deleteSession = async () => {
- setUser(null);
- localStorage.removeItem("token");
- localStorage.removeItem("user");
- axios.defaults.headers.common["Authorization"] = "";
- }
-
- const login = async (user: UserEntity, token: string) => {
- await saveSession(user, token);
- }
-
- const logout = async () => {
- await deleteSession();
- }
-
- const checkSession = async () => {
- const token = localStorage.getItem("token");
- const user = localStorage.getItem("user");
- if(token && user){
- const sessionUser = JSON.parse(user);
- await saveSession({email: sessionUser.email as string, name: sessionUser.name as string, role: sessionUser.role as UserRole}, token);
- }
- }
-
- useEffect(() => {
- checkSession();
- }, []);
-
- const value = {user, login, logout};
- return {children}
-};
-
-export const useAuth = () => {
- if(AuthContext == undefined){
- throw new Error("useAuth debe se usado dentro de un AuthContextProvider");
- }
- return useContext(AuthContext);
-};
\ No newline at end of file
diff --git a/web/src/constants/api_routes.ts b/web/src/core/constants/api_routes.ts
similarity index 53%
rename from web/src/constants/api_routes.ts
rename to web/src/core/constants/api_routes.ts
index cdb28e94..1c403b23 100644
--- a/web/src/constants/api_routes.ts
+++ b/web/src/core/constants/api_routes.ts
@@ -1,13 +1,52 @@
+/**
+ * API route for admin operations.
+ */
export const API_ROUTE_ADMIN = "/admin";
+
+/**
+ * API route for admin signup.
+ */
export const API_ROUTE_ADMIN_SIGNUP = API_ROUTE_ADMIN + "/signup";
+
+/**
+ * API route for admin signin.
+ */
export const API_ROUTE_ADMIN_SIGNIN = API_ROUTE_ADMIN + "/signin";
+
+/**
+ * API route for changing admin password.
+ */
export const API_ROUTE_ADMIN_CHANGE_PASSWORD =
API_ROUTE_ADMIN + "/change-password";
+
+/**
+ * API route for resetting admin password.
+ */
export const API_ROUTE_ADMIN_RESET_PASSWORD =
API_ROUTE_ADMIN + "/reset-password";
+
+/**
+ * API route for generating admin reset code.
+ */
export const API_ROUTE_ADMIN_GENERATE_RESET_CODE =
API_ROUTE_ADMIN + "/get-reset-code";
+
+/**
+ * API route for getting admin information.
+ */
export const API_ROUTE_ADMIN_WHOAMI = API_ROUTE_ADMIN + "/whoami";
-const API_ROUTE_STATE = "/state";
+
+/**
+ * API route for state operations.
+ */
+export const API_ROUTE_STATE = "/state";
+
+/**
+ * API route for point operations.
+ */
export const API_ROUTE_POINT = "/point";
+
+/**
+ * API route for place operations.
+ */
export const API_ROUTE_PLACE = "/place";
diff --git a/web/src/constants/api_url.ts b/web/src/core/constants/api_url.ts
similarity index 62%
rename from web/src/constants/api_url.ts
rename to web/src/core/constants/api_url.ts
index b712d339..463d2127 100644
--- a/web/src/constants/api_url.ts
+++ b/web/src/core/constants/api_url.ts
@@ -1 +1,4 @@
+/**
+ * Base URL for the API.
+ */
export const APIUrl: String = "http://localhost:3005";
\ No newline at end of file
diff --git a/web/src/core/constants/images_nuber.ts b/web/src/core/constants/images_nuber.ts
new file mode 100644
index 00000000..e0472767
--- /dev/null
+++ b/web/src/core/constants/images_nuber.ts
@@ -0,0 +1,4 @@
+/**
+ * Minimum number of images required for a place.
+ */
+export const MIN_NUMBER_PLACE_IMAGES = 1;
\ No newline at end of file
diff --git a/web/src/core/constants/languages.ts b/web/src/core/constants/languages.ts
new file mode 100644
index 00000000..9832daad
--- /dev/null
+++ b/web/src/core/constants/languages.ts
@@ -0,0 +1,7 @@
+/**
+ * List of supported languages.
+ */
+export const languaguesList: string[] = [
+ 'Español', // Spanish
+ 'Inglés', // English
+]
\ No newline at end of file
diff --git a/web/src/core/constants/roles.ts b/web/src/core/constants/roles.ts
new file mode 100644
index 00000000..fcc8e974
--- /dev/null
+++ b/web/src/core/constants/roles.ts
@@ -0,0 +1,17 @@
+/**
+ * Enum representing the different user roles.
+ */
+export enum UserRole {
+ ADMIN = "admin", // Admin role
+ SUPERADMIN = "superadmin", // Super admin role
+}
+
+/**
+ * Constant representing the super admin role.
+ */
+export const SUPERADMIN_ROLE = UserRole.SUPERADMIN;
+
+/**
+ * Constant representing the admin role.
+ */
+export const ADMIN_ROLE = UserRole.ADMIN;
\ No newline at end of file
diff --git a/web/src/core/constants/selected_panel.ts b/web/src/core/constants/selected_panel.ts
new file mode 100644
index 00000000..d9691ddb
--- /dev/null
+++ b/web/src/core/constants/selected_panel.ts
@@ -0,0 +1,17 @@
+/**
+ * Enum representing the different panels available for an admin user.
+ */
+export enum AdminSelectedPanel {
+ TOWN_INFO = "town_info", // Panel for town information
+ PLACES = "places", // Panel for places
+ POINT_OF_INTEREST = "point_of_interest" // Panel for points of interest
+}
+
+/**
+ * Enum representing the different panels available for a super admin user.
+ */
+export enum SuperAdminSelectedPanel {
+ TOWNS = "towns", // Panel for towns
+ ADMINS = "admins", // Panel for admins
+ CATEGORIES = "categories" // Panel for categories
+}
\ No newline at end of file
diff --git a/web/src/core/context/auth_context.tsx b/web/src/core/context/auth_context.tsx
new file mode 100644
index 00000000..51a2373b
--- /dev/null
+++ b/web/src/core/context/auth_context.tsx
@@ -0,0 +1,92 @@
+import { UserEntity } from "../../data/datasource/api/entities/user";
+import axios from "axios";
+import { UserRole } from "../constants/roles";
+import {
+ ReactNode,
+ createContext,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
+
+// Define the shape of the context state and actions
+type AuthContextType = {
+ user: UserEntity | null; // The authenticated user or null if not authenticated
+ login: (user: UserEntity, token: string) => void; // Function to log in the user
+ logout: () => void; // Function to log out the user
+};
+
+// Create the context with default values
+const AuthContext = createContext({
+ user: null,
+ login: () => {},
+ logout: () => {},
+});
+
+// Define the props for the AuthContextProvider component
+type AuthContextProviderProps = {
+ children: ReactNode; // The child components that will have access to the context
+};
+
+// Create the provider component
+export const AuthContextProvider = ({ children }: AuthContextProviderProps) => {
+ const [user, setUser] = useState(null); // State to track the authenticated user
+
+ // Function to save the session data in local storage and set the authorization header
+ const saveSession = async (user: UserEntity, token: string) => {
+ setUser(user);
+ localStorage.setItem("token", token);
+ localStorage.setItem("user", JSON.stringify(user));
+ axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
+ };
+
+ // Function to delete the session data from local storage and clear the authorization header
+ const deleteSession = async () => {
+ setUser(null);
+ localStorage.removeItem("token");
+ localStorage.removeItem("user");
+ axios.defaults.headers.common["Authorization"] = "";
+ };
+
+ // Function to log in the user by saving the session
+ const login = async (user: UserEntity, token: string) => {
+ await saveSession(user, token);
+ };
+
+ // Function to log out the user by deleting the session
+ const logout = async () => {
+ await deleteSession();
+ };
+
+ // Check if there is an existing session in local storage when the component mounts
+ useEffect(() => {
+ const checkSession = async () => {
+ const token = localStorage.getItem("token");
+ const user = localStorage.getItem("user");
+ if (token && user) {
+ const sessionUser = JSON.parse(user);
+ await saveSession(
+ {
+ email: sessionUser.email as string,
+ name: sessionUser.name as string,
+ role: sessionUser.role as UserRole,
+ },
+ token
+ );
+ }
+ };
+ checkSession();
+ }, []);
+
+ // Provide the context value to child components
+ const value = { user, login, logout };
+ return {children};
+};
+
+// Custom hook to use the AuthContext
+export const useAuth = () => {
+ if (AuthContext === undefined) {
+ throw new Error("useAuth debe se usado dentro de un AuthContextProvider");
+ }
+ return useContext(AuthContext);
+};
diff --git a/web/src/context/message_context.tsx b/web/src/core/context/message_context.tsx
similarity index 50%
rename from web/src/context/message_context.tsx
rename to web/src/core/context/message_context.tsx
index 1ce309be..4bee0a31 100644
--- a/web/src/context/message_context.tsx
+++ b/web/src/core/context/message_context.tsx
@@ -1,12 +1,14 @@
import { createContext, ReactNode, useContext, useState } from "react";
+// Define the shape of the context state and actions
type MessageContextType = {
- isVisible: boolean;
- message: string;
- showMessage: (message: string) => void;
- hideMessage: () => void;
+ isVisible: boolean; // Indicates if the message is visible
+ message: string; // The message to be displayed
+ showMessage: (message: string) => void; // Function to show the message
+ hideMessage: () => void; // Function to hide the message
}
+// Create the context with default values
const MessageContext = createContext({
isVisible: false,
message: "",
@@ -14,13 +16,17 @@ const MessageContext = createContext({
hideMessage: () => {}
});
+// Define the props for the MessageContextProvider component
type MessageContextProviderProps = {
- children: ReactNode;
+ children: ReactNode; // The child components that will have access to the context
}
+// Create the provider component
export const MessageContextProvider = ({children}: MessageContextProviderProps) => {
- const [isVisible, setIsVisible] = useState(false);
- const [message, setMessage] = useState("");
+ const [isVisible, setIsVisible] = useState(false); // State to track visibility of the message
+ const [message, setMessage] = useState(""); // State to track the message content
+
+ // Function to show the message and hide it after 3 seconds
const showMessage = (message: string) => {
setIsVisible(true);
setMessage(message);
@@ -30,17 +36,20 @@ export const MessageContextProvider = ({children}: MessageContextProviderProps)
}, 3000);
};
+ // Function to hide the message immediately
const hideMessage = () => {
setIsVisible(false);
setMessage("");
};
+ // Provide the context value to child components
const value = {isVisible, message, showMessage, hideMessage};
return {children}
}
+// Custom hook to use the MessageContext
export const useMessage = () => {
- if(MessageContext == undefined){
+ if(MessageContext === undefined){
throw new Error("useMessage debe se usado dentro de un MessageContextProvider");
}
return useContext(MessageContext);
diff --git a/web/src/core/errors/CustomError.ts b/web/src/core/errors/CustomError.ts
new file mode 100644
index 00000000..a8eeb8e7
--- /dev/null
+++ b/web/src/core/errors/CustomError.ts
@@ -0,0 +1,26 @@
+/**
+ * CustomErrorContent defines the structure of the error content.
+ */
+export type CustomErrorContent = {
+ message: string;
+ context?: { [key: string]: any };
+};
+
+/**
+ * CustomError is an abstract base class for custom errors.
+ * It extends the built-in Error class and adds additional properties.
+ */
+export abstract class CustomError extends Error {
+ // Abstract properties that must be implemented by subclasses
+ abstract readonly statusCode: number;
+ abstract readonly logging: boolean;
+
+ /**
+ * Constructs a new CustomError instance.
+ * @param message - The error message.
+ */
+ constructor(message: string) {
+ super(message);
+ Object.setPrototypeOf(this, CustomError.prototype);
+ }
+}
diff --git a/web/src/core/errors/UnautherizedError.ts b/web/src/core/errors/UnautherizedError.ts
new file mode 100644
index 00000000..e0316e82
--- /dev/null
+++ b/web/src/core/errors/UnautherizedError.ts
@@ -0,0 +1,56 @@
+import { CustomError } from "./CustomError";
+
+/**
+ * UnauthorizedError is a custom error class that extends CustomError.
+ * It represents an error when a user is not authorized to perform an action.
+ */
+export default class UnauthorizedError extends CustomError {
+ // HTTP status code for unauthorized error
+ private static readonly _statusCode = 401;
+ private readonly _code: number;
+ private readonly _logging: boolean;
+ private readonly _context: { [key: string]: any };
+
+ /**
+ * Constructs a new UnauthorizedError instance.
+ * @param params - Optional parameters for the error.
+ * @param params.code - Custom error code (default is 401).
+ * @param params.message - Custom error message (default is "You are not authorized").
+ * @param params.logging - Flag to indicate if the error should be logged (default is false).
+ * @param params.context - Additional context for the error.
+ */
+ constructor(params?: { code?: number; message?: string; logging?: boolean; context?: { [key: string]: any } }) {
+ const { code, message, logging } = params || {};
+
+ super(message || "You are not authorized");
+ this._code = code || UnauthorizedError._statusCode;
+ this._logging = logging || false;
+ this._context = params?.context || {};
+
+ Object.setPrototypeOf(this, UnauthorizedError.prototype);
+ }
+
+ /**
+ * Returns an array of error details.
+ * @returns An array containing the error message and context.
+ */
+ get errors() {
+ return [{ message: this.message, context: this._context }];
+ }
+
+ /**
+ * Returns the HTTP status code for the error.
+ * @returns The status code.
+ */
+ get statusCode() {
+ return this._code;
+ }
+
+ /**
+ * Indicates if the error should be logged.
+ * @returns True if the error should be logged, otherwise false.
+ */
+ get logging() {
+ return this._logging;
+ }
+}
diff --git a/web/src/core/router/login_route.tsx b/web/src/core/router/login_route.tsx
new file mode 100644
index 00000000..d75a3988
--- /dev/null
+++ b/web/src/core/router/login_route.tsx
@@ -0,0 +1,15 @@
+import { Navigate, Outlet } from "react-router-dom";
+import { useAuth } from "../context/auth_context";
+
+// Component to handle login route
+export const LoginRoute = () => {
+ const { user } = useAuth();
+
+ // If user is authenticated, redirect to home page
+ if (user) {
+ return ;
+ }
+
+ // Render the login page if user is not authenticated
+ return ;
+};
diff --git a/web/src/core/router/protected_route.tsx b/web/src/core/router/protected_route.tsx
new file mode 100644
index 00000000..8bb5c233
--- /dev/null
+++ b/web/src/core/router/protected_route.tsx
@@ -0,0 +1,26 @@
+import { Navigate } from "react-router-dom";
+import { useAuth } from "../context/auth_context";
+import { UserRole } from "../constants/roles";
+import { AdminHomePage } from "../../presentation/admin/panel/admin_home_page";
+import { SuperAdminHomePage } from "../../presentation/superadmin/panel/super_admin_home_page";
+
+// Component to handle protected routes based on user role
+export const ProtectedRoute = () => {
+ const { user, logout } = useAuth();
+
+ // If no user is authenticated, redirect to login page
+ if (!user) {
+ return ;
+ } else {
+ // Redirect based on user role
+ if (user.role === UserRole.ADMIN) {
+ return ;
+ } else if (user.role === UserRole.SUPERADMIN) {
+ return ;
+ } else {
+ // Logout and redirect to login if user role is not recognized
+ logout();
+ return ;
+ }
+ }
+};
diff --git a/web/src/core/router/router.tsx b/web/src/core/router/router.tsx
new file mode 100644
index 00000000..50a1eec7
--- /dev/null
+++ b/web/src/core/router/router.tsx
@@ -0,0 +1,30 @@
+import { createBrowserRouter } from "react-router-dom";
+import { ProtectedRoute } from "./protected_route";
+import { LoginPage } from "../../presentation/login/login_page";
+
+// Create the router configuration
+export const router = createBrowserRouter([
+ {
+ // Protected routes that require authentication
+ element: ,
+ children: [
+ {
+ // Default route for authenticated users
+ index: true,
+ path: "/",
+ element:
+ }
+ ]
+ },
+ {
+ // Public route for login page
+ element: ,
+ children: [
+ {
+ // Route for login page
+ path: "/login",
+ element:
+ }
+ ]
+ }
+]);
\ No newline at end of file
diff --git a/web/src/core/utils/Messages.ts b/web/src/core/utils/Messages.ts
new file mode 100644
index 00000000..5418bbc4
--- /dev/null
+++ b/web/src/core/utils/Messages.ts
@@ -0,0 +1,36 @@
+import axios, { AxiosError } from "axios";
+import { toast } from "react-toastify";
+
+/**
+ * Displays an error message using react-toastify based on the type of Axios error.
+ *
+ * @param {AxiosError} error - The error object returned by Axios.
+ */
+export const showErrorAxios = (error: AxiosError) => {
+ let message = "";
+
+ // Determine the error message based on the error code
+ switch(error.code){
+ case(axios.AxiosError.ERR_BAD_REQUEST):
+ message = "Acceso no autorizado"; // Unauthorized access
+ break;
+ case(axios.AxiosError.ERR_NETWORK):
+ message = "Conexión con el servidor fallida"; // Server connection failed
+ break;
+ default:
+ message = error.message; // Default to the error message provided by Axios
+ break;
+ }
+
+ // Display the error message using react-toastify
+ toast.error(message, {
+ position: "bottom-right", // Position the toast at the bottom-right corner
+ autoClose: 1500, // Automatically close the toast after 1.5 seconds
+ hideProgressBar: false, // Show the progress bar
+ closeOnClick: true, // Close the toast when clicked
+ pauseOnHover: false, // Do not pause the toast on hover
+ draggable: true, // Allow the toast to be draggable
+ progress: undefined, // Use the default progress bar behavior
+ theme: "colored" // Use the colored theme for the toast
+ });
+}
\ No newline at end of file
diff --git a/web/src/data/datasource/admin_datasource.ts b/web/src/data/datasource/admin_datasource.ts
new file mode 100644
index 00000000..0bf0b76c
--- /dev/null
+++ b/web/src/data/datasource/admin_datasource.ts
@@ -0,0 +1,55 @@
+import { Admin, AdminFormValues } from "./api/entities/admin_form_values";
+import { ResetPasswordValues } from "./api/entities/reset_password_values";
+
+/**
+ * Interface representing a data source for handling admin-related operations.
+ */
+export interface AdminDatasourceInf {
+ /**
+ * Registers a new admin.
+ * @param form - The admin data to register.
+ * @returns A promise that resolves when the registration is complete.
+ */
+ registerAdmin(form: AdminFormValues): Promise;
+
+ /**
+ * Retrieves admin information based on a token.
+ * @param token - The authentication token.
+ * @returns A promise that resolves to an Admin object.
+ */
+ getAdminInfo(token: string): Promise;
+
+ /**
+ * Changes the password for an admin.
+ * @param token - The authentication token.
+ * @param prevPassword - The previous password.
+ * @param newPassword - The new password.
+ * @returns A promise that resolves when the password change is complete.
+ */
+ changePassword(
+ token: string,
+ prevPassword: string,
+ newPassword: string
+ ): Promise;
+
+ /**
+ * Retrieves a list of admins by town.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Admin objects.
+ */
+ getAdminsByTown(idTown: number): Promise;
+
+ /**
+ * Generates a reset code for the given email.
+ * @param email - The email address to send the reset code to.
+ * @returns A promise that resolves when the reset code is generated.
+ */
+ generateResetCode(email: string): Promise;
+
+ /**
+ * Resets the password using the provided reset form values.
+ * @param form - The reset password form values.
+ * @returns A promise that resolves when the password reset is complete.
+ */
+ resetPassword(form: ResetPasswordValues): Promise;
+}
diff --git a/web/src/data/datasources/prod/admin_datasource.ts b/web/src/data/datasource/api/admin_datasource.ts
similarity index 58%
rename from web/src/data/datasources/prod/admin_datasource.ts
rename to web/src/data/datasource/api/admin_datasource.ts
index a89fa78c..2e4ac80d 100644
--- a/web/src/data/datasources/prod/admin_datasource.ts
+++ b/web/src/data/datasource/api/admin_datasource.ts
@@ -1,12 +1,9 @@
import axios from "axios";
-import { AdminDatasourceInf } from "../../../infraestructure/datasources/admin_datasource";
-import {
- Admin,
- AdminFormValues,
-} from "../../../infraestructure/entities/admin_form_values";
-import { APIUrl } from "../../../constants/api_url";
-import { AdminModel } from "../../models/prod/AdminModel";
-import { UserRole } from "../../../constants/roles";
+import { AdminDatasourceInf } from "../admin_datasource";
+import { Admin, AdminFormValues } from "./entities/admin_form_values";
+import { APIUrl } from "../../../core/constants/api_url";
+import { AdminModel } from "../../../domain/model/AdminModel";
+import { UserRole } from "../../../core/constants/roles";
import {
API_ROUTE_ADMIN,
API_ROUTE_ADMIN_CHANGE_PASSWORD,
@@ -14,10 +11,15 @@ import {
API_ROUTE_ADMIN_RESET_PASSWORD,
API_ROUTE_ADMIN_SIGNUP,
API_ROUTE_ADMIN_WHOAMI,
-} from "../../../constants/api_routes";
-import { ResetPasswordValues } from "../../../infraestructure/entities/reset_password_values";
+} from "../../../core/constants/api_routes";
+import { ResetPasswordValues } from "./entities/reset_password_values";
export class AdminDatasourceProd implements AdminDatasourceInf {
+ /**
+ * Registers a new admin using the provided form data.
+ * @param form - The admin data to be registered.
+ * @returns A promise that resolves when the admin is successfully registered.
+ */
async registerAdmin(form: AdminFormValues): Promise {
await axios.post(APIUrl + API_ROUTE_ADMIN_SIGNUP, {
email: form.email,
@@ -28,6 +30,11 @@ export class AdminDatasourceProd implements AdminDatasourceInf {
});
}
+ /**
+ * Retrieves admin information using the provided token.
+ * @param token - The token of the admin.
+ * @returns A promise that resolves to an Admin object.
+ */
async getAdminInfo(token: string): Promise {
const { data } = await axios.get(
APIUrl + API_ROUTE_ADMIN_WHOAMI,
@@ -50,6 +57,13 @@ export class AdminDatasourceProd implements AdminDatasourceInf {
return admin;
}
+ /**
+ * Changes the password of the admin.
+ * @param token - The token of the admin.
+ * @param prevPassword - The previous password.
+ * @param newPassword - The new password.
+ * @returns A promise that resolves when the password is successfully changed.
+ */
async changePassword(
token: string,
prevPassword: string,
@@ -69,6 +83,11 @@ export class AdminDatasourceProd implements AdminDatasourceInf {
);
}
+ /**
+ * Retrieves a list of admins by town ID.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Admin objects.
+ */
async getAdminsByTown(idTown: number): Promise {
const { data } = await axios.get(
APIUrl + API_ROUTE_ADMIN + `/${idTown}`
@@ -85,12 +104,22 @@ export class AdminDatasourceProd implements AdminDatasourceInf {
return admins;
}
+ /**
+ * Generates a reset code for the given email.
+ * @param email - The email of the admin.
+ * @returns A promise that resolves when the reset code is successfully generated.
+ */
async generateResetCode(email: string): Promise {
await axios.post(APIUrl + API_ROUTE_ADMIN_GENERATE_RESET_CODE, {
email: email,
});
}
+ /**
+ * Resets the password using the provided form data.
+ * @param form - The reset password form values.
+ * @returns A promise that resolves when the password is successfully reset.
+ */
async resetPassword(form: ResetPasswordValues): Promise {
await axios.post(APIUrl + API_ROUTE_ADMIN_RESET_PASSWORD, {
email: form.email,
diff --git a/web/src/data/datasource/api/category_datasource.ts b/web/src/data/datasource/api/category_datasource.ts
new file mode 100644
index 00000000..e364270d
--- /dev/null
+++ b/web/src/data/datasource/api/category_datasource.ts
@@ -0,0 +1,62 @@
+import axios from "axios";
+import { CategoryDatasourceInf } from "../category_datasource";
+import { Category, CategoryFormValues } from "./entities/category";
+import { APIUrl } from "../../../core/constants/api_url";
+import { CategoryModel } from "../../../domain/model/CategoryModel";
+
+export class CategoryDatasourceProd implements CategoryDatasourceInf {
+ /**
+ * Registers a new category using the provided form data.
+ * @param form - The category data to be registered.
+ * @returns A promise that resolves when the category is successfully registered.
+ */
+ async registerCategory(form: CategoryFormValues): Promise {
+ await axios.post(APIUrl + "/category", {
+ nameES: form.nameES,
+ nameEN: form.nameEN,
+ });
+ }
+
+ /**
+ * Retrieves a list of categories.
+ * @returns A promise that resolves to an array of Category objects.
+ */
+ async getCategories(): Promise {
+ const { data: dataES } = await axios.get(
+ APIUrl + "/category/",
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+ const { data: dataEN } = await axios.get(
+ APIUrl + "/category/",
+ {
+ params: {
+ lang: "EN",
+ },
+ }
+ );
+ const categories: Category[] = [];
+ for (let i = 0; i < dataES.length; i++) {
+ const category: Category = {
+ idCategory: dataES[i].idCategory,
+ nameES: dataES[i].name,
+ nameEN: dataEN[i].name,
+ };
+ categories.push(category);
+ }
+
+ return categories;
+ }
+
+ /**
+ * Deletes a category by its ID.
+ * @param category - The category to be deleted.
+ * @returns A promise that resolves when the category is successfully deleted.
+ */
+ async deleteCategory(category: Category): Promise {
+ await axios.delete(APIUrl + `/category/${category.idCategory}`);
+ }
+}
diff --git a/web/src/infraestructure/entities/admin_form_values.ts b/web/src/data/datasource/api/entities/admin_form_values.ts
similarity index 61%
rename from web/src/infraestructure/entities/admin_form_values.ts
rename to web/src/data/datasource/api/entities/admin_form_values.ts
index 69786190..f6c71772 100644
--- a/web/src/infraestructure/entities/admin_form_values.ts
+++ b/web/src/data/datasource/api/entities/admin_form_values.ts
@@ -1,5 +1,8 @@
-import { UserRole } from "../../constants/roles";
+import { UserRole } from "../../../../core/constants/roles";
+/**
+ * Interface representing the values of an admin form.
+ */
export interface AdminFormValues {
email: string;
name: string;
@@ -9,6 +12,9 @@ export interface AdminFormValues {
townAdmin: number;
}
+/**
+ * Interface representing an admin.
+ */
export interface Admin {
email: string;
name: string;
@@ -18,8 +24,11 @@ export interface Admin {
status?: string;
}
+/**
+ * Interface representing the values required to change an admin's password.
+ */
export interface AdminPasswordValues {
prevPassword: string;
newPassword: string;
newPasswordConfirm: string;
-}
\ No newline at end of file
+}
diff --git a/web/src/data/datasource/api/entities/category.ts b/web/src/data/datasource/api/entities/category.ts
new file mode 100644
index 00000000..3edd3dc1
--- /dev/null
+++ b/web/src/data/datasource/api/entities/category.ts
@@ -0,0 +1,16 @@
+/**
+ * Interface representing a category.
+ */
+export interface Category {
+ idCategory: number;
+ nameES: string;
+ nameEN: string;
+}
+
+/**
+ * Interface representing the values of a category form.
+ */
+export interface CategoryFormValues {
+ nameES: string;
+ nameEN: string;
+}
\ No newline at end of file
diff --git a/web/src/data/datasource/api/entities/image.ts b/web/src/data/datasource/api/entities/image.ts
new file mode 100644
index 00000000..960b6ecf
--- /dev/null
+++ b/web/src/data/datasource/api/entities/image.ts
@@ -0,0 +1,7 @@
+/**
+ * Interface representing an image.
+ */
+export interface Image {
+ file: File;
+ preview: string;
+}
\ No newline at end of file
diff --git a/web/src/data/datasource/api/entities/login_form_values.ts b/web/src/data/datasource/api/entities/login_form_values.ts
new file mode 100644
index 00000000..f7c8007d
--- /dev/null
+++ b/web/src/data/datasource/api/entities/login_form_values.ts
@@ -0,0 +1,7 @@
+/**
+ * Interface representing the values of a login form.
+ */
+export interface LoginFormValues {
+ email: string;
+ password: string;
+}
\ No newline at end of file
diff --git a/web/src/infraestructure/entities/place.ts b/web/src/data/datasource/api/entities/place.ts
similarity index 69%
rename from web/src/infraestructure/entities/place.ts
rename to web/src/data/datasource/api/entities/place.ts
index ca43cd08..2abb1e14 100644
--- a/web/src/infraestructure/entities/place.ts
+++ b/web/src/data/datasource/api/entities/place.ts
@@ -1,6 +1,9 @@
-export interface Place{
+/**
+ * Interface representing a place.
+ */
+export interface Place {
idTown: number;
- idPlace? : number;
+ idPlace?: number;
name: string;
categoriesId: number[];
descriptions?: string[];
@@ -15,6 +18,9 @@ export interface Place{
address: string;
}
+/**
+ * Enum representing available days.
+ */
export enum AvailableDays {
WEEKEND = 'weekend',
ALL_DAYS = 'all_days',
@@ -22,19 +28,28 @@ export enum AvailableDays {
CUSTOM = 'custom'
}
-export interface availableDaysOption{
+/**
+ * Interface representing an available days option.
+ */
+export interface availableDaysOption {
option: AvailableDays;
name: string;
}
-export const availableDaysList= [
+/**
+ * List of available days options.
+ */
+export const availableDaysList = [
{ option: AvailableDays.WEEKEND, name: 'Fines de semana' },
{ option: AvailableDays.ALL_DAYS, name: 'Todos los dias' },
{ option: AvailableDays.WEEKDAYS, name: 'Lunes a Viernes' },
{ option: AvailableDays.CUSTOM, name: 'Personalizado' }
];
-export const EmptyPlace : Place = {
+/**
+ * Constant representing an empty place.
+ */
+export const EmptyPlace: Place = {
idTown: -1,
idPlace: -1,
name: "",
@@ -46,4 +61,4 @@ export const EmptyPlace : Place = {
closeAt: 0,
available: AvailableDays.WEEKEND,
address: ''
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/web/src/infraestructure/entities/poi.ts b/web/src/data/datasource/api/entities/poi.ts
similarity index 76%
rename from web/src/infraestructure/entities/poi.ts
rename to web/src/data/datasource/api/entities/poi.ts
index cdbfcb7e..ad5936a3 100644
--- a/web/src/infraestructure/entities/poi.ts
+++ b/web/src/data/datasource/api/entities/poi.ts
@@ -1,3 +1,6 @@
+/**
+ * Interface representing a point of interest.
+ */
export interface PointOfInterest {
idPoint?: number;
idPlace: number;
@@ -9,6 +12,9 @@ export interface PointOfInterest {
directionsES: string;
}
+/**
+ * Constant representing an empty point of interest.
+ */
export const EmptyPointOfInterest: PointOfInterest = {
idPoint: 0,
idPlace: 0,
@@ -18,4 +24,4 @@ export const EmptyPointOfInterest: PointOfInterest = {
contentES: '',
directionsEN: '',
directionsES: ''
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/web/src/infraestructure/entities/reset_password_values.ts b/web/src/data/datasource/api/entities/reset_password_values.ts
similarity index 62%
rename from web/src/infraestructure/entities/reset_password_values.ts
rename to web/src/data/datasource/api/entities/reset_password_values.ts
index a353e140..e7da0355 100644
--- a/web/src/infraestructure/entities/reset_password_values.ts
+++ b/web/src/data/datasource/api/entities/reset_password_values.ts
@@ -1,3 +1,6 @@
+/**
+ * Interface representing the values required to reset a password.
+ */
export interface ResetPasswordValues {
email: string;
code: number;
diff --git a/web/src/data/datasource/api/entities/state.ts b/web/src/data/datasource/api/entities/state.ts
new file mode 100644
index 00000000..2451f5fe
--- /dev/null
+++ b/web/src/data/datasource/api/entities/state.ts
@@ -0,0 +1,8 @@
+/**
+ * Interface representing a state.
+ */
+export interface State {
+ stateId: number;
+ name: string;
+ imageURL: string;
+}
\ No newline at end of file
diff --git a/web/src/data/datasource/api/entities/town.ts b/web/src/data/datasource/api/entities/town.ts
new file mode 100644
index 00000000..c3b08f74
--- /dev/null
+++ b/web/src/data/datasource/api/entities/town.ts
@@ -0,0 +1,12 @@
+/**
+ * Interface representing a town.
+ */
+export interface Town {
+ idTown: number;
+ name: string;
+ descriptionES?: string;
+ descriptionEN?: string;
+ idState: number;
+ state: string;
+ imageURL?: string | File;
+}
\ No newline at end of file
diff --git a/web/src/data/datasource/api/entities/user.ts b/web/src/data/datasource/api/entities/user.ts
new file mode 100644
index 00000000..a824fa72
--- /dev/null
+++ b/web/src/data/datasource/api/entities/user.ts
@@ -0,0 +1,223 @@
+import { UserRole } from "../../../../core/constants/roles";
+
+/**
+ * Interface representing a user entity.
+ */
+export interface UserEntity {
+ name: string;
+ lastName?: string;
+ email: string;
+ role: UserRole;
+}
+
+/**
+ * Interface representing a logged-in user.
+ */
+export interface LoggedInUser {
+ user: UserEntity;
+ token: string;
+}
+
+/**
+ * Interface representing user information.
+ */
+export interface UserInfo {
+ name?: string;
+ lastName?: string;
+ email: string;
+}
+
+/**
+ * Class for converting JSON strings to UserEntity objects and vice versa.
+ */
+export class Convert {
+ public static toUser(json: string): UserEntity {
+ return cast(JSON.parse(json), r("User"));
+ }
+
+ public static userToJson(value: UserEntity): string {
+ return JSON.stringify(uncast(value, r("User")), null, 2);
+ }
+}
+
+function invalidValue(typ: any, val: any, key: any, parent: any = ""): never {
+ const prettyTyp = prettyTypeName(typ);
+ const parentText = parent ? ` on ${parent}` : "";
+ const keyText = key ? ` for key "${key}"` : "";
+ throw Error(
+ `Invalid value${keyText}${parentText}. Expected ${prettyTyp} but got ${JSON.stringify(
+ val
+ )}`
+ );
+}
+
+function prettyTypeName(typ: any): string {
+ if (Array.isArray(typ)) {
+ if (typ.length === 2 && typ[0] === undefined) {
+ return `an optional ${prettyTypeName(typ[1])}`;
+ } else {
+ return `one of [${typ
+ .map((a) => {
+ return prettyTypeName(a);
+ })
+ .join(", ")}]`;
+ }
+ } else if (typeof typ === "object" && typ.literal !== undefined) {
+ return typ.literal;
+ } else {
+ return typeof typ;
+ }
+}
+
+function jsonToJSProps(typ: any): any {
+ if (typ.jsonToJS === undefined) {
+ const map: any = {};
+ typ.props.forEach((p: any) => (map[p.json] = { key: p.js, typ: p.typ }));
+ typ.jsonToJS = map;
+ }
+ return typ.jsonToJS;
+}
+
+function jsToJSONProps(typ: any): any {
+ if (typ.jsToJSON === undefined) {
+ const map: any = {};
+ typ.props.forEach((p: any) => (map[p.js] = { key: p.json, typ: p.typ }));
+ typ.jsToJSON = map;
+ }
+ return typ.jsToJSON;
+}
+
+function transform(
+ val: any,
+ typ: any,
+ getProps: any,
+ key: any = "",
+ parent: any = ""
+): any {
+ function transformPrimitive(typ: string, val: any): any {
+ if (typeof typ === typeof val) return val;
+ return invalidValue(typ, val, key, parent);
+ }
+
+ function transformUnion(typs: any[], val: any): any {
+ // val must validate against one typ in typs
+ const l = typs.length;
+ for (let i = 0; i < l; i++) {
+ const typ = typs[i];
+ try {
+ return transform(val, typ, getProps);
+ } catch (_) {}
+ }
+ return invalidValue(typs, val, key, parent);
+ }
+
+ function transformEnum(cases: string[], val: any): any {
+ if (cases.indexOf(val) !== -1) return val;
+ return invalidValue(
+ cases.map((a) => {
+ return l(a);
+ }),
+ val,
+ key,
+ parent
+ );
+ }
+
+ function transformArray(typ: any, val: any): any {
+ // val must be an array with no invalid elements
+ if (!Array.isArray(val)) return invalidValue(l("array"), val, key, parent);
+ return val.map((el) => transform(el, typ, getProps));
+ }
+
+ function transformDate(val: any): any {
+ if (val === null) {
+ return null;
+ }
+ const d = new Date(val);
+ if (isNaN(d.valueOf())) {
+ return invalidValue(l("Date"), val, key, parent);
+ }
+ return d;
+ }
+
+ function transformObject(
+ props: { [k: string]: any },
+ additional: any,
+ val: any
+ ): any {
+ if (val === null || typeof val !== "object" || Array.isArray(val)) {
+ return invalidValue(l(ref || "object"), val, key, parent);
+ }
+ const result: any = {};
+ Object.getOwnPropertyNames(props).forEach((key) => {
+ const prop = props[key];
+ const v = Object.prototype.hasOwnProperty.call(val, key)
+ ? val[key]
+ : undefined;
+ result[prop.key] = transform(v, prop.typ, getProps, key, ref);
+ });
+ Object.getOwnPropertyNames(val).forEach((key) => {
+ if (!Object.prototype.hasOwnProperty.call(props, key)) {
+ result[key] = transform(val[key], additional, getProps, key, ref);
+ }
+ });
+ return result;
+ }
+
+ if (typ === "any") return val;
+ if (typ === null) {
+ if (val === null) return val;
+ return invalidValue(typ, val, key, parent);
+ }
+ if (typ === false) return invalidValue(typ, val, key, parent);
+ let ref: any = undefined;
+ while (typeof typ === "object" && typ.ref !== undefined) {
+ ref = typ.ref;
+ typ = typeMap[typ.ref];
+ }
+ if (Array.isArray(typ)) return transformEnum(typ, val);
+ if (typeof typ === "object") {
+ return typ.hasOwnProperty("unionMembers")
+ ? transformUnion(typ.unionMembers, val)
+ : typ.hasOwnProperty("arrayItems")
+ ? transformArray(typ.arrayItems, val)
+ : typ.hasOwnProperty("props")
+ ? transformObject(getProps(typ), typ.additional, val)
+ : invalidValue(typ, val, key, parent);
+ }
+ // Numbers can be parsed by Date but shouldn't be.
+ if (typ === Date && typeof val !== "number") return transformDate(val);
+ return transformPrimitive(typ, val);
+}
+
+function cast(val: any, typ: any): T {
+ return transform(val, typ, jsonToJSProps);
+}
+
+function uncast(val: T, typ: any): any {
+ return transform(val, typ, jsToJSONProps);
+}
+
+function l(typ: any) {
+ return { literal: typ };
+}
+
+
+function o(props: any[], additional: any) {
+ return { props, additional };
+}
+
+function r(name: string) {
+ return { ref: name };
+}
+
+const typeMap: any = {
+ User: o(
+ [
+ { json: "email", js: "email", typ: "" },
+ { json: "name", js: "name", typ: "" },
+ { json: "role", js: "role", typ: "" },
+ ],
+ false
+ ),
+};
diff --git a/web/src/data/datasource/api/login_datasource.ts b/web/src/data/datasource/api/login_datasource.ts
new file mode 100644
index 00000000..9040460b
--- /dev/null
+++ b/web/src/data/datasource/api/login_datasource.ts
@@ -0,0 +1,41 @@
+import { LoginDatasource } from "../login_datasource";
+import { LoginFormValues } from "./entities/login_form_values";
+import axios from "axios";
+import { LoggedInUser } from "./entities/user";
+import { LoggedInUserModel } from "../../../domain/model/LoggedInUserModel";
+import { UserRole } from "../../../core/constants/roles";
+import { APIUrl } from "../../../core/constants/api_url";
+
+/**
+ * Implementation of the LoginDatasource interface.
+ */
+export class LoginDatasourceImpl implements LoginDatasource {
+ /**
+ * Retrieves a token for the given login form values.
+ * @param form - The login form values.
+ * @returns A promise that resolves to a logged-in user.
+ */
+ async getToken(form: LoginFormValues): Promise {
+ const { email, password } = form;
+ const { data } = await axios.post(
+ APIUrl + "/admin/signin",
+ {
+ email: email,
+ password: password,
+ }
+ );
+ const user: LoggedInUser = {
+ user: {
+ email: data.email,
+ name: data.name,
+ role:
+ data.role === UserRole.SUPERADMIN
+ ? UserRole.SUPERADMIN
+ : UserRole.ADMIN,
+ },
+ token: data.token,
+ };
+
+ return user;
+ }
+}
diff --git a/web/src/data/datasource/api/place_datasource.ts b/web/src/data/datasource/api/place_datasource.ts
new file mode 100644
index 00000000..88145c21
--- /dev/null
+++ b/web/src/data/datasource/api/place_datasource.ts
@@ -0,0 +1,128 @@
+import axios from "axios";
+import { APIUrl } from "../../../core/constants/api_url";
+import { PlaceDatasourceInf } from "../place_datasource";
+import { AvailableDays, Place } from "./entities/place";
+import {
+ PlaceModel,
+ placeModelToEntity,
+} from "../../../domain/model/PlaceModel";
+
+export class PlaceDatasourceProd implements PlaceDatasourceInf {
+ /**
+ * Registers a new place using the provided form data.
+ * @param form - The place data to be registered.
+ * @returns A promise that resolves when the place is successfully registered.
+ */
+ async registerPlace(form: Place): Promise {
+ const formToSend = new FormData();
+ formToSend.append("available", form.available);
+ formToSend.append("idTown", String(form.idTown));
+ formToSend.append("name", form.name);
+ formToSend.append("categoriesId", form.categoriesId.join(","));
+ formToSend.append("descriptionES", form.descriptions?.[0] ?? "");
+ formToSend.append("descriptionEN", form.descriptions?.[1] ?? "");
+ formToSend.append("image", form.imagesList?.[0] ?? "");
+ formToSend.append("latitude", String(form.latitude));
+ 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));
+ formToSend.append("endDate", String(form.endDate));
+ }
+
+ const headers = {
+ "Content-Type": "multipart/form-data",
+ };
+
+ await axios.post(APIUrl + "/place", formToSend, { headers });
+ }
+
+ /**
+ * Retrieves a list of places by town ID.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Place objects.
+ */
+ async getPlacesByTown(idTown: number): Promise {
+ const { data } = await axios.get(
+ APIUrl + `/place/town/${idTown}/place`,
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+
+ const places = data.map((dataES) => {
+ return placeModelToEntity(dataES);
+ });
+
+ return places;
+ }
+
+ /**
+ * Retrieves a place by its ID.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to a Place object.
+ */
+ async getPlaceById(idPlace: number): Promise {
+ const { data: dataES } = await axios.get(
+ APIUrl + `/place/${idPlace}`,
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+
+ const { data: dataEN } = await axios.get(
+ APIUrl + `/place/${idPlace}`,
+ {
+ params: {
+ lang: "EN",
+ },
+ }
+ );
+
+ const place: Place = placeModelToEntity(dataES);
+ place.descriptions?.push(dataEN.description);
+
+ return place;
+ }
+
+ /**
+ * Updates an existing place using the provided form data.
+ * @param place - The place data to be updated.
+ * @returns A promise that resolves when the place is successfully updated.
+ */
+ async updatePlace(place: Place): Promise {
+ const formToSend = new FormData();
+ formToSend.append("available", place.available);
+ formToSend.append("idTown", String(place.idTown));
+ formToSend.append("name", place.name);
+ formToSend.append("categoriesId", place.categoriesId.join(","));
+ formToSend.append("descriptionES", place.descriptions?.[0] ?? "");
+ formToSend.append("descriptionEN", place.descriptions?.[1] ?? "");
+ formToSend.append("image", place.imagesList?.[0] ?? "");
+ formToSend.append("latitude", String(place.latitude));
+ 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));
+ formToSend.append("endDate", String(place.endDate));
+ }
+
+ const headers = {
+ "Content-Type": "multipart/form-data",
+ };
+
+ await axios.patch(APIUrl + `/place/${place.idPlace}`, formToSend, {
+ headers,
+ });
+ }
+}
diff --git a/web/src/data/datasource/api/poi_datasource.ts b/web/src/data/datasource/api/poi_datasource.ts
new file mode 100644
index 00000000..206f5c92
--- /dev/null
+++ b/web/src/data/datasource/api/poi_datasource.ts
@@ -0,0 +1,106 @@
+import axios from "axios";
+import { Buffer } from "buffer";
+import { PoiDatasourceInf } from "../poi_datasource";
+import { PointOfInterest } from "./entities/poi";
+import { APIUrl } from "../../../core/constants/api_url";
+import {
+ API_ROUTE_PLACE,
+ API_ROUTE_POINT,
+} from "../../../core/constants/api_routes";
+import { POIModel, POIModelToEntity } from "../../../domain/model/POIModel";
+
+export class POIDatasourceProd implements PoiDatasourceInf {
+ /**
+ * Registers a new point of interest using the provided form data.
+ * @param form - The point of interest data to be registered.
+ * @returns A promise that resolves when the point is successfully registered.
+ */
+ async registerPoint(form: PointOfInterest): Promise {
+ const formToSend = new FormData();
+ formToSend.append("idPlace", String(form.idPlace));
+ formToSend.append("name", form.name);
+ formToSend.append("image", form.image);
+ formToSend.append("contentEN", form.contentEN);
+ formToSend.append("contentES", form.contentES);
+ formToSend.append("directionsEN", form.directionsEN);
+ formToSend.append("directionsES", form.directionsES);
+
+ const headers = {
+ "Content-Type": "multipart/form-data",
+ };
+
+ await axios.post(APIUrl + API_ROUTE_POINT, formToSend, { headers });
+ }
+
+ /**
+ * Retrieves a list of points of interest by place ID.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to an array of PointOfInterest objects.
+ */
+ async getPOIsByPlace(idPlace: number): Promise {
+ const { data: dataES } = await axios.get(
+ APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT,
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+
+ const poiList = dataES.map((dataESModel) => {
+ return POIModelToEntity(dataESModel);
+ });
+
+ return poiList;
+ }
+
+ /**
+ * Retrieves a point of interest by its ID.
+ * @param idPoint - The ID of the point of interest.
+ * @returns A promise that resolves to a PointOfInterest object.
+ */
+ async getPOIById(idPoint: number): Promise {
+ const { data: dataES } = await axios.get(
+ APIUrl + API_ROUTE_POINT + `/${idPoint}`,
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+
+ const { data: dataEN } = await axios.get(
+ APIUrl + API_ROUTE_POINT + `/${idPoint}`,
+ {
+ params: {
+ lang: "EN",
+ },
+ }
+ );
+
+ const poi: PointOfInterest = POIModelToEntity(dataES);
+ poi.contentEN = dataEN.content;
+ poi.directionsEN = dataEN.directions;
+
+ return poi;
+ }
+
+ /**
+ * Generates a PDF for the specified points of interest.
+ * @param idPlace - The ID of the place.
+ * @param pointsId - An array of point IDs to include in the PDF.
+ * @returns A promise that resolves to a base64-encoded string of the PDF.
+ */
+ async getPDFByPoints(idPlace: number, pointsId: number[]): Promise {
+ const { data } = await axios.get(
+ APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT + "/generate",
+ {
+ params: {
+ pointsId: pointsId.join(","),
+ },
+ responseType: "arraybuffer",
+ }
+ );
+ return Buffer.from(data, "binary").toString("base64");
+ }
+}
diff --git a/web/src/data/datasource/api/town_datasource.ts b/web/src/data/datasource/api/town_datasource.ts
new file mode 100644
index 00000000..b99259e9
--- /dev/null
+++ b/web/src/data/datasource/api/town_datasource.ts
@@ -0,0 +1,115 @@
+import axios from "axios";
+import { APIUrl } from "../../../core/constants/api_url";
+import { TownDatasourceInf } from "../town_datasource";
+import { State } from "./entities/state";
+import { Town } from "./entities/town";
+import { StateModel } from "../../../domain/model/StateModel";
+import { TownModelTrad, TownModel } from "../../../domain/model/TownModel";
+import { API_ROUTE_STATE } from "../../../core/constants/api_routes";
+
+export class TownDatasourceProd implements TownDatasourceInf {
+ /**
+ * Retrieves a list of states from the API.
+ * @returns A promise that resolves to an array of State objects.
+ */
+ async getStates(): Promise {
+ const { data } = await axios.get(APIUrl + API_ROUTE_STATE);
+ const states = data.map((value) => {
+ const state: State = {
+ stateId: value.stateId,
+ name: value.name,
+ imageURL: value.imageURL,
+ };
+ return state;
+ });
+
+ return states;
+ }
+
+ /**
+ * Registers a new town using the provided form data.
+ * @param form - The town data to be registered.
+ * @returns A promise that resolves when the town is successfully registered.
+ */
+ async registerTown(form: Town): Promise {
+ const formToSend = new FormData();
+ formToSend.append("name", form.name);
+ formToSend.append("descriptionES", form.descriptionES || "");
+ formToSend.append("descriptionEN", form.descriptionEN || "");
+ formToSend.append("state", String(form.idState));
+ formToSend.append("image", form.imageURL || "");
+
+ const headers = {
+ "Content-Type": "multipart/form-data",
+ };
+
+ await axios.post(APIUrl + "/town", formToSend, { headers });
+ }
+
+ /**
+ * Retrieves a list of towns by state ID and state name.
+ * @param idState - The ID of the state.
+ * @param stateName - The name of the state.
+ * @returns A promise that resolves to an array of Town objects.
+ */
+ async getTownsByState(idState: number, stateName: string): Promise {
+ const { data } = await axios.get(
+ APIUrl + `/state/${idState}/town`,
+ {
+ params: {
+ lang: "ES",
+ },
+ }
+ );
+ const towns = data.map((value) => {
+ const town: Town = {
+ idTown: value.townId,
+ name: value.name,
+ idState: value.stateId,
+ state: stateName,
+ };
+ return town;
+ });
+
+ return towns;
+ }
+
+ /**
+ * Retrieves a town by its ID.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to a Town object.
+ */
+ async getTown(idTown: number): Promise {
+ const { data } = await axios.get(APIUrl + `/town/${idTown}`);
+ const town: Town = {
+ idTown: data.townId,
+ name: data.name,
+ idState: data.stateId,
+ descriptionES: data.descriptionES,
+ descriptionEN: data.descriptionEN,
+ state: "",
+ imageURL: data.imageName,
+ };
+ return town;
+ }
+
+ /**
+ * Updates an existing town using the provided form data.
+ * @param form - The town data to be updated.
+ * @returns A promise that resolves when the town is successfully updated.
+ */
+ async updateTown(form: Town): Promise {
+ const formToSend = new FormData();
+ formToSend.append("name", form.name);
+ formToSend.append("descriptionES", form.descriptionES || "");
+ formToSend.append("descriptionEN", form.descriptionEN || "");
+ formToSend.append("image", form.imageURL || "");
+ formToSend.append("state", String(form.idState));
+
+ const headers = {
+ "Content-Type": "multipart/form-data",
+ };
+
+ await axios.patch(APIUrl + `/town/${form.idTown}`, formToSend, { headers });
+ }
+}
diff --git a/web/src/data/datasource/category_datasource.ts b/web/src/data/datasource/category_datasource.ts
new file mode 100644
index 00000000..1f207247
--- /dev/null
+++ b/web/src/data/datasource/category_datasource.ts
@@ -0,0 +1,26 @@
+import { Category, CategoryFormValues } from "./api/entities/category";
+
+/**
+ * Interface representing a data source for handling category-related operations.
+ */
+export interface CategoryDatasourceInf {
+ /**
+ * Registers a new category.
+ * @param form - The category data to register.
+ * @returns A promise that resolves when the registration is complete.
+ */
+ registerCategory(form: CategoryFormValues): Promise;
+
+ /**
+ * Retrieves a list of categories.
+ * @returns A promise that resolves to an array of Category objects.
+ */
+ getCategories(): Promise;
+
+ /**
+ * Deletes an existing category.
+ * @param category - The category to delete.
+ * @returns A promise that resolves when the deletion is complete.
+ */
+ deleteCategory(category: Category): Promise;
+}
diff --git a/web/src/data/datasource/login_datasource.ts b/web/src/data/datasource/login_datasource.ts
new file mode 100644
index 00000000..69a04888
--- /dev/null
+++ b/web/src/data/datasource/login_datasource.ts
@@ -0,0 +1,14 @@
+import { LoginFormValues } from "./api/entities/login_form_values";
+import { LoggedInUser } from "./api/entities/user";
+
+/**
+ * Interface representing a data source for handling login operations.
+ */
+export interface LoginDatasource {
+ /**
+ * Retrieves a token for the given login form values.
+ * @param form - The login form values.
+ * @returns A promise that resolves to a LoggedInUser object containing the token.
+ */
+ getToken(form: LoginFormValues): Promise;
+}
diff --git a/web/src/data/datasource/place_datasource.ts b/web/src/data/datasource/place_datasource.ts
new file mode 100644
index 00000000..3b787935
--- /dev/null
+++ b/web/src/data/datasource/place_datasource.ts
@@ -0,0 +1,34 @@
+import { Place } from "./api/entities/place";
+
+/**
+ * Interface representing a data source for handling place-related operations.
+ */
+export interface PlaceDatasourceInf {
+ /**
+ * Registers a new place.
+ * @param form - The place data to register.
+ * @returns A promise that resolves when the registration is complete.
+ */
+ registerPlace(form: Place): Promise;
+
+ /**
+ * Retrieves a list of places by town.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Place objects.
+ */
+ getPlacesByTown(idTown: number): Promise;
+
+ /**
+ * Retrieves a place by its ID.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to a Place object.
+ */
+ getPlaceById(idPlace: number): Promise;
+
+ /**
+ * Updates an existing place.
+ * @param place - The updated place data.
+ * @returns A promise that resolves when the update is complete.
+ */
+ updatePlace(place: Place): Promise;
+}
diff --git a/web/src/data/datasource/poi_datasource.ts b/web/src/data/datasource/poi_datasource.ts
new file mode 100644
index 00000000..b03b50dd
--- /dev/null
+++ b/web/src/data/datasource/poi_datasource.ts
@@ -0,0 +1,35 @@
+import { PointOfInterest } from "./api/entities/poi";
+
+/**
+ * Interface representing a data source for handling points of interest (POI) operations.
+ */
+export interface PoiDatasourceInf {
+ /**
+ * Registers a new point of interest.
+ * @param form - The POI data to register.
+ * @returns A promise that resolves when the registration is complete.
+ */
+ registerPoint(form: PointOfInterest): Promise;
+
+ /**
+ * Retrieves a list of POIs by place.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to an array of PointOfInterest objects.
+ */
+ getPOIsByPlace(idPlace: number): Promise;
+
+ /**
+ * Retrieves a POI by its ID.
+ * @param idPoint - The ID of the POI.
+ * @returns A promise that resolves to a PointOfInterest object.
+ */
+ getPOIById(idPoint: number): Promise;
+
+ /**
+ * Retrieves a PDF document containing information about specified POIs.
+ * @param idPlace - The ID of the place.
+ * @param pointsId - An array of POI IDs.
+ * @returns A promise that resolves to a string representing the PDF document.
+ */
+ getPDFByPoints(idPlace: number, pointsId: number[]): Promise;
+}
diff --git a/web/src/data/datasource/town_datasource.ts b/web/src/data/datasource/town_datasource.ts
new file mode 100644
index 00000000..87fa51c5
--- /dev/null
+++ b/web/src/data/datasource/town_datasource.ts
@@ -0,0 +1,41 @@
+import { State } from "./api/entities/state";
+import { Town } from "./api/entities/town";
+
+/**
+ * Interface representing a data source for handling town-related operations.
+ */
+export interface TownDatasourceInf {
+ /**
+ * Retrieves a list of states.
+ * @returns A promise that resolves to an array of State objects.
+ */
+ getStates(): Promise;
+
+ /**
+ * Registers a new town.
+ * @param form - The town data to register.
+ */
+ registerTown(form: Town): void;
+
+ /**
+ * Retrieves a list of towns by state.
+ * @param idState - The ID of the state.
+ * @param stateName - The name of the state.
+ * @returns A promise that resolves to an array of Town objects.
+ */
+ getTownsByState(idState: number, stateName: string): Promise;
+
+ /**
+ * Retrieves a town by its ID.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to a Town object.
+ */
+ getTown(idTown: number): Promise;
+
+ /**
+ * Updates an existing town.
+ * @param form - The updated town data.
+ * @returns A promise that resolves when the update is complete.
+ */
+ updateTown(form: Town): Promise;
+}
diff --git a/web/src/data/datasources/prod/category_datasource.ts b/web/src/data/datasources/prod/category_datasource.ts
deleted file mode 100644
index 41271b55..00000000
--- a/web/src/data/datasources/prod/category_datasource.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import axios from "axios";
-import { CategoryDatasourceInf } from "../../../infraestructure/datasources/category_datasource";
-import { Category, CategoryFormValues } from "../../../infraestructure/entities/category";
-import { CategoryModel } from "../../models/prod/CategoryModel";
-import { APIUrl } from "../../../constants/api_url";
-
-export class CategoryDatasourceProd implements CategoryDatasourceInf{
- async registerCategory(form: CategoryFormValues): Promise {
- await axios.post(
- APIUrl + "/category",
- {
- nameES: form.nameES,
- nameEN: form.nameEN
- }
- );
- }
-
- async getCategories(): Promise {
- const {data: dataES} = await axios.get(APIUrl+'/category/', {
- params: {
- lang: 'ES'
- }
- });
- const {data: dataEN} = await axios.get(APIUrl+'/category/', {
- params: {
- lang: 'EN'
- }
- });
- const categories : Category[] = [];
- for(let i=0; i {
- await axios.delete(APIUrl + `/category/${category.idCategory}`)
- }
-}
\ No newline at end of file
diff --git a/web/src/data/datasources/prod/login_datasource.ts b/web/src/data/datasources/prod/login_datasource.ts
deleted file mode 100644
index c2d7f535..00000000
--- a/web/src/data/datasources/prod/login_datasource.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import { LoginDatasourceInf } from "../../../infraestructure/datasources/login_datasource";
-import { LoginFormValues } from "../../../infraestructure/entities/login_form_values";
-import axios from "axios";
-import { LoggedInUser } from "../../../infraestructure/entities/user";
-import { LoggedInUserModel } from "../../models/prod/LoggedInUserModel";
-import { UserRole } from "../../../constants/roles";
-import { APIUrl } from "../../../constants/api_url";
-
-export class LoginDatasourceProd implements LoginDatasourceInf{
- async getToken(form: LoginFormValues): Promise {
- const {email, password} = form;
- const {data} = await axios.post(
- APIUrl + "/admin/signin",
- {
- email: email,
- password: password,
- }
- );
- const user: LoggedInUser = {
- user: {
- email: data.email,
- name: data.name,
- role: data.role === UserRole.SUPERADMIN ? UserRole.SUPERADMIN : UserRole.ADMIN,
- },
- token: data.token,
- };
-
- return user;
- }
-}
\ 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
deleted file mode 100644
index 299676c5..00000000
--- a/web/src/data/datasources/prod/place_datasource.ts
+++ /dev/null
@@ -1,94 +0,0 @@
-import axios from "axios";
-import { APIUrl } from "../../../constants/api_url";
-import { PlaceDatasourceInf } from "../../../infraestructure/datasources/place_datasource";
-import { AvailableDays, Place } from "../../../infraestructure/entities/place";
-import { PlaceModel, placeModelToEntity } from "../../models/prod/PlaceModel";
-
-export class PlaceDatasourceProd implements PlaceDatasourceInf{
- async registerPlace(form: Place): Promise {
- const formToSend = new FormData();
- formToSend.append('available', form.available);
- formToSend.append('idTown', String(form.idTown));
- formToSend.append('name', form.name);
- formToSend.append('categoriesId', form.categoriesId.join(','));
- formToSend.append('descriptionES', form.descriptions?.[0] ?? '');
- formToSend.append('descriptionEN', form.descriptions?.[1] ?? '');
- formToSend.append('image', form.imagesList?.[0] ?? '');
- formToSend.append('latitude', String(form.latitude));
- 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));
- formToSend.append('endDate', String(form.endDate));
- }
-
- const headers = {
- 'Content-Type': 'multipart/form-data'
- };
-
- await axios.post(APIUrl + '/place', formToSend,{headers});
- }
-
- async getPlacesByTown(idTown: number): Promise {
- const {data} = await axios.get(APIUrl+`/place/town/${idTown}/place`, {
- params: {
- lang: 'ES'
- }
- });
-
- const places = data.map((dataES) => {
- return placeModelToEntity(dataES);
- })
-
- return places;
- }
-
- async getPlaceById(idPlace: number): Promise {
- const {data: dataES} = await axios.get(APIUrl+`/place/${idPlace}`, {
- params: {
- lang: 'ES'
- }
- });
-
- const {data: dataEN} = await axios.get(APIUrl+`/place/${idPlace}`, {
- params: {
- lang: 'EN'
- }
- });
-
- const place: Place = placeModelToEntity(dataES);
- place.descriptions?.push(dataEN.description);
-
- return place;
- }
-
- async updatePlace(place: Place): Promise {
- const formToSend = new FormData();
- formToSend.append('available', place.available);
- formToSend.append('idTown', String(place.idTown));
- formToSend.append('name', place.name);
- formToSend.append('categoriesId', place.categoriesId.join(','));
- formToSend.append('descriptionES', place.descriptions?.[0] ?? '');
- formToSend.append('descriptionEN', place.descriptions?.[1] ?? '');
- formToSend.append('image', place.imagesList?.[0] ?? '');
- formToSend.append('latitude', String(place.latitude));
- 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));
- formToSend.append('endDate', String(place.endDate));
- }
-
- const headers = {
- 'Content-Type': 'multipart/form-data'
- };
-
- await axios.patch(APIUrl+`/place/${place.idPlace}`, formToSend,{headers});
- }
-}
\ No newline at end of file
diff --git a/web/src/data/datasources/prod/poi_datasource.ts b/web/src/data/datasources/prod/poi_datasource.ts
deleted file mode 100644
index f1d6b92b..00000000
--- a/web/src/data/datasources/prod/poi_datasource.ts
+++ /dev/null
@@ -1,70 +0,0 @@
-import axios from "axios";
-import { Buffer } from "buffer";
-import { PoiDatasourceInf } from "../../../infraestructure/datasources/poi_datasource";
-import { PointOfInterest } from "../../../infraestructure/entities/poi";
-import { APIUrl } from "../../../constants/api_url";
-import { API_ROUTE_PLACE, API_ROUTE_POINT } from "../../../constants/api_routes";
-import { POIModel, POIModelToEntity } from "../../models/prod/POIModel";
-
-export class POIDatasourceProd implements PoiDatasourceInf{
- async registerPoint(form: PointOfInterest): Promise {
- const formToSend = new FormData();
- formToSend.append('idPlace', String(form.idPlace));
- formToSend.append('name', form.name);
- formToSend.append('image', form.image);
- formToSend.append('contentEN', form.contentEN);
- formToSend.append('contentES', form.contentES);
- formToSend.append('directionsEN', form.directionsEN);
- formToSend.append('directionsES', form.directionsES);
-
- const headers = {
- 'Content-Type': 'multipart/form-data'
- };
-
- await axios.post(APIUrl + API_ROUTE_POINT, formToSend,{headers});
- }
-
- async getPOIsByPlace(idPlace: number): Promise {
- const {data: dataES} = await axios.get(APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT, {
- params: {
- lang: 'ES'
- }
- });
-
- const poiList = dataES.map((dataESModel) => {
- return POIModelToEntity(dataESModel);
- })
-
- return poiList;
- }
-
- async getPOIById(idPoint: number): Promise {
- const {data: dataES} = await axios.get(APIUrl + API_ROUTE_POINT + `/${idPoint}`, {
- params: {
- lang: 'ES'
- }
- });
-
- const {data: dataEN} = await axios.get(APIUrl + API_ROUTE_POINT + `/${idPoint}`, {
- params: {
- lang: 'EN'
- }
- });
-
- const poi: PointOfInterest = POIModelToEntity(dataES);
- poi.contentEN = dataEN.content;
- poi.directionsEN = dataEN.directions;
-
- return poi;
- }
-
- async getPDFByPoints(idPlace: number, pointsId: number[]): Promise {
- const {data} = await axios.get(APIUrl + API_ROUTE_PLACE + `/${idPlace}` + API_ROUTE_POINT + '/generate', {
- params: {
- pointsId: pointsId.join(',')
- },
- responseType: 'arraybuffer'
- });
- return Buffer.from(data, 'binary').toString('base64');
- }
-}
\ No newline at end of file
diff --git a/web/src/data/datasources/prod/town_datasource.ts b/web/src/data/datasources/prod/town_datasource.ts
deleted file mode 100644
index fcbba15e..00000000
--- a/web/src/data/datasources/prod/town_datasource.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import axios from "axios";
-import { APIUrl } from "../../../constants/api_url";
-import { TownDatasourceInf } from "../../../infraestructure/datasources/town_datasource";
-import { StateModel } from "../../models/prod/StateModel";
-import { State } from "../../../infraestructure/entities/state";
-import { Town } from "../../../infraestructure/entities/town";
-import { TownModel, TownModelTrad } from "../../models/prod/TownModel";
-
-export class TownDatasourceProd implements TownDatasourceInf{
- async getStates(): Promise {
- const {data} = await axios.get(APIUrl+"/state");
- const states = data.map((value) => {
- const state: State = {
- stateId : value.stateId,
- name: value.name,
- imageURL: value.imageURL
- }
- return state;
- })
-
- return states;
- }
-
- async registerTown(form: Town): Promise {
- const formToSend = new FormData();
- formToSend.append('name',form.name);
- formToSend.append('descriptionES',form.descriptionES || '');
- formToSend.append('descriptionEN',form.descriptionEN || '');
- formToSend.append('state', String(form.idState));
- formToSend.append('image',form.imageURL || '');
-
- const headers = {
- 'Content-Type': 'multipart/form-data'
- };
-
- await axios.post(APIUrl + '/town', formToSend,{headers});
- }
-
- async getTownsByState(idState: number, stateName:string): Promise {
- const {data} = await axios.get(APIUrl+`/state/${idState}/town`, {
- params: {
- lang: 'ES'
- }
- });
- const towns = data.map((value) => {
- const town: Town = {
- idTown : value.townId,
- name: value.name,
- idState: value.stateId,
- state: stateName
- }
- return town;
- })
-
- return towns;
- }
-
- async getTown(idTown: number): Promise {
- const {data} = await axios.get(APIUrl+`/town/${idTown}`);
- const town: Town = {
- idTown : data.townId,
- name: data.name,
- idState: data.stateId,
- descriptionES: data.descriptionES,
- descriptionEN: data.descriptionEN,
- state: '',
- imageURL: data.imageName
- }
- return town;
- }
-
- async updateTown(form: Town): Promise {
- const formToSend = new FormData();
- formToSend.append('name',form.name);
- formToSend.append('descriptionES',form.descriptionES || '');
- formToSend.append('descriptionEN',form.descriptionEN || '');
- formToSend.append('image',form.imageURL || '');
- formToSend.append('state', String(form.idState));
-
- const headers = {
- 'Content-Type': 'multipart/form-data'
- };
-
- await axios.patch(APIUrl+`/town/${form.idTown}`, formToSend,{headers});
- }
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/AdminModel.ts b/web/src/data/models/prod/AdminModel.ts
deleted file mode 100644
index 2ac2cfc4..00000000
--- a/web/src/data/models/prod/AdminModel.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export interface AdminModel {
- email: string;
- name: string;
- lastName: string;
- role?: string;
- idTown?: number;
- status: string;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/CategoryModel.ts b/web/src/data/models/prod/CategoryModel.ts
deleted file mode 100644
index 2846a79c..00000000
--- a/web/src/data/models/prod/CategoryModel.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export interface CategoryModel{
- idCategory: number;
- name: string;
-}
-
-export interface CategoryModelLan {
- idCategory: number;
- language: string;
- name: string;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/LoggedInUserModel.ts b/web/src/data/models/prod/LoggedInUserModel.ts
deleted file mode 100644
index 8f73d45b..00000000
--- a/web/src/data/models/prod/LoggedInUserModel.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface LoggedInUserModel {
- email: string;
- name: string;
- role: string;
- token: string;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/POIModel.ts b/web/src/data/models/prod/POIModel.ts
deleted file mode 100644
index 603b8bd4..00000000
--- a/web/src/data/models/prod/POIModel.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { PointOfInterest } from "../../../infraestructure/entities/poi";
-
-export interface POIModel {
- idPoint: number;
- idPlace: number;
- name: string;
- imageName: string;
- content: string;
- directions: string;
-}
-
-export const POIModelToEntity = (model: POIModel) =>{
- const poi: PointOfInterest = {
- idPoint : model.idPoint,
- idPlace : model.idPlace,
- name: model.name,
- image: model.imageName,
- contentES: model.content,
- contentEN: model.content,
- directionsES: model.directions,
- directionsEN: model.directions
- }
- return poi;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/PlaceModel.ts b/web/src/data/models/prod/PlaceModel.ts
deleted file mode 100644
index 5e4ea3e4..00000000
--- a/web/src/data/models/prod/PlaceModel.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { AvailableDays, Place } from "../../../infraestructure/entities/place";
-import { CategoryModelLan } from "./CategoryModel";
-
-export interface PlaceModel {
- idTown: number;
- idPlace: number;
- available: string;
- description: string;
- latitude: number;
- longitude: number;
- imageName: string;
- name: string;
- categories: CategoryModelLan[]
- openAt: number;
- closeAt: number;
- startDate?: Date;
- endDate?: Date;
- address: string;
-}
-
-export const placeModelToEntity = (model: PlaceModel) =>{
- let availableDays = AvailableDays.WEEKEND;
- switch(model.available){
- case AvailableDays.ALL_DAYS:
- availableDays = AvailableDays.ALL_DAYS;
- break;
- case AvailableDays.CUSTOM:
- availableDays = AvailableDays.CUSTOM;
- break;
- case AvailableDays.WEEKDAYS:
- availableDays = AvailableDays.WEEKDAYS;
- break;
- default:
- availableDays = AvailableDays.WEEKEND;
- break;
- }
-
- const place: Place = {
- idTown : model.idTown,
- idPlace : model.idPlace,
- available : availableDays,
- latitude: model.latitude,
- longitude: model.longitude,
- descriptions: [model.description],
- imagesList: [model.imageName],
- name: model.name,
- categoriesId: model.categories.map((category)=> category.idCategory),
- openAt: model.openAt,
- closeAt: model.closeAt,
- startDate: model.startDate,
- endDate: model.endDate,
- address: model.address
- }
- return place;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/StateModel.ts b/web/src/data/models/prod/StateModel.ts
deleted file mode 100644
index 41f2f827..00000000
--- a/web/src/data/models/prod/StateModel.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface StateModel {
- stateId: number;
- name: string;
- imageURL: string;
-}
\ No newline at end of file
diff --git a/web/src/data/models/prod/TownModel.ts b/web/src/data/models/prod/TownModel.ts
deleted file mode 100644
index 4b79e916..00000000
--- a/web/src/data/models/prod/TownModel.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-export interface TownModelTrad {
- townId: number;
- name : string;
- imageName : string;
- description : string;
- stateId : number;
-}
-
-export interface TownModel {
- townId: number;
- name : string;
- descriptionEN : string;
- descriptionES : string;
- imageName : string;
- stateId : number;
-}
\ No newline at end of file
diff --git a/web/src/data/repositories/prod/admin_repository.ts b/web/src/data/repositories/prod/admin_repository.ts
deleted file mode 100644
index b86b4da1..00000000
--- a/web/src/data/repositories/prod/admin_repository.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { AdminDatasourceInf } from "../../../infraestructure/datasources/admin_datasource";
-import {
- Admin,
- AdminFormValues,
-} from "../../../infraestructure/entities/admin_form_values";
-import { ResetPasswordValues } from "../../../infraestructure/entities/reset_password_values";
-import { AdminRepositoryInf } from "../../../infraestructure/repositories/admin_repository";
-
-export class AdminRepositoryProd implements AdminRepositoryInf {
- constructor(private datasource: AdminDatasourceInf) {}
-
- async registerAdmin(form: AdminFormValues): Promise {
- return this.datasource.registerAdmin(form);
- }
-
- async getAdminInfo(token: string): Promise {
- return this.datasource.getAdminInfo(token);
- }
-
- async changePassword(
- token: string,
- prevPassword: string,
- newPassword: string
- ): Promise {
- return this.datasource.changePassword(token, prevPassword, newPassword);
- }
-
- async getAdminsByTown(idTown: number): Promise {
- return this.datasource.getAdminsByTown(idTown);
- }
-
- async generateResetCode(email: string): Promise {
- return this.datasource.generateResetCode(email);
- }
-
- async resetPassword(form: ResetPasswordValues): Promise {
- return this.datasource.resetPassword(form);
- }
-}
diff --git a/web/src/data/repositories/prod/category_repository.ts b/web/src/data/repositories/prod/category_repository.ts
deleted file mode 100644
index ab0055eb..00000000
--- a/web/src/data/repositories/prod/category_repository.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { CategoryDatasourceInf } from "../../../infraestructure/datasources/category_datasource";
-import { Category, CategoryFormValues } from "../../../infraestructure/entities/category";
-import { CategoryRepositoryInf } from "../../../infraestructure/repositories/category_repository";
-
-export class CategoryRepositoryProd implements CategoryRepositoryInf{
- constructor(
- private datasource: CategoryDatasourceInf
- ){}
-
- async registerCategory(form: CategoryFormValues): Promise {
- return this.datasource.registerCategory(form);
- }
-
- async getCategories(): Promise {
- return this.datasource.getCategories();
- }
-
- async deleteCategory(category: Category): Promise {
- return this.datasource.deleteCategory(category);
- }
-}
\ No newline at end of file
diff --git a/web/src/data/repositories/prod/login_repository.ts b/web/src/data/repositories/prod/login_repository.ts
deleted file mode 100644
index 69c0694f..00000000
--- a/web/src/data/repositories/prod/login_repository.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { LoginDatasourceInf } from "../../../infraestructure/datasources/login_datasource";
-import { LoginFormValues } from "../../../infraestructure/entities/login_form_values";
-import { LoggedInUser } from "../../../infraestructure/entities/user";
-import { LoginRepositoryInf } from "../../../infraestructure/repositories/login_repository";
-
-export class LoginRepositoryProd implements LoginRepositoryInf{
- constructor(
- private datasource: LoginDatasourceInf
- ){}
- async getToken(form: LoginFormValues): Promise {
- return this.datasource.getToken(form);
- }
-}
\ No newline at end of file
diff --git a/web/src/data/repositories/prod/place_repository.ts b/web/src/data/repositories/prod/place_repository.ts
deleted file mode 100644
index 843fdb8d..00000000
--- a/web/src/data/repositories/prod/place_repository.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { PlaceDatasourceInf } from "../../../infraestructure/datasources/place_datasource";
-import { Place } from "../../../infraestructure/entities/place";
-import { PlaceRepositoryInf } from "../../../infraestructure/repositories/place_repository";
-
-export class PlaceRepositoryProd implements PlaceRepositoryInf{
- constructor(
- private datasouce: PlaceDatasourceInf
- ){}
- async registerPlace(form: Place): Promise {
- return this.datasouce.registerPlace(form);
- }
-
- async getPlacesByTown(idTown: number): Promise {
- return this.datasouce.getPlacesByTown(idTown);
- }
-
- async getPlaceById(idPlace: number): Promise {
- return this.datasouce.getPlaceById(idPlace);
- }
-
- async updatePlace(place: Place): Promise {
- return this.datasouce.updatePlace(place);
- }
-}
\ No newline at end of file
diff --git a/web/src/data/repositories/prod/poi_repository.ts b/web/src/data/repositories/prod/poi_repository.ts
deleted file mode 100644
index 86a180bd..00000000
--- a/web/src/data/repositories/prod/poi_repository.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { PoiDatasourceInf } from "../../../infraestructure/datasources/poi_datasource";
-import { PointOfInterest } from "../../../infraestructure/entities/poi";
-import { PoiRepositoryInf } from "../../../infraestructure/repositories/poi_repository";
-
-export class POIRepositoryProd implements PoiRepositoryInf{
- constructor(
- private datasouce: PoiDatasourceInf
- ){}
-
- async registerPoint(form: PointOfInterest): Promise {
- return this.datasouce.registerPoint(form);
- }
-
- async getPOIById(idPoint: number): Promise {
- return this.datasouce.getPOIById(idPoint);
- }
-
- async getPOIsByPlace(idPlace: number): Promise {
- return this.datasouce.getPOIsByPlace(idPlace);
- }
-
- async getPDFByPoints(idPlace: number, pointsId: number[]): Promise {
- return this.datasouce.getPDFByPoints(idPlace, pointsId);
- }
-}
\ No newline at end of file
diff --git a/web/src/data/repositories/prod/town_repository.ts b/web/src/data/repositories/prod/town_repository.ts
deleted file mode 100644
index 72996d29..00000000
--- a/web/src/data/repositories/prod/town_repository.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import { TownDatasourceInf } from "../../../infraestructure/datasources/town_datasource";
-import { State } from "../../../infraestructure/entities/state";
-import { Town } from "../../../infraestructure/entities/town";
-import { TownRepositoryInf } from "../../../infraestructure/repositories/town_repository";
-
-export class TownRepositoryProd implements TownRepositoryInf{
- constructor(
- private datasource: TownDatasourceInf
- ){}
- async getStates(): Promise {
- return this.datasource.getStates();
- }
- async registerTown(form: Town): Promise {
- return this.datasource.registerTown(form);
- }
- async getTownsByState(idState: number, stateName:string) : Promise {
- return this.datasource.getTownsByState(idState, stateName);
- }
- async getTown(idTown: number): Promise {
- return this.datasource.getTown(idTown);
- }
- async updateTown(form: Town): Promise {
- return this.datasource.updateTown(form);
- }
-}
\ No newline at end of file
diff --git a/web/src/data/repository/admin_repository.ts b/web/src/data/repository/admin_repository.ts
new file mode 100644
index 00000000..e2ceedcb
--- /dev/null
+++ b/web/src/data/repository/admin_repository.ts
@@ -0,0 +1,74 @@
+import { AdminDatasourceInf } from "../datasource/admin_datasource";
+import {
+ Admin,
+ AdminFormValues,
+} from "../datasource/api/entities/admin_form_values";
+import { ResetPasswordValues } from "../datasource/api/entities/reset_password_values";
+import { AdminRepositoryInf } from "../../domain/repository/admin_repository";
+
+/**
+ * Implementation of the AdminRepository interface for production.
+ */
+export class AdminRepositoryProd implements AdminRepositoryInf {
+ constructor(private datasource: AdminDatasourceInf) {}
+
+ /**
+ * Registers a new admin.
+ * @param form - The admin data to register.
+ * @returns A promise that resolves when the admin is registered.
+ */
+ async registerAdmin(form: AdminFormValues): Promise {
+ return this.datasource.registerAdmin(form);
+ }
+
+ /**
+ * Retrieves admin information by token.
+ * @param token - The token of the admin.
+ * @returns A promise that resolves to an Admin object.
+ */
+ async getAdminInfo(token: string): Promise {
+ return this.datasource.getAdminInfo(token);
+ }
+
+ /**
+ * Changes the password of an admin.
+ * @param token - The token of the admin.
+ * @param prevPassword - The previous password.
+ * @param newPassword - The new password.
+ * @returns A promise that resolves when the password is changed.
+ */
+ async changePassword(
+ token: string,
+ prevPassword: string,
+ newPassword: string
+ ): Promise {
+ return this.datasource.changePassword(token, prevPassword, newPassword);
+ }
+
+ /**
+ * Retrieves admins by town.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Admin objects.
+ */
+ async getAdminsByTown(idTown: number): Promise {
+ return this.datasource.getAdminsByTown(idTown);
+ }
+
+ /**
+ * Generates a reset code for the given email.
+ * @param email - The email to generate the reset code for.
+ * @returns A promise that resolves when the reset code is generated.
+ */
+ async generateResetCode(email: string): Promise {
+ return this.datasource.generateResetCode(email);
+ }
+
+ /**
+ * Resets the password using the given form values.
+ * @param form - The reset password form values.
+ * @returns A promise that resolves when the password is reset.
+ */
+ async resetPassword(form: ResetPasswordValues): Promise {
+ return this.datasource.resetPassword(form);
+ }
+}
diff --git a/web/src/data/repository/category_repository.ts b/web/src/data/repository/category_repository.ts
new file mode 100644
index 00000000..d35aa5fa
--- /dev/null
+++ b/web/src/data/repository/category_repository.ts
@@ -0,0 +1,39 @@
+import { CategoryDatasourceInf } from "../datasource/category_datasource";
+import {
+ Category,
+ CategoryFormValues,
+} from "../datasource/api/entities/category";
+import { CategoryRepositoryInf } from "../../domain/repository/category_repository";
+
+/**
+ * Implementation of the CategoryRepository interface for production.
+ */
+export class CategoryRepositoryProd implements CategoryRepositoryInf {
+ constructor(private datasource: CategoryDatasourceInf) {}
+
+ /**
+ * Registers a new category.
+ * @param form - The category data to register.
+ * @returns A promise that resolves when the category is registered.
+ */
+ async registerCategory(form: CategoryFormValues): Promise {
+ return this.datasource.registerCategory(form);
+ }
+
+ /**
+ * Retrieves all categories.
+ * @returns A promise that resolves to an array of Category objects.
+ */
+ async getCategories(): Promise {
+ return this.datasource.getCategories();
+ }
+
+ /**
+ * Deletes an existing category.
+ * @param category - The category to delete.
+ * @returns A promise that resolves when the category is deleted.
+ */
+ async deleteCategory(category: Category): Promise {
+ return this.datasource.deleteCategory(category);
+ }
+}
diff --git a/web/src/data/repository/login_repository.ts b/web/src/data/repository/login_repository.ts
new file mode 100644
index 00000000..4dac9d5b
--- /dev/null
+++ b/web/src/data/repository/login_repository.ts
@@ -0,0 +1,20 @@
+import { LoginDatasource } from "../datasource/login_datasource";
+import { LoginFormValues } from "../datasource/api/entities/login_form_values";
+import { LoggedInUser } from "../datasource/api/entities/user";
+import { LoginRepository } from "../../domain/repository/login_repository";
+
+/**
+ * Implementation of the LoginRepository interface.
+ */
+export class LoginRepositoryImpl implements LoginRepository {
+ constructor(private datasource: LoginDatasource) {}
+
+ /**
+ * Retrieves a token for the given login form values.
+ * @param form - The login form values.
+ * @returns A promise that resolves to a logged-in user.
+ */
+ async getToken(form: LoginFormValues): Promise {
+ return this.datasource.getToken(form);
+ }
+}
diff --git a/web/src/data/repository/place_repository.ts b/web/src/data/repository/place_repository.ts
new file mode 100644
index 00000000..aa120f13
--- /dev/null
+++ b/web/src/data/repository/place_repository.ts
@@ -0,0 +1,46 @@
+import { PlaceDatasourceInf } from "../datasource/place_datasource";
+import { Place } from "../datasource/api/entities/place";
+import { PlaceRepositoryInf } from "../../domain/repository/place_repository";
+
+/**
+ * Implementation of the PlaceRepository interface for production.
+ */
+export class PlaceRepositoryProd implements PlaceRepositoryInf {
+ constructor(private datasouce: PlaceDatasourceInf) {}
+
+ /**
+ * Registers a new place.
+ * @param form - The place data to register.
+ * @returns A promise that resolves when the place is registered.
+ */
+ async registerPlace(form: Place): Promise {
+ return this.datasouce.registerPlace(form);
+ }
+
+ /**
+ * Retrieves places by town.
+ * @param idTown - The ID of the town.
+ * @returns A promise that resolves to an array of Place objects.
+ */
+ async getPlacesByTown(idTown: number): Promise {
+ return this.datasouce.getPlacesByTown(idTown);
+ }
+
+ /**
+ * Retrieves a place by its ID.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to a Place object.
+ */
+ async getPlaceById(idPlace: number): Promise {
+ return this.datasouce.getPlaceById(idPlace);
+ }
+
+ /**
+ * Updates an existing place.
+ * @param place - The place data to update.
+ * @returns A promise that resolves when the place is updated.
+ */
+ async updatePlace(place: Place): Promise {
+ return this.datasouce.updatePlace(place);
+ }
+}
diff --git a/web/src/data/repository/poi_repository.ts b/web/src/data/repository/poi_repository.ts
new file mode 100644
index 00000000..9a59ed06
--- /dev/null
+++ b/web/src/data/repository/poi_repository.ts
@@ -0,0 +1,47 @@
+import { PoiDatasourceInf } from "../datasource/poi_datasource";
+import { PointOfInterest } from "../datasource/api/entities/poi";
+import { PoiRepositoryInf } from "../../domain/repository/poi_repository";
+
+/**
+ * Implementation of the PoiRepository interface for production.
+ */
+export class POIRepositoryProd implements PoiRepositoryInf {
+ constructor(private datasouce: PoiDatasourceInf) {}
+
+ /**
+ * Registers a new point of interest.
+ * @param form - The point of interest data to register.
+ * @returns A promise that resolves when the point of interest is registered.
+ */
+ async registerPoint(form: PointOfInterest): Promise {
+ return this.datasouce.registerPoint(form);
+ }
+
+ /**
+ * Retrieves a point of interest by its ID.
+ * @param idPoint - The ID of the point of interest.
+ * @returns A promise that resolves to a PointOfInterest object.
+ */
+ async getPOIById(idPoint: number): Promise {
+ return this.datasouce.getPOIById(idPoint);
+ }
+
+ /**
+ * Retrieves points of interest by place.
+ * @param idPlace - The ID of the place.
+ * @returns A promise that resolves to an array of PointOfInterest objects.
+ */
+ async getPOIsByPlace(idPlace: number): Promise