import { ActionTree } from "vuex"; import { Actions } from "./generics"; import { IState } from "./state"; import { Mutation, MutationsTypes } from "./mutations"; import router from "../routes"; import { GettersTypes } from "./getters"; // Payload types type IAuthenticatePayload = { email: string, password: string, remember: boolean }; type IAuthenticateResult = { email?: string[], password?: string[] } | null; type IAuthFetchPayload = { path: string, options?: RequestInit }; /** * The available actions te perform */ export enum Action { // Authentication AuthAuthenticate = "AUTH_AUTHENTICATE", AuthForget = "AUHT_FORGET", AuthLoad = "AUTH_LOAD", // RESTful AuthFetch = "AUTH_FETCH" } /** * The action function signatures */ export type ActionsTypes = { // Authentication [Action.AuthAuthenticate]: (payload: IAuthenticatePayload) => Promise, [Action.AuthForget] : () => void, [Action.AuthLoad] : () => boolean // RESTful [Action.AuthFetch]: (payload: IAuthFetchPayload) => Promise } /** * The action function implementations */ export const actions: Actions & ActionTree = { // Authentication ------------------------------------------------------------------------------ /** * Authenticate the credentials of a user and log them in */ [Action.AuthAuthenticate]({commit, dispatch}, {email, password, remember = false}) { return new Promise((resolve, reject) => { fetch(`/auth/login?use_cookies=${navigator.cookieEnabled}`, { method: "post", headers: { "Content-Type": "application/json" }, body: JSON.stringify({email, password}) }) .then(async response => { let body = await response.json(); if (response.status !== 200) { if (response.status === 401) { body.errors = { "email": [ "Email or password is incorrect" ] }; } resolve(body.errors || {}); return; } commit(Mutation.LoadUser, body.token); commit(Mutation.StoreUser, remember); resolve(null); }) .catch(e => { console.error("Error occurred during submission:", e); reject(e); }); }); }, /** * Forget the login token and log the user out */ [Action.AuthForget]({commit}) { commit(Mutation.ForgetUser, undefined); }, /** * Load the user from local storage */ [Action.AuthLoad]({getters, commit, dispatch}) { let token = getters.storedToken; if (!token) { return false; } try { commit(Mutation.LoadUser, token); } catch(e) { dispatch(Action.AuthForget, undefined); return false; } return true; }, // RESTful ------------------------------------------------------------------------------------- /** * Fetch request providing authentication and logout upon unauthorized requests */ async [Action.AuthFetch]({commit, state}, {path, options = {}}) { if (state.user == null) { router.push({ name: "Login" }); throw Error("Unauthorized"); } options.credentials = "include"; options.headers = Object.assign(options.headers ?? {}, { "Authorization": `Bearer ${state.user.token}` }); let response = await fetch(path, options); if (response.status === 401) { commit(Mutation.ForgetUser, undefined); router.push({ name: "Login" }); throw Error("Unauthorized"); } return response; } };