+import axios from 'axios';
+import { isEqual } from 'lodash';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const context = React.createContext({
+ login: () => false,
+ logout: () => false,
+ user: null,
+});
+
+export const useUser = () => React.useContext(context);
+
+export const withUser = (WrappedComponent, as) => function WithUserContext(props) {
+ return <context.Consumer>
+ {user => <WrappedComponent {...{[as || 'user']: user, ...props}} />}
+ </context.Consumer>;
+};
+
+export const UserProvider = ({ children }) => {
+ const [user, setUser] = React.useState(null);
+
+ const fetchUser = React.useCallback(async () => {
+ try {
+ const response = await axios.get('/api/user');
+ setUser(user => isEqual(user, response.data) ? user : response.data);
+ } catch (e) {
+ setUser(null);
+ }
+ }, []);
+
+ React.useEffect(() => {
+ let timer = null;
+ axios
+ .get('/sanctum/csrf-cookie')
+ .then(() => {
+ fetchUser();
+ timer = setInterval(fetchUser, 5 * 60 * 1000);
+ });
+ return () => {
+ if (timer) clearInterval(timer);
+ };
+ }, []);
+
+ const login = React.useCallback(async (creds) => {
+ try {
+ await axios.post('/login', {
+ ...creds,
+ remember: 'on',
+ });
+ await fetchUser();
+ } catch (error) {
+ if (error.response && error.response.status === 419) {
+ await axios.get('/sanctum/csrf-cookie');
+ await axios.post('/login', {
+ ...creds,
+ remember: 'on',
+ });
+ await fetchUser();
+ } else {
+ throw error;
+ }
+ }
+ }, []);
+
+ const logout = React.useCallback(async () => {
+ await axios.post('/logout');
+ setUser(null);
+ }, []);
+
+ return <context.Provider value={{ login, logout, user }}>
+ {children}
+ </context.Provider>;
+};
+
+UserProvider.propTypes = {
+ children: PropTypes.node,
+};