diff --git a/.env.local b/.env.local new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/.env.local @@ -0,0 +1 @@ + diff --git a/.gitignore b/.gitignore index 10e85c1c7d2c7ccb5fe82aad28538bcb65f9449b..fe4d87fecd8a2e0fdd3d2a806c96823f7e262403 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # local env files .env +.env.local # vercel .vercel diff --git a/src/app/(dashboard)/consultation-reservations/PlaceUI.jsx b/src/app/(dashboard)/consultation-reservations/PlaceUI.jsx new file mode 100644 index 0000000000000000000000000000000000000000..f60e74f1f23a0f1be5390cdf5a41a11430299656 --- /dev/null +++ b/src/app/(dashboard)/consultation-reservations/PlaceUI.jsx @@ -0,0 +1,57 @@ +import React, { useContext, useState } from 'react'; +import { ReservationContext } from './page'; + +const colors = [ + '#FF5733', '#50cc65', '#3357FF', '#c9ce41', '#FF33A8', + '#24c4b8', '#FF8333', '#8333FF', '#3383FF', '#83FF33', + '#FF3383', '#2ac567', '#FF33F3', '#4cb7be', '#F333FF', + '#cdd927', '#FF33A8', '#80d3cd', '#FF8333', '#8333FF', + '#3383FF', '#92d965', '#FF3383', '#4ebb78', '#FF33F3', +]; + +const getColorForProject = (projectId) => { + const index = projectId % colors.length; + return colors[index]; +}; + +const PlaceUI = ({ id, isTop }) => { + const { allPlaces, bookedPlaces } = useContext(ReservationContext); + const [showTooltip, setShowTooltip] = useState(false); + const place = allPlaces?.find((place) => place.id === id); + const bookedPlace = bookedPlaces?.find((place) => place.id_place === id); + + if (place) { + const backgroundColor = getColorForProject(place.project_id); // Assuming place object has a project_id field + return ( +
setShowTooltip(true)} + onMouseLeave={() => setShowTooltip(false)} + > +

+ {place?.project_name || ""} +

