diff --git a/web/src/components/admin_panel_navbar/admin_navbar.tsx b/web/src/components/admin_panel_navbar/admin_navbar.tsx index 0dad5f8dbd657ebcaec7c86f7a9424a6e604ed4f..81e61e3dc2d3ee73715b5016c1e107657f7806d6 100644 --- a/web/src/components/admin_panel_navbar/admin_navbar.tsx +++ b/web/src/components/admin_panel_navbar/admin_navbar.tsx @@ -1,16 +1,42 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faSignOut, faUser } from "@fortawesome/free-solid-svg-icons"; +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{ - windowActive: boolean; + isWindowActive: boolean; + setIsWindowActive: Dispatch>; } -export const AdminPanelNavBar = ({windowActive}:props) => { +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; @@ -25,14 +51,14 @@ export const AdminPanelNavBar = ({windowActive}:props) => {
{ - windowActive + isWindowActive ? setToggle(false) : setToggle(!toggle) }} style={ - windowActive + isWindowActive ? {cursor: "auto"} : @@ -48,9 +74,9 @@ export const AdminPanelNavBar = ({windowActive}:props) => {

- + {setChangePasswordWindowVisibility(true); setToggle(false);}} className="sub-menu-link"> -

Editar cuenta

+

Cambiar contraseña

@@ -61,6 +87,87 @@ export const AdminPanelNavBar = ({windowActive}:props) => { } + { + changePasswordWindowActive && +
+
+ Cambio de contraseña + setChangePasswordWindowVisibility(false)}/> +
+ +
+
+
+ +
+ + +
+

{errors.prevPassword?.message}

+
+ +
+ +
+ + +
+

{errors.newPassword?.message}

+
+ +
+ +
+ + +
+

{errors.newPasswordConfirm?.message}

+
+ +
+ +
+
+
+
+ } ); } \ No newline at end of file diff --git a/web/src/components/admin_panel_navbar/assets/styles/style.css b/web/src/components/admin_panel_navbar/assets/styles/style.css index 6665a0775115485fbc6d3dce85551cdc4e9de414..e8d2af3fa2b37b21d448f8bba3d4392a994f195c 100644 --- a/web/src/components/admin_panel_navbar/assets/styles/style.css +++ b/web/src/components/admin_panel_navbar/assets/styles/style.css @@ -1,91 +1,181 @@ :root { - --shadow: 0px 2px 8px 0px gray; + --shadow: 0px 2px 8px 0px gray; } .navbar{ - height: 6vh; - width: 100%; - display: flex; - align-items: center; - justify-content: space-between; - box-shadow: var(--shadow); + height: 6vh; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + box-shadow: var(--shadow); } .profile{ - position: absolute; - right: 20px; - user-select: none; + position: absolute; + right: 20px; + user-select: none; } .user-pic{ - width: 30px; - border-radius: 50%; - background: white; + width: 30px; + border-radius: 50%; + background: white; } .profile-sub-menu-wrap{ - position: absolute; - top: 100%; - right: 10%; - min-width: 300px; - max-width: 300px; - overflow: hidden; - z-index: 1000; - transition: max-height 0.5s; + position: absolute; + top: 100%; + right: 10%; + min-width: 300px; + max-width: 300px; + overflow: hidden; + z-index: 1000; + transition: max-height 0.5s; } .sub-menu{ - background: white; - padding: 10px; - margin: 10px; + background: white; + padding: 10px; + margin: 10px; } .user-info{ - display: flex; - align-items: center; + display: flex; + align-items: center; } .user-info img{ - width: 60px; - margin-right: 15px; - border-radius: 50%; + width: 60px; + margin-right: 15px; + border-radius: 50%; } .user-info h3{ - font-weight: 500; + font-weight: 500; } .sub-menu hr{ - border: 0; - height: 1px; - width: 100%; - background: #ccc ; - margin: 15px 0 10px; + border: 0; + height: 1px; + width: 100%; + background: #ccc ; + margin: 15px 0 10px; } .sub-menu-link{ - display: flex; - align-items: center; - text-decoration: none; - color: #525252; + display: flex; + align-items: center; + text-decoration: none; + color: #525252; } .sub-menu-link:hover .sub-menu-link-icon{ - transform: scale(1.1); + transform: scale(1.1); } .sub-menu-link:hover p{ - font-weight: 600; + font-weight: 600; } .sub-menu-link p{ - user-select: none; + user-select: none; } .sub-menu-link .sub-menu-link-icon{ - width: 20px; - background: #E5E5E5; - border-radius: 50%; - padding: 8px; - margin-right: 15px; + width: 20px; + background: #E5E5E5; + border-radius: 50%; + padding: 8px; + margin-right: 15px; +} + +.change-password-window { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + margin: auto; + width: 30vw; + height: 40vh; + background: green; + display: flex; + flex-direction: column; + z-index: 5; +} + +.change-password-window .header { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + padding: 5px; +} + +.change-password-window .header .close_btn{ + display: inline-block; + cursor: pointer; + height: 5%; + position: absolute; + right: 5px; +} + +.change-password-window .content { + background: white; + width: 100%; + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.change-password-window .content form{ + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.change-password-window .content form .input_cnt{ + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding: 5px 0; +} + +.change-password-window .content form .input_cnt input{ + width: 80%; + padding: 5px 20px; + border: 1px solid lightgray; + border-radius: 5px; +} + +.error{ + color: red; + font-size: 12px; + padding: 0; + margin: 0; +} + +.change-password-window .content form .input_cnt .submit_btn{ + width: 30%; +} + +.change-password-window .content form .input_cnt .password_cnt{ + position: relative; + width: 80%; +} + +.change-password-window .content form .input_cnt .password_cnt input{ + width: 100%; + padding-left: 20px; + padding-right: 30px; +} + +.change-password-window .content form .input_cnt .password_cnt .visibility-button{ + position: absolute; + top: 50%; + right: 5px; + transform: translateY(-50%); + cursor: pointer; } \ 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 index 7ded0c77cdc6943cec3ad27ef03f4aed951177bc..94aa6d31ffe06ed8d4b5e1ae4bd05e650e4f8bfc 100644 --- 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 @@ -10,12 +10,12 @@ import { Dispatch, SetStateAction, useEffect } from 'react'; interface props{ idTown: number; isWindowActive: boolean; - setIsWindowActive: Dispatch>; + setWindowVisibility: (visibility: boolean) => void; setActualPlace: Dispatch>; setIsRegisterPane: Dispatch>; } -export const AdminPanelPlaceList = ({idTown, isWindowActive, setIsWindowActive, setActualPlace, setIsRegisterPane}: props) => { +export const AdminPanelPlaceList = ({idTown, isWindowActive, setWindowVisibility, setActualPlace, setIsRegisterPane}: props) => { const { placeList, pending, @@ -25,7 +25,7 @@ export const AdminPanelPlaceList = ({idTown, isWindowActive, setIsWindowActive, const handleEditSelectedCategory = (place: Place) => { setIsRegisterPane(false); setActualPlace(place); - setIsWindowActive(true); + setWindowVisibility(true); } useEffect(() => { diff --git a/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx b/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx index fff742bcca27f9a6cebebee9feacd39c7929f0ee..fe958171d87e2c111077819e8b8e9f95ba3628c3 100644 --- a/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx +++ b/web/src/components/admin_panel_places/admin_panel_place_register/admin_panel_place_register.tsx @@ -11,7 +11,7 @@ import { AvailableDays, availableDaysList, EmptyPlace, Place } from "../../../in import { Category } from "../../../infraestructure/entities/category"; interface props { - setIsWindowActive: Dispatch>; + setWindowVisibility: (visibility: boolean) => void; categoriesList: Category[]; idTown: number; forceRenderList: () => void; @@ -19,7 +19,7 @@ interface props { form?: Place; } -export const AdminPanelPlaceRegister = ({setIsWindowActive, idTown, categoriesList, forceRenderList, isRegister, form}: props) => { +export const AdminPanelPlaceRegister = ({setWindowVisibility, idTown, categoriesList, forceRenderList, isRegister, form}: props) => { const { register, handleSubmit, @@ -39,7 +39,7 @@ export const AdminPanelPlaceRegister = ({setIsWindowActive, idTown, categoriesLi onSubmitRegister, onSubmitUpdate, clearErrors - } = usePlace(forceRenderList, setIsWindowActive); + } = usePlace(forceRenderList, setWindowVisibility); const [clickedCategories, setClickedCategories] = useState(new Array(categoriesList.length).fill(false)); const [isLoading, setIsLoading] = useState(false); const [actualPlace, setActualPlace] = useState(EmptyPlace); @@ -112,7 +112,7 @@ export const AdminPanelPlaceRegister = ({setIsWindowActive, idTown, categoriesLi
Registra el lugar setIsWindowActive(false)}/> + onClick={() => setWindowVisibility(false)}/>
{isLoading diff --git a/web/src/components/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx b/web/src/components/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx index d693e3d2be593f9f9258d31058225a573a84d165..1fd72bb9835b4ee38b73b3b4699b29075ec952ec 100644 --- a/web/src/components/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx +++ b/web/src/components/admin_panel_places/admin_panel_place_screen/admin_panel_place_screen.tsx @@ -16,6 +16,7 @@ export const AdminPanelPlaceScreen = ({isWindowActive,setIsWindowActive, town}: const [renderCount, setRenderCount] = useState(0); const [isRegisterPane, setIsRegisterPane] = useState(true); const [actualPlace, setActualPlace] = useState(); + const [isPlaceRegisterWindowActive, setIsPlaceRegisterWindowActive] = useState(false); const { categoriesList, updateCategoriesList, @@ -26,6 +27,11 @@ export const AdminPanelPlaceScreen = ({isWindowActive,setIsWindowActive, town}: setIsWindowActive(false); } + const setWindowVisibility = (visibility: boolean) => { + setIsPlaceRegisterWindowActive(visibility); + setIsWindowActive(visibility); + } + useEffect(()=>{ updateCategoriesList(); },[]); @@ -39,7 +45,7 @@ export const AdminPanelPlaceScreen = ({isWindowActive,setIsWindowActive, town}: disabled={isWindowActive || !town} onClick={() => { setIsRegisterPane(true); - setIsWindowActive(true); + setWindowVisibility(true); }} > Registrar lugar @@ -47,8 +53,8 @@ export const AdminPanelPlaceScreen = ({isWindowActive,setIsWindowActive, town}:
{ - isWindowActive && }
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 new file mode 100644 index 0000000000000000000000000000000000000000..0ec33afc7ed80c9f1c7546d0a3c65fa47c1a758a --- /dev/null +++ b/web/src/components/admin_panel_poi/admin_panel_poi_list/admin_panel_poi_list.tsx @@ -0,0 +1,111 @@ +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 { faEdit } 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'; + +interface props{ + idTown: number; + isWindowActive: boolean; + setWindowVisibility: (visibility: boolean) => void; + setActualPoint: Dispatch>; + setIsRegisterPane: Dispatch>; +} + +export const AdminPanelPoiList = ({idTown, isWindowActive}: props) => { + const [isLoading, setIsLoading] = useState(false); + const { + placeList, + updatePlacesByTown + } = usePlace(); + + const { + pending, + updatePOIByPlace, + poiList + } = usePointOfInterest(); + + const columns : TableColumn[] = [ + { + name: "Identificador", + selector: row => row.idPoint || -1, + sortable: true + }, + { + name: "Nombre", + selector: row => row.name, + sortable: true + }, + { + name: "Descripción", + selector: row => row.contentES, + sortable: true + }, + { + name: "Acciones", + cell: (row) => { + return ( + + ); + } + } + ]; + + useEffect(() => { + setIsLoading(true); + updatePlacesByTown(idTown); + setIsLoading(false); + },[]); + + const refreshList = (idPlace: number) => { + updatePOIByPlace(idPlace) + }; + + + if(isLoading) return + + return ( +
+
+ Lugar + +
+
+ + } + columns={columns} data={poiList} selectableRows className="data_table" + /> +
+
+ ); +} \ No newline at end of file diff --git a/web/src/components/admin_panel_poi/admin_panel_poi_list/assets/css/styles.css b/web/src/components/admin_panel_poi/admin_panel_poi_list/assets/css/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..a3154b01e61761a5e87179fa0764cb33593d7382 --- /dev/null +++ b/web/src/components/admin_panel_poi/admin_panel_poi_list/assets/css/styles.css @@ -0,0 +1,34 @@ +.poi_list_cnt{ + display: flex; + height: 100%; + width: 100%; + flex-direction: column; +} + +.poi_list_header{ + display: flex; + width: 100%; + height: 8%; + justify-content: center; + align-items: center; +} + +.poi_list_body{ + display: flex; + width: 100%; + flex-grow: 1; +} + +.data_table{ + height: 100%; +} + +.bhFeAR{ + display: flex !important; + height: 100%; +} + +.rdt_TableBody{ + max-height: 100%; + overflow-y: auto; +} \ 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 new file mode 100644 index 0000000000000000000000000000000000000000..d8f653e1dfa7ed5b1205a150713c13852063e512 --- /dev/null +++ b/web/src/components/admin_panel_poi/admin_panel_poi_register/admin_panel_poi_register.tsx @@ -0,0 +1,207 @@ +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 [actualPOI, setActualPOI] = useState(EmptyPointOfInterest); + 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){ + setActualPOI(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 + ? + + : +
+
+
+
+ Nombre del punto de interés +
+ +

{errors.name?.message}

+
+ +
+
+ Descripción del punto de interés + +
+ { + languaguesList.map((language, index) => { + if(index===languageDescriptionIndexSelected){ + return ( +