mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Ajout d'une fonction de logout
This commit is contained in:
@ -15,6 +15,7 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import DropdownMenu from '@/components/DropdownMenu';
|
import DropdownMenu from '@/components/DropdownMenu';
|
||||||
import Logo from '@/components/Logo';
|
import Logo from '@/components/Logo';
|
||||||
|
import Popup from '@/components/Popup';
|
||||||
import {
|
import {
|
||||||
FE_ADMIN_HOME_URL,
|
FE_ADMIN_HOME_URL,
|
||||||
FE_ADMIN_SUBSCRIPTIONS_URL,
|
FE_ADMIN_SUBSCRIPTIONS_URL,
|
||||||
@ -45,6 +46,7 @@ export default function Layout({
|
|||||||
|
|
||||||
const [establishment, setEstablishment] = useState(null);
|
const [establishment, setEstablishment] = useState(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
||||||
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const currentPage = pathname.split('/').pop();
|
const currentPage = pathname.split('/').pop();
|
||||||
@ -54,11 +56,19 @@ export default function Layout({
|
|||||||
const softwareName = "N3WT School";
|
const softwareName = "N3WT School";
|
||||||
const softwareVersion = `v${process.env.NEXT_PUBLIC_APP_VERSION}`;
|
const softwareVersion = `v${process.env.NEXT_PUBLIC_APP_VERSION}`;
|
||||||
|
|
||||||
|
const handleDisconnect = () => {
|
||||||
|
setIsPopupVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmDisconnect = () => {
|
||||||
|
setIsPopupVisible(false);
|
||||||
|
disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
const dropdownItems = [
|
const dropdownItems = [
|
||||||
{
|
{
|
||||||
label: 'Déconnexion',
|
label: 'Déconnexion',
|
||||||
onClick: disconnect,
|
onClick: handleDisconnect,
|
||||||
icon: LogOut,
|
icon: LogOut,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -74,8 +84,6 @@ export default function Layout({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
|
|
||||||
<SessionProvider>
|
<SessionProvider>
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
@ -110,10 +118,14 @@ export default function Layout({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<Popup
|
||||||
|
visible={isPopupVisible}
|
||||||
|
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
|
||||||
|
onConfirm={confirmDisconnect}
|
||||||
|
onCancel={() => setIsPopupVisible(false)}
|
||||||
|
/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,7 @@ import {
|
|||||||
import DjangoCSRFToken from '@/components/DjangoCSRFToken'
|
import DjangoCSRFToken from '@/components/DjangoCSRFToken'
|
||||||
import { useCsrfToken } from '@/context/CsrfContext';
|
import { useCsrfToken } from '@/context/CsrfContext';
|
||||||
import { fetchRegistrationFileGroups } from '@/app/lib/registerFileGroupAction';
|
import { fetchRegistrationFileGroups } from '@/app/lib/registerFileGroupAction';
|
||||||
|
import { ESTABLISHMENT_ID } from '@/utils/Url';
|
||||||
|
|
||||||
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
|
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
|
||||||
|
|
||||||
@ -371,7 +372,8 @@ useEffect(()=>{
|
|||||||
idGuardians: selectedGuardiansIds,
|
idGuardians: selectedGuardiansIds,
|
||||||
fees: allFeesIds,
|
fees: allFeesIds,
|
||||||
discounts: allDiscountsds,
|
discounts: allDiscountsds,
|
||||||
fileGroup: selectedFileGroup
|
fileGroup: selectedFileGroup,
|
||||||
|
establishment: ESTABLISHMENT_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
createRegisterForm(data, csrfToken)
|
createRegisterForm(data, csrfToken)
|
||||||
@ -413,7 +415,8 @@ useEffect(()=>{
|
|||||||
sibling: []
|
sibling: []
|
||||||
},
|
},
|
||||||
fees: allFeesIds,
|
fees: allFeesIds,
|
||||||
discounts: allDiscountsds
|
discounts: allDiscountsds,
|
||||||
|
establishment: ESTABLISHMENT_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
createRegisterForm(data, csrfToken)
|
createRegisterForm(data, csrfToken)
|
||||||
|
|||||||
@ -9,6 +9,9 @@ import { FE_PARENTS_HOME_URL,FE_PARENTS_MESSAGERIE_URL,FE_PARENTS_SETTINGS_URL
|
|||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import { fetchMessages } from '@/app/lib/messagerieAction';
|
import { fetchMessages } from '@/app/lib/messagerieAction';
|
||||||
import ProtectedRoute from '@/components/ProtectedRoute';
|
import ProtectedRoute from '@/components/ProtectedRoute';
|
||||||
|
import { SessionProvider } from 'next-auth/react';
|
||||||
|
import { disconnect } from '@/app/lib/authAction';
|
||||||
|
import Popup from '@/components/Popup';
|
||||||
|
|
||||||
export default function Layout({
|
export default function Layout({
|
||||||
children,
|
children,
|
||||||
@ -18,6 +21,16 @@ export default function Layout({
|
|||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const [userId, setUserId] = useLocalStorage("userId", '') ;
|
const [userId, setUserId] = useLocalStorage("userId", '') ;
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [isPopupVisible, setIsPopupVisible] = useState(false);
|
||||||
|
|
||||||
|
const handleDisconnect = () => {
|
||||||
|
setIsPopupVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmDisconnect = () => {
|
||||||
|
setIsPopupVisible(false);
|
||||||
|
disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -42,6 +55,7 @@ export default function Layout({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<SessionProvider>
|
||||||
<ProtectedRoute>
|
<ProtectedRoute>
|
||||||
<div className="flex flex-col min-h-screen bg-gray-50">
|
<div className="flex flex-col min-h-screen bg-gray-50">
|
||||||
{/* Entête */}
|
{/* Entête */}
|
||||||
@ -75,7 +89,7 @@ export default function Layout({
|
|||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
buttonContent={<User />}
|
buttonContent={<User />}
|
||||||
items={[
|
items={[
|
||||||
{ label: 'Se déconnecter', icon: LogOut, onClick: () => {} },
|
{ label: 'Se déconnecter', icon: LogOut, onClick: handleDisconnect },
|
||||||
{ label: 'Settings', icon: Settings , onClick: () => { router.push(FE_PARENTS_SETTINGS_URL); } }
|
{ label: 'Settings', icon: Settings , onClick: () => { router.push(FE_PARENTS_SETTINGS_URL); } }
|
||||||
]}
|
]}
|
||||||
buttonClassName="p-2 rounded-full hover:bg-gray-200"
|
buttonClassName="p-2 rounded-full hover:bg-gray-200"
|
||||||
@ -90,7 +104,14 @@ export default function Layout({
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Popup
|
||||||
|
visible={isPopupVisible}
|
||||||
|
message="Êtes-vous sûr(e) de vouloir vous déconnecter ?"
|
||||||
|
onConfirm={confirmDisconnect}
|
||||||
|
onCancel={() => setIsPopupVisible(false)}
|
||||||
|
/>
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
|
</SessionProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ export default function Page() {
|
|||||||
return data.errorMessage === ""
|
return data.errorMessage === ""
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFormLogin(formData) {
|
/*async function handleFormLogin(formData) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -76,6 +76,51 @@ export default function Page() {
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setErrorMessage('An error occurred during sign in.');
|
setErrorMessage('An error occurred during sign in.');
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
function handleFormLogin(formData) {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
signIn('credentials', {
|
||||||
|
redirect: false,
|
||||||
|
email: formData.get('login'),
|
||||||
|
password: formData.get('password'),
|
||||||
|
}).then(result => {
|
||||||
|
console.log('Sign In Result', result);
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
setErrorMessage(result.error);
|
||||||
|
} else {
|
||||||
|
getSession().then(session => {
|
||||||
|
if (!session || !session.user) {
|
||||||
|
throw new Error('Session not found');
|
||||||
|
}
|
||||||
|
const user = session.user;
|
||||||
|
console.log('User Session:', user);
|
||||||
|
localStorage.setItem('userId', user.id); // Stocker l'identifiant de l'utilisateur
|
||||||
|
if (user.droit === 0) {
|
||||||
|
// Vue ECOLE
|
||||||
|
} else if (user.droit === 1) {
|
||||||
|
// Vue ADMIN
|
||||||
|
router.push(FE_ADMIN_SUBSCRIPTIONS_URL);
|
||||||
|
} else if (user.droit === 2) {
|
||||||
|
// Vue PARENT
|
||||||
|
router.push(FE_PARENTS_HOME_URL);
|
||||||
|
} else {
|
||||||
|
// Cas anormal
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Error during session retrieval:', error);
|
||||||
|
setIsLoading(false);
|
||||||
|
setErrorMessage('An error occurred during session retrieval.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Error during sign in:', error);
|
||||||
|
setIsLoading(false);
|
||||||
|
setErrorMessage('An error occurred during sign in.');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoading === true) {
|
if (isLoading === true) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
|
import { signOut } from 'next-auth/react';
|
||||||
import {
|
import {
|
||||||
BE_AUTH_LOGIN_URL,
|
BE_AUTH_LOGIN_URL,
|
||||||
BE_AUTH_REGISTER_URL,
|
BE_AUTH_REGISTER_URL,
|
||||||
@ -8,25 +8,17 @@ import {
|
|||||||
FE_USERS_LOGIN_URL,
|
FE_USERS_LOGIN_URL,
|
||||||
} from '@/utils/Url';
|
} from '@/utils/Url';
|
||||||
|
|
||||||
import {mockUser} from "@/data/mockUsersData";
|
|
||||||
|
|
||||||
const useFakeData = process.env.NEXT_PUBLIC_USE_FAKE_DATA === 'true';
|
|
||||||
|
|
||||||
|
|
||||||
const requestResponseHandler = async (response) => {
|
const requestResponseHandler = async (response) => {
|
||||||
|
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
// Throw an error with the JSON body containing the form errors
|
|
||||||
const error = new Error('Form submission error');
|
const error = new Error('Form submission error');
|
||||||
error.details = body;
|
error.details = body;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const login = (data, csrfToken) => {
|
/*export const login = (data, csrfToken) => {
|
||||||
console.log('data', data);
|
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
`${BE_AUTH_LOGIN_URL}`,
|
`${BE_AUTH_LOGIN_URL}`,
|
||||||
{
|
{
|
||||||
@ -39,32 +31,40 @@ export const login = (data, csrfToken) => {
|
|||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
|
};*/
|
||||||
|
|
||||||
|
export const login = (data, csrfToken) => {
|
||||||
|
const request = new Promise((resolve, reject) => {
|
||||||
|
signIn('credentials', {
|
||||||
|
redirect: false,
|
||||||
|
email: data.email,
|
||||||
|
password: data.password,
|
||||||
|
}).then(result => {
|
||||||
|
if (result.error) {
|
||||||
|
reject(new Error(result.error));
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
}
|
}
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
return request.then(requestResponseHandler);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnects the user after confirming the action.
|
* Disconnects the user after confirming the action.
|
||||||
* If `NEXT_PUBLIC_USE_FAKE_DATA` environment variable is set to 'true', it will log a fake disconnect and redirect to the login URL.
|
* If `NEXT_PUBLIC_USE_FAKE_DATA` environment variable is set to 'true', it will log a fake disconnect and redirect to the login URL.
|
||||||
* Otherwise, it will send a PUT request to the backend to update the user profile and then redirect to the login URL.
|
* Otherwise, it will call `signOut` from NextAuth.js to handle the logout.
|
||||||
*
|
*
|
||||||
* @function
|
* @function
|
||||||
* @name disconnect
|
* @name disconnect
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export const disconnect = () => {
|
export const disconnect = () => {
|
||||||
if (confirm("\nÊtes-vous sûr(e) de vouloir vous déconnecter ?")) {
|
signOut({ callbackUrl: FE_USERS_LOGIN_URL });
|
||||||
|
|
||||||
if (useFakeData) {
|
|
||||||
console.log('Fake disconnect:', mockUser);
|
|
||||||
router.push(`${FE_USERS_LOGIN_URL}`);
|
|
||||||
} else {
|
|
||||||
console.log('Fake disconnect:', mockUser);
|
|
||||||
router.push(`${FE_USERS_LOGIN_URL}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const createProfile = (data, csrfToken) => {
|
export const createProfile = (data, csrfToken) => {
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
`${BE_AUTH_PROFILES_URL}`,
|
`${BE_AUTH_PROFILES_URL}`,
|
||||||
@ -78,8 +78,8 @@ const request = new Request(
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const updateProfile = (id, data, csrfToken) => {
|
export const updateProfile = (id, data, csrfToken) => {
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
@ -94,11 +94,10 @@ export const updateProfile = (id, data, csrfToken) => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const sendNewPassword = (data, csrfToken) => {
|
export const sendNewPassword = (data, csrfToken) => {
|
||||||
|
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
`${BE_AUTH_NEW_PASSWORD_URL}`,
|
`${BE_AUTH_NEW_PASSWORD_URL}`,
|
||||||
{
|
{
|
||||||
@ -111,8 +110,8 @@ export const sendNewPassword = (data, csrfToken) => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const subscribe = (data, csrfToken) => {
|
export const subscribe = (data, csrfToken) => {
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
@ -127,8 +126,8 @@ export const subscribe = (data,csrfToken) =>{
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const resetPassword = (uuid, data, csrfToken) => {
|
export const resetPassword = (uuid, data, csrfToken) => {
|
||||||
const request = new Request(
|
const request = new Request(
|
||||||
@ -143,8 +142,8 @@ export const resetPassword = (uuid, data, csrfToken) => {
|
|||||||
body: JSON.stringify(data),
|
body: JSON.stringify(data),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return fetch(request).then(requestResponseHandler)
|
return fetch(request).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getResetPassword = (uuid) => {
|
export const getResetPassword = (uuid) => {
|
||||||
const url = `${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`;
|
const url = `${BE_AUTH_RESET_PASSWORD_URL}/${uuid}`;
|
||||||
@ -152,5 +151,5 @@ export const getResetPassword = (uuid) => {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
}).then(requestResponseHandler)
|
}).then(requestResponseHandler);
|
||||||
}
|
};
|
||||||
@ -40,7 +40,12 @@ const options = {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
session: {
|
session: {
|
||||||
jwt: true
|
jwt: true,
|
||||||
|
maxAge: 24 * 60 * 60, // 1 day in seconds
|
||||||
|
updateAge: 24 * 60 * 60 // Update session every day
|
||||||
|
},
|
||||||
|
jwt: {
|
||||||
|
maxAge: 24 * 60 * 60 // 1 day in seconds
|
||||||
},
|
},
|
||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({ token, user }) {
|
async jwt({ token, user }) {
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
import { signOut } from 'next-auth/react';
|
|
||||||
|
|
||||||
export default function SignOut() {
|
|
||||||
return (
|
|
||||||
<button onClick={() => signOut({ callbackUrl: '/' })}>
|
|
||||||
Sign out
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user