blob: 3bac10d8635dc07d0363f9636342335d0e13a78c [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';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000021import { useNavigate } from 'react-router-dom';
simon416d0792022-11-03 02:46:18 -040022
23import ProcessingRequest from '../components/ProcessingRequest';
24import { apiUrl } from '../utils/constants';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000025import { WithChildren } from '../utils/utils';
simon416d0792022-11-03 02:46:18 -040026
27interface IAuthContext {
28 token: string;
29 account: Account;
30 logout: () => void;
31}
32
33const AuthContext = createContext<IAuthContext | undefined>(undefined);
34
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000035export default ({ children }: WithChildren) => {
simon416d0792022-11-03 02:46:18 -040036 const [token, setToken] = useState<string | undefined>();
37 const [account, setAccount] = useState<Account | undefined>();
38 const navigate = useNavigate();
39
40 const logout = useCallback(() => {
41 localStorage.removeItem('accessToken');
42 navigate('/');
43 }, [navigate]);
44
45 useEffect(() => {
46 const accessToken = localStorage.getItem('accessToken');
47
48 if (!accessToken) {
49 console.warn('Missing authentication JWT. Redirecting to login page...');
50 logout();
51 } else {
52 setToken(accessToken);
53 }
54 }, [logout]);
55
56 useEffect(() => {
57 if (token) {
58 const getAccount = async () => {
59 const url = new URL('/account', apiUrl);
60 const response = await fetch(url, {
61 method: 'GET',
62 headers: {
63 Authorization: `Bearer ${token}`,
64 },
65 });
66
67 if (response.status === HttpStatusCode.Ok) {
68 const serializedAccount = await response.json();
69 const account = Account.from(serializedAccount);
70 setAccount(account);
71 } else {
72 throw new Error(response.statusText);
73 }
74 };
75
76 getAccount().catch((e) => {
77 console.error('Error while retrieving account: ', e);
78 logout();
79 });
80 }
81 }, [token, logout]);
82
83 if (!token || !account) {
84 return <ProcessingRequest open />;
85 }
86
87 return (
88 <AuthContext.Provider
89 value={{
90 token,
91 logout,
92 account,
93 }}
94 >
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000095 {children}
simon416d0792022-11-03 02:46:18 -040096 </AuthContext.Provider>
97 );
98};
99
100export function useAuthContext(dontThrowIfUndefined: true): IAuthContext | undefined;
101export function useAuthContext(): IAuthContext;
102export function useAuthContext(dontThrowIfUndefined?: true) {
103 const authContext = useContext(AuthContext);
104 if (!authContext && !dontThrowIfUndefined) {
105 throw new Error('AuthContext is not provided');
106 }
107 return authContext;
108}