+ 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) &&
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
-
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 (
|