blob: 50b1723579b54c220efd436bed3bd6c91b43371c [file] [log] [blame]
simon416d0792022-11-03 02:46:18 -04001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
18import { Account } from 'jami-web-common/dist/Account';
19import { HttpStatusCode } from 'jami-web-common/dist/enums/http-status-code';
20import { createContext, useCallback, useContext, useEffect, useState } from 'react';
21import { Outlet, useNavigate } from 'react-router-dom';
22
23import ProcessingRequest from '../components/ProcessingRequest';
24import { apiUrl } from '../utils/constants';
25
26interface IAuthContext {
27 token: string;
28 account: Account;
29 logout: () => void;
30}
31
32const AuthContext = createContext<IAuthContext | undefined>(undefined);
33
34export default () => {
35 const [token, setToken] = useState<string | undefined>();
36 const [account, setAccount] = useState<Account | undefined>();
37 const navigate = useNavigate();
38
39 const logout = useCallback(() => {
40 localStorage.removeItem('accessToken');
41 navigate('/');
42 }, [navigate]);
43
44 useEffect(() => {
45 const accessToken = localStorage.getItem('accessToken');
46
47 if (!accessToken) {
48 console.warn('Missing authentication JWT. Redirecting to login page...');
49 logout();
50 } else {
51 setToken(accessToken);
52 }
53 }, [logout]);
54
55 useEffect(() => {
56 if (token) {
57 const getAccount = async () => {
58 const url = new URL('/account', apiUrl);
59 const response = await fetch(url, {
60 method: 'GET',
61 headers: {
62 Authorization: `Bearer ${token}`,
63 },
64 });
65
66 if (response.status === HttpStatusCode.Ok) {
67 const serializedAccount = await response.json();
68 const account = Account.from(serializedAccount);
69 setAccount(account);
70 } else {
71 throw new Error(response.statusText);
72 }
73 };
74
75 getAccount().catch((e) => {
76 console.error('Error while retrieving account: ', e);
77 logout();
78 });
79 }
80 }, [token, logout]);
81
82 if (!token || !account) {
83 return <ProcessingRequest open />;
84 }
85
86 return (
87 <AuthContext.Provider
88 value={{
89 token,
90 logout,
91 account,
92 }}
93 >
94 <Outlet />
95 </AuthContext.Provider>
96 );
97};
98
99export function useAuthContext(dontThrowIfUndefined: true): IAuthContext | undefined;
100export function useAuthContext(): IAuthContext;
101export function useAuthContext(dontThrowIfUndefined?: true) {
102 const authContext = useContext(AuthContext);
103 if (!authContext && !dontThrowIfUndefined) {
104 throw new Error('AuthContext is not provided');
105 }
106 return authContext;
107}