+ {bookedPlace && ( +
+ )} + {showTooltip && bookedPlace && ( +
+

First Name: {bookedPlace.first_name}

+

Last Name: {bookedPlace.last_name}

+

Role: {bookedPlace.role}

+

Presence: {bookedPlace.presence}

+

Created At: {new Date(bookedPlace.created_at).toLocaleString()}

+
+ )} +
+ ); + } else { + return ( +
+ ); + } +}; + +export default PlaceUI; diff --git a/src/app/(dashboard)/consultation-reservations/TableUI.jsx b/src/app/(dashboard)/consultation-reservations/TableUI.jsx new file mode 100644 index 0000000000000000000000000000000000000000..ce702a2af8182dceaa21dc700b0ad20d3e6ee9fe --- /dev/null +++ b/src/app/(dashboard)/consultation-reservations/TableUI.jsx @@ -0,0 +1,52 @@ +import React from 'react' +import PlaceUI from './PlaceUI'; + +const TableUI = ({id, numero, places}) => { + function groupConsecutive(arr) { + + arr = arr.sort((a, b) => a.id - b.id) + if (arr.length === 0) { + return []; + } + + const grouped = []; + var counter = 0 + while (counter < arr.length) { + if (counter + 1 < arr.length) { + grouped.push([arr[counter], arr[counter + 1]]) + } else { + grouped.push([arr[counter]]) + } + counter += 2; + } + + return grouped; + } + + const processedPlaces = groupConsecutive(places).reverse() + + + if (!processedPlaces || processedPlaces.length === 0) return <> + return ( +
+ {processedPlaces.map((element, index) => { + return
+
+ +
+
+ {(element.length > 1) &&
+ +
} +
+ })} +
+ ) +} + +export default TableUI \ No newline at end of file diff --git a/src/app/(dashboard)/consultation-reservations/ZoneUI.jsx b/src/app/(dashboard)/consultation-reservations/ZoneUI.jsx new file mode 100644 index 0000000000000000000000000000000000000000..48ae7d19663b3c0b7c308a4271a2252e047b92c5 --- /dev/null +++ b/src/app/(dashboard)/consultation-reservations/ZoneUI.jsx @@ -0,0 +1,17 @@ +import React from 'react' +import TableUI from './TableUI' + +const ZoneUI = ({ id, tables, nom }) => { + return ( +
+

{nom}

+
+ {tables.map((table) => { + return + })} +
+
+ ) +} + +export default ZoneUI \ No newline at end of file diff --git a/src/app/(dashboard)/consultation-reservations/page.jsx b/src/app/(dashboard)/consultation-reservations/page.jsx new file mode 100644 index 0000000000000000000000000000000000000000..dad62827148adc8baab320c3d5100d80232fbdc5 --- /dev/null +++ b/src/app/(dashboard)/consultation-reservations/page.jsx @@ -0,0 +1,282 @@ +'use client' + +import React, { useEffect, useState } from 'react' +import ZoneUI from './ZoneUI' +import fetchRequest from '@/app/lib/fetchRequest' +import Loader from '@/components/Loader/Loader' +import { useNotification } from '@/context/NotificationContext' + +export const ReservationContext = React.createContext() + +const Reservation = () => { + const [isLoadingData, setIsLoadingData] = useState(false) + const { toggleNotification } = useNotification() + const [date, setDate] = useState({ day: null, week: null }) + const [isLoadingSelectsData, setIsLoadingSelectsData] = useState(true) + const [floors, setFloors] = useState([]) + const [projectsData, setProjectsData] = useState([]) + const [currentDateData, setCurrentDateData] = useState(null) + const [datesData, setDatesData] = useState(null) + const [bookedPlaces, setBookedPlaces] = useState([]) + const [ etages, setEtages ] = useState([]) + const [ isLoadingEtages, setIsLoadingEtages ] = useState(true) + const [ selectedEtage, setSelectedEtage ] = useState(null) + const [ zones, setZones ] = useState([]) + const [ isLoadingZones, setIsLoadingZones ] = useState(true) + const [ selectedZone, setSelectedZone ] = useState(null) + + useEffect(() => { + const getPlan = async () => { + try { + const { isSuccess, errors, data } = await fetchRequest('/zoaning/etage-zone-table-place/') + setIsLoadingSelectsData(false) + if (isSuccess) { + setFloors(data) + } else { + console.log(errors) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } catch (error) { + console.log(error) + } + } + getPlan() + }, []) + + useEffect(() => { + const getAllEtages = async () => { + try { + const { isSuccess, errors, data } = await fetchRequest('/zoaning/etages/', { method: 'GET' }) + setIsLoadingEtages(false) + if (isSuccess) { + setEtages(data) + } else { + setEtages([]) + } + } catch (error) { + setIsLoadingEtages(false) + console.log(error) + } + } + getAllEtages() + }, []) + + useEffect(() => { + if(selectedEtage){ + const concernedEtage = floors.find((element) => element.id == selectedEtage) + setZones(concernedEtage.zones) + } + }, [selectedEtage]) + + console.log(floors) + console.log("selectedEtage", selectedEtage) + console.log("zones", zones) + + + useEffect(() => { + const getSyncData = async () => { + const getUserPlan = async () => { + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/projects-zones-places/${date.week}/${date.day}`) + if (isSuccess) { + setProjectsData(data) + } else { + console.log(errors) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + const getBookedPlaces = async () => { + const { isSuccess, errors, data } = await fetchRequest(`/zoaning/reservations/date/${date.date}/`) + if (isSuccess) { + console.log("booked places : :", data) + setBookedPlaces(data.map((element) => ({ ...element, id_place: element.id_place.id, presence: element.presence, id_user: element.id_user.id, created_at: element.created_at, first_name: element.id_user.first_name, last_name: element.id_user.last_name, role: element.id_user.role.name }))) + } + else { + console.log(errors) + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + setIsLoadingData(true) + await Promise.all([getUserPlan(), getBookedPlaces()]) + setIsLoadingData(false) + } + if (date.week && date.day) getSyncData() + else { + setProjectsData([]) + setBookedPlaces([]) + } + + }, [date.week, date.day]) + + useEffect(() => { + const getCurrentDateData = async () => { + const { isSuccess, errors, data } = await fetchRequest('/zoaning/current-date/'); + if (isSuccess) { + setCurrentDateData(data) + } else { + toggleNotification({ + visible: true, + message: "Failed to fetch current date", + type: "error" + }) + } + } + const YearCalendar = async () => { + const { isSuccess, errors, data } = await fetchRequest('/zoaning/dates/'); + if (isSuccess) { + console.log("dates data", data) + setDatesData(data) + } else { + console.log(errors) + toggleNotification({ + visible: true, + message: "Failed to fetch current date", + type: "error" + }) + } + } + const getSyncData = async () => { + await Promise.all([getCurrentDateData(), YearCalendar()]) + } + getSyncData() + }, []) + + const handleChangeDate = (event) => { + if (event.target.value) { + const dateSelected = JSON.parse(event.target.value); + console.log("weekMonthly", dateSelected.weekMonthly); + console.log("day", dateSelected.day); + setDate({ day: dateSelected.day, week: dateSelected.weekMonthly, date: dateSelected.date }) + setSelectedEtage(null) + setSelectedZone(null) + } + else { + setDate({ day: null, week: null }) + setSelectedEtage(null) + } + } + + const handleChangeEtage = (event) =>{ + const etage_id = event.target.value + if(selectedEtage !== etage_id){ + setSelectedEtage(etage_id) + setSelectedZone(null) + setSelectedZone(null) + + } + } + + const handleChangeZone = (event) =>{ + const zone_id = event.target.value + if(selectedZone !== zone_id){ + setSelectedZone(zone_id) + } + } + + const concernedZones = projectsData?.map((element) => element.zones.map((zone) => zone.id)).flatMap((element) => element) || [] + const concernedFloors = floors?.filter((element) => element.zones.map((zone) => zone.id).some((element) => concernedZones.includes(element))).map(element => element.id) || [] + const allPlaces = projectsData?.map((project) => project.zones.map((zone) => zone.places.map((place) => ({ ...place, project_name: project.project_name, project_id: project.project_id })))).flat(2) || [] + if (isLoadingSelectsData) + return
+ +
+ + const currentMonth = new Date().getMonth() + 1 + // filter dates from now to 2 weeks later + const filteredDatesData = datesData?.filter((element) => { + const date = new Date(element.date) + const month = date.getMonth() + 1 + return (month === currentMonth) && (date.getDate() >= new Date().getDate() && date.getDate() <= new Date().getDate() + 14) + }) + + return ( +
+
+ + + +
+ {(!isLoadingData) + ? <> +
+ + { + (selectedEtage) ? + floors.filter((element) => + {if (concernedFloors.includes(element.id) && element.id == selectedEtage) {return element}} + ).map((floor) => { + return
+

Etage {floor.numero}

+ {(selectedZone)? + floor.zones.filter((element) => + {if (concernedZones.includes(element.id) && element.id == selectedZone) {return element}} + ).map((zone, index) => { + return + }) + : + floor.zones.filter((element) => concernedZones.includes(element.id)).map((zone, index) => { + return + }) + } +
+ }) + : + floors.filter((element) => concernedFloors.includes(element.id)).map((floor) => { + return
+

Etage {floor.numero}

+ {floor.zones.filter((element) => concernedZones.includes(element.id)).map((zone, index) => { + return + })} +
+ }) + } + {floors.filter((element) => concernedFloors.includes(element.id)).length === 0 + &&
+

Un exemple d'un message à l'utilisateur

+
} +
+
+ + :
+ +
+ } +
+ ) +} + +export default Reservation \ No newline at end of file diff --git a/src/app/(dashboard)/etage/AddEtageComponent.jsx b/src/app/(dashboard)/etage/AddEtageComponent.jsx index 42cfdcaca0e4ebc0d9a637b119290c15672a0543..aaf361f797a0a86cf95d9f66d384a46cf468b1c5 100644 --- a/src/app/(dashboard)/etage/AddEtageComponent.jsx +++ b/src/app/(dashboard)/etage/AddEtageComponent.jsx @@ -56,16 +56,13 @@ const AddEtageComponent = ({ etagesState }) => { } return ( -
-
- Nouveau étage: -
- -
- +
+ Nouveau étage: +
+
+
- ) } diff --git a/src/app/(dashboard)/etage/page.jsx b/src/app/(dashboard)/etage/page.jsx index ca6ba133d7e0f10a017ac734590659543769a18f..9d69312dc9f14e1af2e1c403ce13ba840f0006b1 100644 --- a/src/app/(dashboard)/etage/page.jsx +++ b/src/app/(dashboard)/etage/page.jsx @@ -80,8 +80,8 @@ const Etage = () => { }; return ( -
-
+
+

Liste des étages

@@ -108,7 +108,9 @@ const Etage = () => { }
- +
+ +
{ - const { allPlaces, selectedDate, bookedPlaces, setBookedPlaces } = useContext(ReservationContext) + const { allPlaces, selectedDate, bookedPlaces, setBookedPlaces, authenticatedUserData, hasPlace } = useContext(ReservationContext) const { toggleNotification } = useNotification() const [isOpenBooking, setIsOpenBooking] = useState(false) const [isOpenCanceling, setIsOpenCanceling] = useState(false) - const [authenticatedUserData, setAuthenticatedUserData] = useState(null) - const cookie = Cookies.get("session") - const getUserData = async () => { - try { - if (cookie) { - const data = await decrypt(cookie) - setAuthenticatedUserData(data) - } - } catch (error) { - console.log(error) - } - } - useMemo(getUserData, [cookie]) const place = allPlaces?.find((place) => place.id === id) const bookedPlace = bookedPlaces?.find((bookedPlace) => bookedPlace.id_place === id) - const hasPlace = bookedPlaces?.some((p) => p.id_user === authenticatedUserData?.sessionData?.user_id) + console.log(hasPlace); const handleBooking = (event) => { event.stopPropagation() + if (hasPlace && hasPlace.presence) return; if (hasPlace) { toggleNotification({ visible: true, @@ -121,7 +107,7 @@ const PlaceUI = ({ id }) => { if (place) if (bookedPlace) if (bookedPlace.id_user === authenticatedUserData.sessionData?.user_id) - return
+ return
{ }} className={`${bookedPlace.presence ? "bg-green-500/80" : "bg-amber-500/80 cursor-pointer"} absolute items-center flex justify-center h-full px-[2px] w-full text-sm`}>

{place.project_name || ""}

handleCancelingConfirmation(bookedPlace.id)} onClose={closeCancelingPopup} />
diff --git a/src/app/(dashboard)/reservation/PresenceButton.jsx b/src/app/(dashboard)/reservation/PresenceButton.jsx new file mode 100644 index 0000000000000000000000000000000000000000..ae586779712c63922b807b1025dd52d959a1edba --- /dev/null +++ b/src/app/(dashboard)/reservation/PresenceButton.jsx @@ -0,0 +1,105 @@ +"use client" +import fetchRequest from '@/app/lib/fetchRequest' +import Loader from '@/components/Loader/Loader' +import { useNotification } from '@/context/NotificationContext' +import React, { useContext, useEffect, useState } from 'react' +import { ReservationContext } from './page' + +const PresenceButton = ({ processUserLocation, geolocationError, isInside }) => { + const { toggleNotification } = useNotification() + const [isLoading, setIsLoading] = useState(false) + const { setBookedPlaces, hasPlace } = useContext(ReservationContext) + const handlePresenceSave = async () => { + if (hasPlace) { + setIsLoading(true) + const { isSuccess, errors, data, status } = await fetchRequest(`/zoaning/reservations/${hasPlace.id}/`, { + method: "PATCH", + body: JSON.stringify({ presence: true }) + }) + setIsLoading(false) + if (isSuccess) { + toggleNotification({ + visible: true, + message: "Votre présence a été enregistrée avec succès.", + type: "success" + }) + console.log(data) + setBookedPlaces((elements) => elements.map((element) => element.id === data.data?.id ? data.data : element)) + } + else { + console.log(errors) + if (status === 404) + toggleNotification({ + visible: true, + message: "Aucune réservation existe dans cette date.", + type: "warning" + }) + else + toggleNotification({ + visible: true, + message: "Internal Server Error", + type: "error" + }) + } + } + } + useEffect(() => { + if ("User denied the request for Geolocation." === geolocationError) { + toggleNotification({ + visible: true, + message: "Vous devez activer la géolocalisation pour enregistrer la présence", + type: "warning" + }) + } + else if (geolocationError === "The request to get user location timed out.") { + toggleNotification({ + visible: true, + message: "Vous devez activer la géolocalisation pour enregistrer la présence", + type: "warning" + }) + } + else if (geolocationError === "Location information is unavailable.") { + toggleNotification({ + visible: true, + message: "Erreur de géolocation", + type: "error" + }) + } + }, [geolocationError]) + + + if ("User denied the request for Geolocation." === geolocationError) { + return
+

Autorisez la géolocalisation pour enregistrer votre présence

+ +
+ } + else if (geolocationError === "The request to get user location timed out.") { + return
+

Autorisez la géolocalisation pour enregistrer votre présence

+ +
+ } + else if (geolocationError === "Location information is unavailable.") { + return + } + else if (isInside) + return + else return
+

Vous n'êtes pas géolocalisé à l'intérieur de Teamwill.

+ +
+} + + +export default PresenceButton \ No newline at end of file diff --git a/src/app/(dashboard)/reservation/page.jsx b/src/app/(dashboard)/reservation/page.jsx index 37921d1a0f944967bd26d7a1809c4ddb1d6f247d..e899e4013740ae504b09becab751d6e3c1cc1b2e 100644 --- a/src/app/(dashboard)/reservation/page.jsx +++ b/src/app/(dashboard)/reservation/page.jsx @@ -1,10 +1,13 @@ 'use client' -import React, { useEffect, useState } from 'react' +import React, { useEffect, useState, useMemo } from 'react' import ZoneUI from './ZoneUI' import fetchRequest from '@/app/lib/fetchRequest' import Loader from '@/components/Loader/Loader' import { useNotification } from '@/context/NotificationContext' +import PresenceButton from './PresenceButton' +import Cookies from 'js-cookie'; +import { decrypt } from '@/app/lib/session'; export const ReservationContext = React.createContext() @@ -18,6 +21,115 @@ const Reservation = () => { const [currentDateData, setCurrentDateData] = useState(null) const [datesData, setDatesData] = useState(null) const [bookedPlaces, setBookedPlaces] = useState([]) + const [isInside, setIsInside] = useState(null) + const [geolocationError, setGeolocationError] = useState(null) + + const [authenticatedUserData, setAuthenticatedUserData] = useState(null) + + const cookie = Cookies.get("session") + const getUserData = async () => { + try { + if (cookie) { + const data = await decrypt(cookie) + setAuthenticatedUserData(data) + } + } catch (error) { + console.log(error) + } + } + useMemo(getUserData, [cookie]) + + const processUserLocation = () => { + const companyLatitude = 36.8402141; // Example: Company's latitude + const companyLongitude = 10.2432573; // Example: Company's longitude + const allowedRadius = 400; // Example: Radius in meters + + + function getDistanceFromLatLonInMeters(lat1, lon1, lat2, lon2) { + const R = 6371000; // Radius of the Earth in meters + const dLat = (lat2 - lat1) * Math.PI / 180; + const dLon = (lon2 - lon1) * Math.PI / 180; + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + const distance = R * c; // Distance in meters + return distance; + } + + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + function (position) { + const userLatitude = position.coords.latitude; + const userLongitude = position.coords.longitude; + + const distance = getDistanceFromLatLonInMeters( + userLatitude, + userLongitude, + companyLatitude, + companyLongitude + ); + + if (distance <= allowedRadius) { + setIsInside(true) + } else { + setIsInside(false) + } + setGeolocationError(null) + }, + function (error) { + switch (error.code) { + case error.PERMISSION_DENIED: + setGeolocationError("User denied the request for Geolocation."); + break; + case error.POSITION_UNAVAILABLE: + setGeolocationError("Location information is unavailable."); + break; + case error.TIMEOUT: + setGeolocationError("The request to get user location timed out."); + break; + case error.UNKNOWN_ERROR: + setGeolocationError("An unknown error occurred."); + break; + } + } + ); + } else { + toggleNotification({ + message: "La géolocalisation n'est pas supporté par votre navigateur.", + type: "warning", + visible: true + }) + } + } + + + useEffect(() => { + const handlePermissionChange = (permissionStatus) => { + if (permissionStatus.state === 'granted' || permissionStatus.state === 'prompt') { + processUserLocation(); + } else { + setGeolocationError("User denied the request for Geolocation."); + } + }; + + navigator.permissions.query({ name: 'geolocation' }).then((permissionStatus) => { + handlePermissionChange(permissionStatus); + + permissionStatus.onchange = () => { + handlePermissionChange(permissionStatus); + }; + }).catch((error) => { + console.error('Failed to query geolocation permission:', error); + }); + return () => { + navigator.permissions.query({ name: 'geolocation' }).then((permissionStatus) => { + permissionStatus.onchange = null; + }); + }; + }, []) + useEffect(() => { const getPlan = async () => { try { @@ -129,11 +241,12 @@ const Reservation = () => { } } - + const currentDate = new Date().toJSON()?.split("T")[0] || null const concernedZones = projectsData?.map((element) => element.zones.map((zone) => zone.id)).flatMap((element) => element) || [] const concernedFloors = floors?.filter((element) => element.zones.map((zone) => zone.id).some((element) => concernedZones.includes(element))).map(element => element.id) || [] const allPlaces = projectsData?.map((project) => project.zones.map((zone) => zone.places.map((place) => ({ ...place, project_name: project.project_name, project_id: project.project_id })))).flat(2) || [] - console.log("all places", allPlaces) + const hasPlace = bookedPlaces?.find((p) => p.id_user === authenticatedUserData?.sessionData?.user_id) + if (isLoadingSelectsData) return
@@ -181,14 +294,13 @@ const Reservation = () => {
{(!isLoadingData) - ? <> - {(floors.filter((element) => concernedFloors.includes(element.id))?.length > 0) &&
- -
} -
- + ? + + <> + {(floors.filter((element) => concernedFloors.includes(element.id))?.length > 0 && hasPlace && currentDate && currentDate === date?.date) &&
+ +
} +
{floors.filter((element) => concernedFloors.includes(element.id)).map((floor) => { return

Etage {floor.numero}

@@ -201,9 +313,9 @@ const Reservation = () => { &&

Un exemple d'un message à l'utilisateur

} - -
- + +
+
:
diff --git a/src/app/(dashboard)/role/RoleTableRows.jsx b/src/app/(dashboard)/role/RoleTableRows.jsx index 89fcaa45b8e4eaf4466e9d033513258e420b7d66..ccdcad936b6b9f077fc3ac86eb584d85d919d691 100644 --- a/src/app/(dashboard)/role/RoleTableRows.jsx +++ b/src/app/(dashboard)/role/RoleTableRows.jsx @@ -57,6 +57,7 @@ const RoleTableRows = ({ name, setRoles, id, privileges, setRoleToUpdate }) => { {privileges?.map((element, index) => { return
{element.name}
})} + {!privileges || privileges.length == 0 &&

-

}
diff --git a/src/app/auth/login/page.jsx b/src/app/auth/login/page.jsx index e94f196d34238d6f6324f5d3754292a44943a1b0..1bacbee6cc9ee5c10cc33b397a68e90a104341bb 100644 --- a/src/app/auth/login/page.jsx +++ b/src/app/auth/login/page.jsx @@ -33,7 +33,7 @@ const LoginPage = () => { setMessages(data.non_field_errors[0]); } else { await createSession(data); - window.location.href = '/auth/verif'; + window.location.href = '/reservation'; } } catch (error) { setMessages('An error occurred'); diff --git a/src/app/globals.css b/src/app/globals.css index 20a77109e6c82197c14a84e414576d61c368ee32..771e450dc11a6f30e40dc71e7777819d498bae59 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -201,4 +201,12 @@ width: 0; transition-duration: 300ms } +} + +.tooltip { + @apply invisible absolute; +} + +.has-tooltip:hover .tooltip { + @apply visible z-50; } \ No newline at end of file diff --git a/src/app/ui/LogoutButton.js b/src/app/ui/LogoutButton.js index 1ffc0e4cc4a99298add62338c87fc0d13d1bb173..5dbae382baf8dfc354588a2009ce49f896e79ce3 100644 --- a/src/app/ui/LogoutButton.js +++ b/src/app/ui/LogoutButton.js @@ -3,30 +3,30 @@ import Cookies from 'js-cookie'; import fetchRequest from "@/app/lib/fetchRequest"; import LogoutIcon from "@/static/image/svg/logout.svg" -const LogoutButton = ({ isButton = false }) => { + +const LogoutButton = ({isButton = false}) => { const logout = async () => { const response = await fetchRequest(`/logout`, { method: 'GET' }); console.log(response); - if (response.isSuccess) { - console.log('logout successful'); - Cookies.remove('session'); - window.location.href = '/'; - } + console.log('logout successful'); + Cookies.remove('session'); + window.location.href = '/auth/login'; }; if (isButton) return
-
-

+

+

Se déconnecter

return ( ); }; diff --git a/src/app/ui/SideBar.jsx b/src/app/ui/SideBar.jsx index 4bab50a6d919bff0a44c48f3424867953bd6e4b7..ea865170eeccb546aa47e8fb7766be5ea730860b 100644 --- a/src/app/ui/SideBar.jsx +++ b/src/app/ui/SideBar.jsx @@ -30,24 +30,14 @@ const SideBar = () => { link: "/reservation", icon: }, - { - label: "Planning", - link: "/planning" - , icon: - }, { label: "Type de Presence", link: "/planning/type-presence" , icon: }, { - label: "Tables", - link: "/table" - , icon: - }, - { - label: "Places", - link: "/place" + label: "Planning", + link: "/planning" , icon: }, { @@ -60,11 +50,26 @@ const SideBar = () => { link: "/zone" , icon: }, + { + label: "Tables", + link: "/table" + , icon: + }, + { + label: "Places", + link: "/place" + , icon: + }, { label: "Gestion des zones", link: "/assign_zone_project" , icon: }, + { + label: "Consulter les réservations", + link: "/consultation-reservations" + , icon: + }, ] return (