diff --git a/backend/src/pointOfInterest/PointOfInterest.service.ts b/backend/src/pointOfInterest/PointOfInterest.service.ts index 607e1100170a2f0ba14da19966e69ac912933205..1be3ce47c147f35afee7a35586b9e88bcf99aff1 100644 --- a/backend/src/pointOfInterest/PointOfInterest.service.ts +++ b/backend/src/pointOfInterest/PointOfInterest.service.ts @@ -40,6 +40,20 @@ export class PointOfInterestService { if (!place) { throw new BadRequestException('Place not found'); } + + const idPlace = place.idPlace; + const points: getPointDto[] = await this.dataSource + .getRepository(PointOfInterestTraduction) + .createQueryBuilder('pointTrad') + .leftJoin('pointTrad.idPoint', 'point') + .select(['point.idPoint as idPoint', 'pointTrad.directions as directions', 'point.idPlace as idPlace']) + .where('point.idPlace = :idPlace', { idPlace }) + .andWhere('pointTrad.directions IS NULL') + .getRawMany(); + if (points.length > 0) { + throw new BadRequestException('El ultimo punto ha sido registrado. Para agregar más, cambia el último punto'); + } + const createPointDto: CreatePointDto = { name: createPointAndTradDto.name, imageName: createPointAndTradDto.image, diff --git a/backend/src/pointOfInterest/dto/create-pointAndTraduction.dto.ts b/backend/src/pointOfInterest/dto/create-pointAndTraduction.dto.ts index 1c77b9e534762442d46f7e5520a7be277fa2b8e8..dc58fa5b9294cd10ec2b310a1d6492a47bfc5769 100644 --- a/backend/src/pointOfInterest/dto/create-pointAndTraduction.dto.ts +++ b/backend/src/pointOfInterest/dto/create-pointAndTraduction.dto.ts @@ -12,7 +12,7 @@ export class CreatePointAndTradDto { @ApiProperty() contentES: string; @ApiProperty() - directionsEN: string; + directionsEN?: string; @ApiProperty() - directionsES: string; + directionsES?: string; } diff --git a/backend/src/pointOfInterest/dto/create-pointTrad.dto.ts b/backend/src/pointOfInterest/dto/create-pointTrad.dto.ts index 6c4a0dcdef5d694b9caad9b510e0463c67481e75..9998e9072448f5665a62dab9250e4e1f803eedf6 100644 --- a/backend/src/pointOfInterest/dto/create-pointTrad.dto.ts +++ b/backend/src/pointOfInterest/dto/create-pointTrad.dto.ts @@ -4,6 +4,6 @@ export class CreatePointTradDto { language: LANGUAGES; idPoint: number; content: string; - directions: string; + directions?: string; audioName: string; } diff --git a/backend/src/pointOfInterest/dto/getPoint.dto.ts b/backend/src/pointOfInterest/dto/getPoint.dto.ts index 2a826ef0cb98c7a1127062c050860c0368857b4c..352b3e56a4dba1f12f8ce45f92f27c09a518ec1d 100644 --- a/backend/src/pointOfInterest/dto/getPoint.dto.ts +++ b/backend/src/pointOfInterest/dto/getPoint.dto.ts @@ -4,5 +4,5 @@ export class getPointDto { name: string; imageName: string; content: string; - directions: string; + directions?: string; } diff --git a/backend/src/pointOfInterest/dto/printPointInfo.dto.ts b/backend/src/pointOfInterest/dto/printPointInfo.dto.ts index 20696a29521b116f1ea09556340700406fbefa4f..19d916733e4fadf215af5c09ec82f15b3fc79b50 100644 --- a/backend/src/pointOfInterest/dto/printPointInfo.dto.ts +++ b/backend/src/pointOfInterest/dto/printPointInfo.dto.ts @@ -2,4 +2,4 @@ export class printPointInfo { idPoint: number; namePlace: string; name: string; -} \ No newline at end of file +} diff --git a/web/src/data/datasource/api/entities/poi.ts b/web/src/data/datasource/api/entities/poi.ts index ad5936a32d5e55509fce5e07612baf32697b8253..8227265a6c54e388f57bf89af2e3221f76104524 100644 --- a/web/src/data/datasource/api/entities/poi.ts +++ b/web/src/data/datasource/api/entities/poi.ts @@ -8,8 +8,8 @@ export interface PointOfInterest { image: File | string; contentEN: string; contentES: string; - directionsEN: string; - directionsES: string; + directionsEN?: string; + directionsES?: string; } /** diff --git a/web/src/data/datasource/api/place_datasource.ts b/web/src/data/datasource/api/place_datasource.ts index 88145c21edde7d41481f40eae57c7e6c2f0f6494..946b8bb567e3d5c8389002de8bbb9e635a7dfa70 100644 --- a/web/src/data/datasource/api/place_datasource.ts +++ b/web/src/data/datasource/api/place_datasource.ts @@ -125,4 +125,13 @@ export class PlaceDatasourceProd implements PlaceDatasourceInf { headers, }); } + + /** + * Delete an existing place. + * @param idPlace - The place id to delete. + * @returns A promise that resolves when the place is deleted. + */ + async deletePlace(idPlace: number): Promise { + //await axios.patch(APIUrl + `/place/${idPlace}`) + } } diff --git a/web/src/data/datasource/api/poi_datasource.ts b/web/src/data/datasource/api/poi_datasource.ts index 206f5c92f139422541c2f5cd8e71337157188f3e..4e26660e57851dd7776fc6906701b2e147cce346 100644 --- a/web/src/data/datasource/api/poi_datasource.ts +++ b/web/src/data/datasource/api/poi_datasource.ts @@ -22,8 +22,10 @@ export class POIDatasourceProd implements PoiDatasourceInf { 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); + if (form.directionsEN && form.directionsES) { + formToSend.append("directionsEN", form.directionsEN); + formToSend.append("directionsES", form.directionsES); + } const headers = { "Content-Type": "multipart/form-data", diff --git a/web/src/data/datasource/place_datasource.ts b/web/src/data/datasource/place_datasource.ts index 3b787935f20b9adada613a0f14fc7e43268a54c4..9407136a03108f30f409699b237f001356936db5 100644 --- a/web/src/data/datasource/place_datasource.ts +++ b/web/src/data/datasource/place_datasource.ts @@ -31,4 +31,11 @@ export interface PlaceDatasourceInf { * @returns A promise that resolves when the update is complete. */ updatePlace(place: Place): Promise; + + /** + * Delete an existing place. + * @param idPlace - The place id to delete. + * @returns A promise that resolves when the place is deleted. + */ + deletePlace(idPlace: number): Promise; } diff --git a/web/src/data/repository/place_repository.ts b/web/src/data/repository/place_repository.ts index aa120f13dc1f8de2d44a3c43e7e36e3931534b8f..f2c0c9dd6a4d98e4d3aea50152e77d956dfda234 100644 --- a/web/src/data/repository/place_repository.ts +++ b/web/src/data/repository/place_repository.ts @@ -43,4 +43,13 @@ export class PlaceRepositoryProd implements PlaceRepositoryInf { async updatePlace(place: Place): Promise { return this.datasouce.updatePlace(place); } + + /** + * Delete an existing place. + * @param idPlace - The place id to delete. + * @returns A promise that resolves when the place is deleted. + */ + async deletePlace(idPlace: number): Promise { + return this.datasouce.deletePlace(idPlace); + } } diff --git a/web/src/domain/model/POIModel.ts b/web/src/domain/model/POIModel.ts index 72d1408084dcc60dd22d13e9cdc3e752bf365aea..c8bf2ac2e5e95f75b0e203a0da85144976252043 100644 --- a/web/src/domain/model/POIModel.ts +++ b/web/src/domain/model/POIModel.ts @@ -15,7 +15,7 @@ export interface POIModel { /** Content description of the point of interest */ content: string; /** Directions to the point of interest */ - directions: string; + directions?: string; } /** diff --git a/web/src/domain/repository/place_repository.ts b/web/src/domain/repository/place_repository.ts index a89108d1903a79beb0ad4117d9b449fb7fd182b0..9ec6e750cea8f47460bcc5a6604c6dd0d2d86150 100644 --- a/web/src/domain/repository/place_repository.ts +++ b/web/src/domain/repository/place_repository.ts @@ -31,4 +31,11 @@ export interface PlaceRepositoryInf { * @returns A promise that resolves when the place is updated. */ updatePlace(place: Place): Promise; + + /** + * Delete an existing place. + * @param idPlace - The place id to delete. + * @returns A promise that resolves when the place is deleted. + */ + deletePlace(idPlace: number): Promise; } diff --git a/web/src/domain/useCase/usePlace.ts b/web/src/domain/useCase/usePlace.ts index eec0430ea4c6263b5304f53d286c58f78f99beb8..d27057a203c5e09dd86a564d384c8e78925dbd1c 100644 --- a/web/src/domain/useCase/usePlace.ts +++ b/web/src/domain/useCase/usePlace.ts @@ -14,6 +14,8 @@ import { showErrorAxios } from "../../core/utils/Messages"; const placeDatasouce = new PlaceDatasourceProd(); const placeRepository = new PlaceRepositoryProd(placeDatasouce); +let lastSubmitTime = 0; + // Define resolver for form validation const resolver: Resolver = async (data) => { const errors: FieldErrors = {}; @@ -199,6 +201,13 @@ export const usePlace = ( // Handle form submission for registering a place const onSubmitRegister: SubmitHandler = (data: Place) => { + const currentTime = Date.now(); + if (currentTime - lastSubmitTime < 5000) { + toast.error("Debe esperar 5 segundos entre ejecuciones."); + return; + } + lastSubmitTime = currentTime; + const fetch = async () => { try { await placeRepository.registerPlace(data).then(() => { @@ -212,12 +221,12 @@ export const usePlace = ( if (axios.isAxiosError(error)) { error as AxiosError; switch (error.code) { - case axios.AxiosError.ERR_BAD_REQUEST: - errorMessage = "Acceso no autorizado"; - break; case axios.AxiosError.ERR_NETWORK: errorMessage = "Conexión con el servidor fallida"; break; + default: + errorMessage = error.response?.data.message; + break; } } throw new Error(errorMessage); @@ -234,8 +243,23 @@ export const usePlace = ( }); }; + // Delete a place + const deletePlace = async (idPlace: number) => { + await placeRepository.deletePlace(idPlace); + if (forceRenderList) { + forceRenderList(); + } + }; + // Handle form submission for updating a place const onSubmitUpdate: SubmitHandler = (data: Place) => { + const currentTime = Date.now(); + if (currentTime - lastSubmitTime < 5000) { + toast.error("Debe esperar 5 segundos entre ejecuciones."); + return; + } + lastSubmitTime = currentTime; + const fetch = async () => { try { await placeRepository.updatePlace(data); @@ -248,12 +272,12 @@ export const usePlace = ( if (axios.isAxiosError(error)) { error as AxiosError; switch (error.code) { - case axios.AxiosError.ERR_BAD_REQUEST: - errorMessage = "Acceso no autorizado"; - break; case axios.AxiosError.ERR_NETWORK: errorMessage = "Conexión con el servidor fallida"; break; + default: + errorMessage = error.response?.data.message; + break; } } throw new Error(errorMessage); @@ -338,5 +362,6 @@ export const usePlace = ( setCategoriesId, getPlaceById, getValues, + deletePlace, }; }; diff --git a/web/src/domain/useCase/usePointOfInterest.ts b/web/src/domain/useCase/usePointOfInterest.ts index 656e827a252fde71a0ff6b0c7746fd0e6dfa40f6..722c190ba7543be997908ef728c2643d04470e38 100644 --- a/web/src/domain/useCase/usePointOfInterest.ts +++ b/web/src/domain/useCase/usePointOfInterest.ts @@ -13,102 +13,112 @@ import { showErrorAxios } from "../../core/utils/Messages"; const POIDatasouce = new POIDatasourceProd(); const POIRepository = new POIRepositoryProd(POIDatasouce); -// Define resolver for form validation -const resolver: Resolver = async (data) => { - const errors: FieldErrors = {}; - - // Validate idPlace - if (!data.idPlace) { - errors.idPlace = { - type: "required", - message: "Debe seleccionar el lugar al que pertenece el punto de interés", - }; - } +let lastSubmitTime = 0; - // Validate name - if (!data.name) { - errors.name = { - type: "required", - message: "El nombre del punto de interés es requerido", - }; - } else if (data.name.length > 255) { - errors.name = { - type: "maxLength", - message: "El tamaño no debe sobrepasar los 255 caracteres", - }; - } +// Custom hook for point of interest functionality +export const usePointOfInterest = ( + forceRenderList?: () => void, + setIsWindowActive?: (visibility: boolean) => void +) => { + const [isLastPoint, setIsLastPoint] = useState(false); - // Validate content in English - if (!data.contentEN) { - errors.contentEN = { - type: "required", - message: "La descripción del punto de interés en inglés es requerida", - }; - } else if (data.contentEN.length > 1024) { - errors.contentEN = { - type: "maxLength", - message: "El tamaño no debe sobrepasar los 1024 caracteres", - }; - } + // Define resolver for form validation + const resolver: Resolver = async (data) => { + const errors: FieldErrors = {}; - // Validate content in Spanish - if (!data.contentES) { - errors.contentES = { - type: "required", - message: "La descripción del punto de interés en español es requerida", - }; - } else if (data.contentES.length > 1024) { - errors.contentES = { - type: "maxLength", - message: "El tamaño no debe sobrepasar los 1024 caracteres", - }; - } + // Validate idPlace + if (!data.idPlace) { + errors.idPlace = { + type: "required", + message: + "Debe seleccionar el lugar al que pertenece el punto de interés", + }; + } - // Validate directions in English - if (!data.directionsEN) { - errors.directionsEN = { - type: "required", - message: "Las direcciones del punto de interés en inglés son requeridas", - }; - } else if (data.directionsEN.length > 1024) { - errors.directionsEN = { - type: "maxLength", - message: "El tamaño no debe sobrepasar los 1024 caracteres", - }; - } + // Validate name + if (!data.name) { + errors.name = { + type: "required", + message: "El nombre del punto de interés es requerido", + }; + } else if (data.name.length > 255) { + errors.name = { + type: "maxLength", + message: "El tamaño no debe sobrepasar los 255 caracteres", + }; + } - // Validate directions in Spanish - if (!data.directionsES) { - errors.directionsES = { - type: "required", - message: "Las direcciones del punto de interés en español son requeridas", - }; - } else if (data.directionsES.length > 1024) { - errors.directionsES = { - type: "maxLength", - message: "El tamaño no debe sobrepasar los 1024 caracteres", - }; - } + // Validate content in English + if (!data.contentEN) { + errors.contentEN = { + type: "required", + message: "La descripción del punto de interés en inglés es requerida", + }; + } else if (data.contentEN.length > 1024) { + errors.contentEN = { + type: "maxLength", + message: "El tamaño no debe sobrepasar los 1024 caracteres", + }; + } - // Validate image - if (!data.image) { - errors.image = { - type: "required", - message: "Debe de haber al menos 1 imagen representativa del lugar", - }; - } + // Validate content in Spanish + if (!data.contentES) { + errors.contentES = { + type: "required", + message: "La descripción del punto de interés en español es requerida", + }; + } else if (data.contentES.length > 1024) { + errors.contentES = { + type: "maxLength", + message: "El tamaño no debe sobrepasar los 1024 caracteres", + }; + } - return { - values: Object.keys(errors).length > 0 ? {} : data, - errors: errors, - }; -}; + // Validate directions in English + if (!isLastPoint) { + if (!data.directionsEN) { + errors.directionsEN = { + type: "required", + message: + "Las direcciones del punto de interés en inglés son requeridas", + }; + } else if (data.directionsEN.length > 1024) { + errors.directionsEN = { + type: "maxLength", + message: "El tamaño no debe sobrepasar los 1024 caracteres", + }; + } + } -// Custom hook for point of interest functionality -export const usePointOfInterest = ( - forceRenderList?: () => void, - setIsWindowActive?: (visibility: boolean) => void -) => { + // Validate directions in Spanish + if (!isLastPoint) { + if (!data.directionsES) { + errors.directionsES = { + type: "required", + message: + "Las direcciones del punto de interés en español son requeridas", + }; + } else if (data.directionsES.length > 1024) { + errors.directionsES = { + type: "maxLength", + message: "El tamaño no debe sobrepasar los 1024 caracteres", + }; + } + } + + // Validate image + if (!data.image) { + errors.image = { + type: "required", + message: "Debe de haber al menos 1 imagen representativa del lugar", + }; + } + + return { + values: Object.keys(errors).length > 0 ? {} : data, + errors: errors, + }; + }; const { register, handleSubmit, @@ -137,6 +147,13 @@ export const usePointOfInterest = ( const onSubmitRegister: SubmitHandler = ( data: PointOfInterest ) => { + const currentTime = Date.now(); + if (currentTime - lastSubmitTime < 5000) { + toast.error("Debe esperar 5 segundos entre ejecuciones."); + return; + } + lastSubmitTime = currentTime; + const fetch = async () => { try { await POIRepository.registerPoint(data).then(() => { @@ -151,14 +168,11 @@ export const usePointOfInterest = ( if (axios.isAxiosError(error)) { error as AxiosError; switch (error.code) { - case axios.AxiosError.ERR_BAD_REQUEST: - setErrorMessage("Acceso no autorizado"); - break; case axios.AxiosError.ERR_NETWORK: setErrorMessage("Conexión con el servidor fallida"); break; default: - setErrorMessage(error.message); + setErrorMessage(error.response?.data.message); break; } } @@ -242,5 +256,7 @@ export const usePointOfInterest = ( getPointById, updatePOIByPlace, getPdfById, + isLastPoint, + setIsLastPoint, }; }; diff --git a/web/src/presentation/admin/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx b/web/src/presentation/admin/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx index e57c1a190eee65748e7e369b4c1eceaa5fce4568..468d08095e04a445043610cbdf4b47426c243cc8 100644 --- a/web/src/presentation/admin/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx +++ b/web/src/presentation/admin/admin_panel_places/admin_panel_place_list/admin_panel_place_list.tsx @@ -4,15 +4,18 @@ import { usePlace } from "../../../../domain/useCase/usePlace"; import "./assets/css/styles.css"; import { Place } from "../../../../data/datasource/api/entities/place"; import { LoadingSpinner } from "../../../components/loading_spinner/loading_spinner"; -import { faEdit } from "@fortawesome/free-solid-svg-icons"; +import { faEdit, faTrash } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { Dispatch, SetStateAction, useEffect } from "react"; +import { Dispatch, SetStateAction, useEffect, useState } from "react"; +import { toast } from "react-toastify"; +import { ConfirmationDialog } from "../../../components/confirmation_dialog_box/confirmation_dialog"; // Define the props interface for the component interface props { idTown: number; isWindowActive: boolean; setWindowVisibility: (visibility: boolean) => void; + setIsWindowActiveDelete: Dispatch>; setActualPlace: Dispatch>; setIsRegisterPane: Dispatch>; } @@ -24,21 +27,62 @@ export const AdminPanelPlaceList = ({ setWindowVisibility, setActualPlace, setIsRegisterPane, + setIsWindowActiveDelete, }: props) => { // Use the custom hook to fetch place data - const { placeList, pending, updatePlacesByTown } = usePlace(); + const { placeList, pending, updatePlacesByTown, deletePlace } = usePlace(); + + // State variables for managing dialog and deletion + const [isDialogOpen, setIsDialogOpen] = useState(false); + const [dialogMessage, setDialogMessage] = useState(""); + const [placeDeleted, setPlaceDeleted] = useState(null); + const [deletePlaceBool, setDeletePlaceBool] = useState(false); // Handle the edit action for a selected place - const handleEditSelectedCategory = (place: Place) => { + const handleEditSelectedPlace = (place: Place) => { setIsRegisterPane(false); setActualPlace(place); setWindowVisibility(true); }; + // Function to delete the selected place with a toast notification + const deleteSelectedPlace = (place: Place) => { + toast.promise(deletePlace(place.idPlace || -1), { + pending: "Eliminando lugar...", + success: "El lugar se ha eliminado correctamente", + error: "No se pudo eliminar el lugar", + }); + }; + + // Effect to handle Place deletion when deletePlaceBool changes + useEffect(() => { + if (deletePlaceBool && placeDeleted) { + deleteSelectedPlace(placeDeleted); + setDeletePlaceBool(false); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [deletePlaceBool]); + + // Function to close the confirmation dialog + const handleToClose = () => { + setIsWindowActiveDelete(false); + setIsDialogOpen(false); + }; + + // Function to handle the delete action and open the confirmation dialog + const handleDeleteSelectedPlace = (place: Place) => { + setDialogMessage( + `¿Desea eliminar el lugar ${place.name}?\nEsto eliminará todos los datos relacionados a este lugar.` + ); + setPlaceDeleted(place); + setIsDialogOpen(true); + setIsWindowActiveDelete(true); + }; + // Fetch the places when the component mounts useEffect(() => { updatePlacesByTown(idTown); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Define the columns for the data table @@ -50,7 +94,6 @@ export const AdminPanelPlaceList = ({ { name: "Nombre", selector: (row) => row.name, - sortable: true, }, { name: "Estado", @@ -60,15 +103,27 @@ export const AdminPanelPlaceList = ({ name: "Acciones", cell: (row) => { return ( - { - if (!isWindowActive) { - handleEditSelectedCategory(row); - } - }} - /> + <> + { + if (!isWindowActive) { + handleDeleteSelectedPlace(row); + } + }} + /> + {/* Separation between icons */} + { + if (!isWindowActive) { + handleEditSelectedPlace(row); + } + }} + /> + ); }, }, @@ -85,6 +140,13 @@ export const AdminPanelPlaceList = ({ data={placeList} className="data_table" /> + {isDialogOpen && ( + + )} ); }; diff --git a/web/src/presentation/admin/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx b/web/src/presentation/admin/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx index fe8e629d02cd38171274f94d97d2c777d80ec61e..c8efa88792bf82ed337552bb8f47e77d7137ac97 100644 --- a/web/src/presentation/admin/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx +++ b/web/src/presentation/admin/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx @@ -154,7 +154,7 @@ export const AdminPanelPlaceRegister = ({ return (
- Registra el lugar + {isRegister ? "Registra" : "Actualiza"} el lugar
Nombre del lugar
- +

{errors.name?.message}

diff --git a/web/src/presentation/admin/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx b/web/src/presentation/admin/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx index d86bae58c10110262411342d0a501724684b872a..21e0cd8dc9f10fc9de0b0cd80598bb500dca013d 100644 --- a/web/src/presentation/admin/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx +++ b/web/src/presentation/admin/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx @@ -78,6 +78,7 @@ export const AdminPanelPlaceScreen = ({ setWindowVisibility={setWindowVisibility} setActualPlace={setActualPlace} setIsRegisterPane={setIsRegisterPane} + setIsWindowActiveDelete={setIsWindowActive} />
diff --git a/web/src/presentation/admin/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx b/web/src/presentation/admin/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx index 5c490a4b084aa44ee5dda25d535029e6b309b624..9672eb5396ecf293f157ce1ae0fb3e253573ad23 100644 --- a/web/src/presentation/admin/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx +++ b/web/src/presentation/admin/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx @@ -9,6 +9,7 @@ import { PointOfInterest } from "../../../../data/datasource/api/entities/poi"; import { usePlace } from "../../../../domain/useCase/usePlace"; import { usePointOfInterest } from "../../../../domain/useCase/usePointOfInterest"; import { LoadingScreen } from "../../../components/loading_screen/loading_screen"; +import { Swicth } from "../../../components/switch/switch"; // Define the props interface for the component interface props { @@ -43,6 +44,8 @@ export const AdminPanelPoiRegister = ({ languageDescriptionIndexSelected, languageDirectionsIndexSelected, setLanguageDirectionsIndexSelected, + isLastPoint, + setIsLastPoint, } = usePointOfInterest(forceRenderList, setWindowVisibility); // State variables for loading, image preview, and image file @@ -169,58 +172,70 @@ export const AdminPanelPoiRegister = ({
- Direcciones hacia el siguiente punto de interés - + setLanguageDirectionsIndexSelected( + Number(e.target.value) + ) + } + > + {languaguesList.map((language, index) => { + return ( + + ); + })} + +
+ {languaguesList.map((language, index) => { + if (index === languageDirectionsIndexSelected) { return ( - +