ConceptPortal-public/rsconcept/frontend/src/context/AuthContext.tsx

110 lines
3.0 KiB
TypeScript
Raw Normal View History

2023-07-25 20:27:29 +03:00
import { createContext, useCallback, useContext, useLayoutEffect, useState } from 'react';
2023-07-15 17:46:19 +03:00
2023-07-25 20:27:29 +03:00
import { type ErrorInfo } from '../components/BackendError';
import useLocalStorage from '../hooks/useLocalStorage';
import { type BackendCallback, getAuth, postLogin, postLogout, postSignup } from '../utils/backendAPI';
import { type ICurrentUser, type IUserSignupData } from '../utils/models';
2023-07-15 17:46:19 +03:00
interface IAuthContext {
user: ICurrentUser | undefined
2023-07-25 20:27:29 +03:00
login: (username: string, password: string, callback?: BackendCallback) => void
logout: (callback?: BackendCallback) => void
signup: (data: IUserSignupData, callback?: BackendCallback) => void
2023-07-15 17:46:19 +03:00
loading: boolean
error: ErrorInfo
setError: (error: ErrorInfo) => void
}
const AuthContext = createContext<IAuthContext | null>(null);
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error(
'useAuth has to be used within <AuthState.Provider>'
);
}
return context;
}
2023-07-15 17:46:19 +03:00
interface AuthStateProps {
children: React.ReactNode
}
export const AuthState = ({ children }: AuthStateProps) => {
const [user, setUser] = useLocalStorage<ICurrentUser | undefined>('user', undefined);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<ErrorInfo>(undefined);
const loadCurrentUser = useCallback(
async () => {
2023-07-25 20:27:29 +03:00
await getAuth({
onError: () => { setUser(undefined); },
2023-07-26 10:59:55 +03:00
onSuccess: response => {
if (response.data.id) {
setUser(response.data);
} else {
setUser(undefined)
}
2023-07-15 17:46:19 +03:00
}
});
}, [setUser]
);
2023-07-25 20:27:29 +03:00
function login(uname: string, pw: string, callback?: BackendCallback) {
2023-07-15 17:46:19 +03:00
setError(undefined);
postLogin({
2023-07-25 20:27:29 +03:00
data: { username: uname, password: pw },
showError: true,
2023-07-25 20:27:29 +03:00
setLoading,
onError: error => { setError(error); },
2023-07-26 10:59:55 +03:00
onSuccess:
2023-07-25 20:27:29 +03:00
(response) => {
loadCurrentUser()
.then(() => { if (callback) callback(response); })
.catch(console.error);
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
}).catch(console.error);
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
function logout(callback?: BackendCallback) {
2023-07-15 17:46:19 +03:00
setError(undefined);
postLogout({
showError: true,
2023-07-26 10:59:55 +03:00
onSuccess:
2023-07-25 20:27:29 +03:00
(response) => {
loadCurrentUser()
.then(() => { if (callback) callback(response); })
.catch(console.error);
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
}).catch(console.error);
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
function signup(data: IUserSignupData, callback?: BackendCallback) {
2023-07-15 17:46:19 +03:00
setError(undefined);
postSignup({
2023-07-25 20:27:29 +03:00
data,
showError: true,
2023-07-25 20:27:29 +03:00
setLoading,
onError: error => { setError(error); },
2023-07-26 10:59:55 +03:00
onSuccess:
2023-07-25 20:27:29 +03:00
(response) => {
loadCurrentUser()
.then(() => { if (callback) callback(response); })
.catch(console.error);
2023-07-15 17:46:19 +03:00
}
2023-07-25 20:27:29 +03:00
}).catch(console.error);
2023-07-15 17:46:19 +03:00
}
useLayoutEffect(() => {
2023-07-25 20:27:29 +03:00
loadCurrentUser().catch(console.error);
2023-07-15 17:46:19 +03:00
}, [loadCurrentUser])
return (
<AuthContext.Provider
value={{ user, login, logout, signup, loading, error, setError }}
>
{children}
</AuthContext.Provider>
);
2023-07-25 20:27:29 +03:00
};