UNPKG

vue3plate-auth-sanctum

Version:

Vue 3 authentication package for vue3plate boilerplate that integrates with Laravel Sanctum

1,122 lines (1,121 loc) 33.5 kB
import { computed as g, ref as R, resolveComponent as y, openBlock as d, createElementBlock as u, withModifiers as O, createElementVNode as s, createVNode as l, createTextVNode as _, toDisplayString as p, createCommentVNode as h, withDirectives as b, normalizeClass as v, vModelText as S, vModelDynamic as P, vModelCheckbox as D, createBlock as N, withCtx as T, renderSlot as X } from "vue"; import { useStore as Q } from "vuex"; import { useRouter as Z } from "vue-router"; import $ from "axios"; function I(a) { const e = Q(), r = Z(), o = g(() => e.getters["auth/isAuthenticated"]), n = g(() => e.getters["auth/user"]), m = g(() => e.getters["auth/token"]), t = g(() => e.getters["auth/isLoading"]), c = g(() => e.getters["auth/error"]), i = g(() => e.getters["auth/userRole"]), L = g(() => e.getters["auth/userStatus"]), A = g(() => e.getters["auth/isAdmin"]), k = g(() => e.getters["auth/isStaff"]), M = g(() => e.getters["auth/isActive"]), H = g(() => e.getters["auth/fullName"]), j = async (f) => { try { await e.dispatch("auth/login", f), r.push(a.afterLogin); } catch (x) { throw x; } }, B = async (f) => { try { await e.dispatch("auth/register", f), r.push(a.afterRegister); } catch (x) { throw x; } }, z = async () => { try { await e.dispatch("auth/logout"), r.push(a.afterLogout); } catch (f) { console.warn("Logout error:", f), r.push(a.afterLogout); } }, J = () => { e.dispatch("auth/clearError"); }, W = () => { e.dispatch("auth/initializeAuth"); }, q = (f) => i.value === f, U = (f) => f.includes(i.value), Y = (f) => !!(A.value || k.value && ["read", "update"].includes(f)), C = () => o.value ? !0 : (r.push("/login"), !1); return { // State isAuthenticated: o, user: n, token: m, isLoading: t, error: c, userRole: i, userStatus: L, isAdmin: A, isStaff: k, isActive: M, fullName: H, // Actions login: j, register: B, logout: z, clearError: J, initializeAuth: W, // Utilities hasRole: q, hasAnyRole: U, can: Y, requireAuth: C, requireGuest: () => o.value ? (r.push(a.afterLogin), !1) : !0, requireRole: (f) => C() ? q(f) ? !0 : (r.push("/unauthorized"), !1) : !1, requireAnyRole: (f) => C() ? U(f) ? !0 : (r.push("/unauthorized"), !1) : !1 }; } const E = (a, e) => { const r = a.__vccOpts || a; for (const [o, n] of e) r[o] = n; return r; }, ee = { name: "LoginForm", props: { config: { type: Object, default: () => ({}) } }, emits: ["success", "error"], setup(a, { emit: e }) { const { login: r, isLoading: o, error: n, clearError: m } = I(a.config), t = R({ email: "", password: "", remember: !1 }), c = R(!1), i = g(() => { var A; return ((A = n.value) == null ? void 0 : A.errors) || {}; }); return { form: t, showPassword: c, errors: i, isLoading: o, error: n, handleSubmit: async () => { m(); try { await r({ email: t.value.email, password: t.value.password }), e("success"); } catch (A) { e("error", A); } } }; } }, oe = { key: 0, class: "error-message" }, re = { class: "form-group" }, se = { class: "input-group" }, te = { key: 0, class: "field-error" }, ne = { class: "form-group" }, ae = { class: "input-group" }, ie = ["type"], le = { key: 0, class: "field-error" }, de = { class: "form-group" }, ue = { class: "checkbox-label" }, ce = ["disabled"], me = { class: "form-footer" }, fe = { class: "signup-prompt" }; function ge(a, e, r, o, n, m) { const t = y("font-awesome-icon"), c = y("router-link"); return d(), u("form", { onSubmit: e[4] || (e[4] = O((...i) => o.handleSubmit && o.handleSubmit(...i), ["prevent"])), class: "login-form" }, [ e[12] || (e[12] = s("div", { class: "form-header" }, [ s("h2", { class: "form-title" }, "Welcome Back"), s("p", { class: "form-subtitle" }, "Sign in to your account") ], -1)), o.error ? (d(), u("div", oe, [ l(t, { icon: "fa-solid fa-exclamation-circle" }), _(" " + p(o.error.message), 1) ])) : h("", !0), s("div", re, [ e[5] || (e[5] = s("label", { for: "email", class: "form-label" }, "Email Address", -1)), s("div", se, [ l(t, { icon: "fa-solid fa-envelope", class: "input-icon" }), b(s("input", { id: "email", "onUpdate:modelValue": e[0] || (e[0] = (i) => o.form.email = i), type: "email", class: v(["form-input", { error: o.errors.email }]), placeholder: "Enter your email", required: "", autocomplete: "email" }, null, 2), [ [S, o.form.email] ]) ]), o.errors.email ? (d(), u("span", te, p(o.errors.email[0]), 1)) : h("", !0) ]), s("div", ne, [ e[6] || (e[6] = s("label", { for: "password", class: "form-label" }, "Password", -1)), s("div", ae, [ l(t, { icon: "fa-solid fa-lock", class: "input-icon" }), b(s("input", { id: "password", "onUpdate:modelValue": e[1] || (e[1] = (i) => o.form.password = i), type: o.showPassword ? "text" : "password", class: v(["form-input", { error: o.errors.password }]), placeholder: "Enter your password", required: "", autocomplete: "current-password" }, null, 10, ie), [ [P, o.form.password] ]), s("button", { type: "button", onClick: e[2] || (e[2] = (i) => o.showPassword = !o.showPassword), class: "password-toggle" }, [ l(t, { icon: o.showPassword ? "fa-solid fa-eye-slash" : "fa-solid fa-eye" }, null, 8, ["icon"]) ]) ]), o.errors.password ? (d(), u("span", le, p(o.errors.password[0]), 1)) : h("", !0) ]), s("div", de, [ s("label", ue, [ b(s("input", { "onUpdate:modelValue": e[3] || (e[3] = (i) => o.form.remember = i), type: "checkbox", class: "checkbox-input" }, null, 512), [ [D, o.form.remember] ]), e[7] || (e[7] = s("span", { class: "checkbox-custom" }, null, -1)), e[8] || (e[8] = _(" Remember me ")) ]) ]), s("button", { type: "submit", class: "submit-button", disabled: o.isLoading }, [ o.isLoading ? (d(), N(t, { key: 0, icon: "fa-solid fa-spinner", spin: "", class: "button-icon" })) : (d(), N(t, { key: 1, icon: "fa-solid fa-sign-in-alt", class: "button-icon" })), _(" " + p(o.isLoading ? "Signing In..." : "Sign In"), 1) ], 8, ce), s("div", me, [ l(c, { to: "/forgot-password", class: "forgot-link" }, { default: T(() => e[9] || (e[9] = [ _(" Forgot your password? ") ])), _: 1, __: [9] }), s("div", fe, [ e[11] || (e[11] = _(" Don't have an account? ")), l(c, { to: "/register", class: "signup-link" }, { default: T(() => e[10] || (e[10] = [ _(" Sign up here ") ])), _: 1, __: [10] }) ]) ]) ], 32); } const V = /* @__PURE__ */ E(ee, [["render", ge], ["__scopeId", "data-v-de152c65"]]); const pe = { name: "LoginPage", components: { LoginForm: V }, props: { config: { type: Object, default: () => ({}) } }, methods: { handleLoginSuccess() { console.log("Login successful"); }, handleLoginError(a) { console.error("Login error:", a); } } }, _e = { class: "login-page" }, he = { class: "login-container" }, be = { class: "login-content" }, we = { class: "brand-section" }, ye = { class: "brand-logo" }; function ve(a, e, r, o, n, m) { const t = y("font-awesome-icon"), c = y("LoginForm"); return d(), u("div", _e, [ s("div", he, [ s("div", be, [ s("div", we, [ s("div", ye, [ l(t, { icon: "fa-solid fa-sign-in-alt" }) ]), e[0] || (e[0] = s("h1", { class: "brand-title" }, "vue3plate", -1)), e[1] || (e[1] = s("p", { class: "brand-subtitle" }, "Welcome Back", -1)) ]), l(c, { config: r.config, onSuccess: m.handleLoginSuccess, onError: m.handleLoginError }, null, 8, ["config", "onSuccess", "onError"]) ]) ]) ]); } const F = /* @__PURE__ */ E(pe, [["render", ve], ["__scopeId", "data-v-999b0c89"]]); const Ae = { name: "RegisterForm", props: { config: { type: Object, default: () => ({}) } }, emits: ["success", "error"], setup(a, { emit: e }) { const { register: r, isLoading: o, error: n, clearError: m } = I(a.config), t = R({ firstName: "", middleName: "", lastName: "", email: "", mobileNumber: "", password: "", passwordConfirmation: "", agreeToTerms: !1 }), c = R(!1), i = R(!1), L = g(() => { var k; return ((k = n.value) == null ? void 0 : k.errors) || {}; }); return { form: t, showPassword: c, showPasswordConfirm: i, errors: L, isLoading: o, error: n, handleSubmit: async () => { m(); try { await r({ firstName: t.value.firstName, middleName: t.value.middleName, lastName: t.value.lastName, email: t.value.email, mobileNumber: t.value.mobileNumber, password: t.value.password, passwordConfirmation: t.value.passwordConfirmation }), e("success"); } catch (k) { e("error", k); } } }; } }, ke = { key: 0, class: "error-message" }, Se = { class: "form-row" }, Re = { class: "form-group" }, Ee = { class: "input-group" }, Le = { key: 0, class: "field-error" }, Ne = { class: "form-group" }, Te = { class: "input-group" }, Ie = { key: 0, class: "field-error" }, Ce = { class: "form-group" }, xe = { class: "input-group" }, Pe = { key: 0, class: "field-error" }, qe = { class: "form-group" }, Ue = { class: "input-group" }, Oe = { key: 0, class: "field-error" }, De = { class: "form-group" }, Ve = { class: "input-group" }, Fe = { key: 0, class: "field-error" }, Ge = { class: "form-row" }, Ke = { class: "form-group" }, Me = { class: "input-group" }, He = ["type"], je = { key: 0, class: "field-error" }, Be = { class: "form-group" }, ze = { class: "input-group" }, Je = ["type"], We = { key: 0, class: "field-error" }, Ye = { class: "form-group" }, Xe = { class: "checkbox-label" }, Qe = ["disabled"], Ze = { class: "form-footer" }, $e = { class: "signin-prompt" }; function eo(a, e, r, o, n, m) { const t = y("font-awesome-icon"), c = y("router-link"); return d(), u("form", { onSubmit: e[10] || (e[10] = O((...i) => o.handleSubmit && o.handleSubmit(...i), ["prevent"])), class: "register-form" }, [ e[25] || (e[25] = s("div", { class: "form-header" }, [ s("h2", { class: "form-title" }, "Create Account"), s("p", { class: "form-subtitle" }, "Join us today") ], -1)), o.error ? (d(), u("div", ke, [ l(t, { icon: "fa-solid fa-exclamation-circle" }), _(" " + p(o.error.message), 1) ])) : h("", !0), s("div", Se, [ s("div", Re, [ e[11] || (e[11] = s("label", { for: "firstName", class: "form-label" }, "First Name", -1)), s("div", Ee, [ l(t, { icon: "fa-solid fa-user", class: "input-icon" }), b(s("input", { id: "firstName", "onUpdate:modelValue": e[0] || (e[0] = (i) => o.form.firstName = i), type: "text", class: v(["form-input", { error: o.errors.first_name }]), placeholder: "First name", required: "", autocomplete: "given-name" }, null, 2), [ [S, o.form.firstName] ]) ]), o.errors.first_name ? (d(), u("span", Le, p(o.errors.first_name[0]), 1)) : h("", !0) ]), s("div", Ne, [ e[12] || (e[12] = s("label", { for: "lastName", class: "form-label" }, "Last Name", -1)), s("div", Te, [ l(t, { icon: "fa-solid fa-user", class: "input-icon" }), b(s("input", { id: "lastName", "onUpdate:modelValue": e[1] || (e[1] = (i) => o.form.lastName = i), type: "text", class: v(["form-input", { error: o.errors.last_name }]), placeholder: "Last name", required: "", autocomplete: "family-name" }, null, 2), [ [S, o.form.lastName] ]) ]), o.errors.last_name ? (d(), u("span", Ie, p(o.errors.last_name[0]), 1)) : h("", !0) ]) ]), s("div", Ce, [ e[13] || (e[13] = s("label", { for: "middleName", class: "form-label" }, "Middle Name (Optional)", -1)), s("div", xe, [ l(t, { icon: "fa-solid fa-user", class: "input-icon" }), b(s("input", { id: "middleName", "onUpdate:modelValue": e[2] || (e[2] = (i) => o.form.middleName = i), type: "text", class: v(["form-input", { error: o.errors.middle_name }]), placeholder: "Middle name", autocomplete: "additional-name" }, null, 2), [ [S, o.form.middleName] ]) ]), o.errors.middle_name ? (d(), u("span", Pe, p(o.errors.middle_name[0]), 1)) : h("", !0) ]), s("div", qe, [ e[14] || (e[14] = s("label", { for: "email", class: "form-label" }, "Email Address", -1)), s("div", Ue, [ l(t, { icon: "fa-solid fa-envelope", class: "input-icon" }), b(s("input", { id: "email", "onUpdate:modelValue": e[3] || (e[3] = (i) => o.form.email = i), type: "email", class: v(["form-input", { error: o.errors.email }]), placeholder: "Enter your email", required: "", autocomplete: "email" }, null, 2), [ [S, o.form.email] ]) ]), o.errors.email ? (d(), u("span", Oe, p(o.errors.email[0]), 1)) : h("", !0) ]), s("div", De, [ e[15] || (e[15] = s("label", { for: "mobileNumber", class: "form-label" }, "Mobile Number", -1)), s("div", Ve, [ l(t, { icon: "fa-solid fa-phone", class: "input-icon" }), b(s("input", { id: "mobileNumber", "onUpdate:modelValue": e[4] || (e[4] = (i) => o.form.mobileNumber = i), type: "tel", class: v(["form-input", { error: o.errors.mobile_number }]), placeholder: "Enter your mobile number", required: "", autocomplete: "tel" }, null, 2), [ [S, o.form.mobileNumber] ]) ]), o.errors.mobile_number ? (d(), u("span", Fe, p(o.errors.mobile_number[0]), 1)) : h("", !0) ]), s("div", Ge, [ s("div", Ke, [ e[16] || (e[16] = s("label", { for: "password", class: "form-label" }, "Password", -1)), s("div", Me, [ l(t, { icon: "fa-solid fa-lock", class: "input-icon" }), b(s("input", { id: "password", "onUpdate:modelValue": e[5] || (e[5] = (i) => o.form.password = i), type: o.showPassword ? "text" : "password", class: v(["form-input", { error: o.errors.password }]), placeholder: "Create password", required: "", autocomplete: "new-password" }, null, 10, He), [ [P, o.form.password] ]), s("button", { type: "button", onClick: e[6] || (e[6] = (i) => o.showPassword = !o.showPassword), class: "password-toggle" }, [ l(t, { icon: o.showPassword ? "fa-solid fa-eye-slash" : "fa-solid fa-eye" }, null, 8, ["icon"]) ]) ]), o.errors.password ? (d(), u("span", je, p(o.errors.password[0]), 1)) : h("", !0) ]), s("div", Be, [ e[17] || (e[17] = s("label", { for: "passwordConfirmation", class: "form-label" }, "Confirm Password", -1)), s("div", ze, [ l(t, { icon: "fa-solid fa-lock", class: "input-icon" }), b(s("input", { id: "passwordConfirmation", "onUpdate:modelValue": e[7] || (e[7] = (i) => o.form.passwordConfirmation = i), type: o.showPasswordConfirm ? "text" : "password", class: v(["form-input", { error: o.errors.password_confirmation }]), placeholder: "Confirm password", required: "", autocomplete: "new-password" }, null, 10, Je), [ [P, o.form.passwordConfirmation] ]), s("button", { type: "button", onClick: e[8] || (e[8] = (i) => o.showPasswordConfirm = !o.showPasswordConfirm), class: "password-toggle" }, [ l(t, { icon: o.showPasswordConfirm ? "fa-solid fa-eye-slash" : "fa-solid fa-eye" }, null, 8, ["icon"]) ]) ]), o.errors.password_confirmation ? (d(), u("span", We, p(o.errors.password_confirmation[0]), 1)) : h("", !0) ]) ]), s("div", Ye, [ s("label", Xe, [ b(s("input", { "onUpdate:modelValue": e[9] || (e[9] = (i) => o.form.agreeToTerms = i), type: "checkbox", class: "checkbox-input", required: "" }, null, 512), [ [D, o.form.agreeToTerms] ]), e[18] || (e[18] = s("span", { class: "checkbox-custom" }, null, -1)), e[19] || (e[19] = _(" I agree to the ")), e[20] || (e[20] = s("a", { href: "/terms", target: "_blank", class: "terms-link" }, "Terms of Service", -1)), e[21] || (e[21] = _(" and ")), e[22] || (e[22] = s("a", { href: "/privacy", target: "_blank", class: "terms-link" }, "Privacy Policy", -1)) ]) ]), s("button", { type: "submit", class: "submit-button", disabled: o.isLoading || !o.form.agreeToTerms }, [ o.isLoading ? (d(), N(t, { key: 0, icon: "fa-solid fa-spinner", spin: "", class: "button-icon" })) : (d(), N(t, { key: 1, icon: "fa-solid fa-user-plus", class: "button-icon" })), _(" " + p(o.isLoading ? "Creating Account..." : "Create Account"), 1) ], 8, Qe), s("div", Ze, [ s("div", $e, [ e[24] || (e[24] = _(" Already have an account? ")), l(c, { to: "/login", class: "signin-link" }, { default: T(() => e[23] || (e[23] = [ _(" Sign in here ") ])), _: 1, __: [23] }) ]) ]) ], 32); } const G = /* @__PURE__ */ E(Ae, [["render", eo], ["__scopeId", "data-v-be35a40f"]]); const oo = { name: "RegisterPage", components: { RegisterForm: G }, props: { config: { type: Object, default: () => ({}) } }, methods: { handleRegisterSuccess() { console.log("Registration successful"); }, handleRegisterError(a) { console.error("Registration error:", a); } } }, ro = { class: "register-page" }, so = { class: "register-container" }, to = { class: "register-content" }, no = { class: "brand-section" }, ao = { class: "brand-logo" }; function io(a, e, r, o, n, m) { const t = y("font-awesome-icon"), c = y("RegisterForm"); return d(), u("div", ro, [ s("div", so, [ s("div", to, [ s("div", no, [ s("div", ao, [ l(t, { icon: "fa-solid fa-user-plus" }) ]), e[0] || (e[0] = s("h1", { class: "brand-title" }, "vue3plate", -1)), e[1] || (e[1] = s("p", { class: "brand-subtitle" }, "Join Our Community", -1)) ]), l(c, { config: r.config, onSuccess: m.handleRegisterSuccess, onError: m.handleRegisterError }, null, 8, ["config", "onSuccess", "onError"]) ]) ]) ]); } const K = /* @__PURE__ */ E(oo, [["render", io], ["__scopeId", "data-v-ea5bb4e2"]]); const lo = { name: "AuthGuard", props: { config: { type: Object, default: () => ({}) }, requireRole: { type: String, default: null }, requireAnyRole: { type: Array, default: () => [] } }, setup(a) { const { isAuthenticated: e, isLoading: r, userRole: o, hasRole: n, hasAnyRole: m } = I(a.config), t = g(() => a.requireRole ? n(a.requireRole) : a.requireAnyRole.length > 0 ? m(a.requireAnyRole) : !0); return { isAuthenticated: g(() => e.value && t.value), isLoading: r, userRole: o }; } }, uo = { key: 0 }, co = { key: 1, class: "auth-guard-message" }, mo = { class: "message-content" }, fo = { key: 2, class: "auth-guard-loading" }; function go(a, e, r, o, n, m) { const t = y("font-awesome-icon"), c = y("router-link"); return o.isAuthenticated ? (d(), u("div", uo, [ X(a.$slots, "default", {}, void 0, !0) ])) : o.isLoading ? (d(), u("div", fo, [ l(t, { icon: "fa-solid fa-spinner", spin: "", class: "loading-icon" }), e[3] || (e[3] = s("p", null, "Checking authentication...", -1)) ])) : (d(), u("div", co, [ s("div", mo, [ l(t, { icon: "fa-solid fa-lock", class: "lock-icon" }), e[1] || (e[1] = s("h3", { class: "message-title" }, "Authentication Required", -1)), e[2] || (e[2] = s("p", { class: "message-text" }, "You need to be logged in to access this content.", -1)), l(c, { to: "/login", class: "login-button" }, { default: T(() => [ l(t, { icon: "fa-solid fa-sign-in-alt" }), e[0] || (e[0] = _(" Sign In ")) ]), _: 1, __: [0] }) ]) ])); } const po = /* @__PURE__ */ E(lo, [["render", go], ["__scopeId", "data-v-f42a8912"]]); class _o { constructor() { this.config = null, this.client = null; } /** * Initialize the API client with configuration * @param {Object} config - Configuration object */ init(e) { this.config = e, this.client = $.create({ baseURL: e.apiBaseUrl, timeout: 1e4, headers: { "Content-Type": "application/json", Accept: "application/json", "X-Requested-With": "XMLHttpRequest" } }), this.client.interceptors.request.use( (r) => { const o = localStorage.getItem(e.tokenKey); return o && (r.headers.Authorization = `Bearer ${o}`), r; }, (r) => Promise.reject(r) ), this.client.interceptors.response.use( (r) => r, (r) => { var o; return ((o = r.response) == null ? void 0 : o.status) === 401 && (this.clearAuthData(), window.location.pathname !== "/login" && (window.location.href = "/login")), Promise.reject(r); } ); } /** * Register a new user account * @param {Object} userData - User registration data * @returns {Promise} API response */ async register(e) { try { const r = await this.client.post("/register-account", { first_name: e.firstName, middle_name: e.middleName || "", last_name: e.lastName, email: e.email, mobile_number: e.mobileNumber, password: e.password, password_confirmation: e.passwordConfirmation }); return r.data.token && this.setAuthData(r.data.token, r.data.user), r.data; } catch (r) { throw this.handleError(r); } } /** * Login user * @param {Object} credentials - Login credentials * @returns {Promise} API response */ async login(e) { try { const r = await this.client.post("/login", { email: e.email, password: e.password }); return r.data.token && this.setAuthData(r.data.token, r.data.user), r.data; } catch (r) { throw this.handleError(r); } } /** * Logout user * @returns {Promise} API response */ async logout() { try { const e = await this.client.post("/logout"); return this.clearAuthData(), e.data; } catch (e) { throw this.clearAuthData(), this.handleError(e); } } /** * Set authentication data in localStorage * @param {string} token - Auth token * @param {Object} user - User data */ setAuthData(e, r) { localStorage.setItem(this.config.tokenKey, e), localStorage.setItem(this.config.userKey, JSON.stringify(r)); } /** * Clear authentication data from localStorage */ clearAuthData() { localStorage.removeItem(this.config.tokenKey), localStorage.removeItem(this.config.userKey); } /** * Get stored token * @returns {string|null} Auth token */ getStoredToken() { return localStorage.getItem(this.config.tokenKey); } /** * Get stored user data * @returns {Object|null} User data */ getStoredUser() { const e = localStorage.getItem(this.config.userKey); return e ? JSON.parse(e) : null; } /** * Check if user is authenticated * @returns {boolean} Authentication status */ isAuthenticated() { return !!this.getStoredToken(); } /** * Handle API errors * @param {Error} error - Axios error * @returns {Object} Formatted error */ handleError(e) { return e.response ? { message: e.response.data.message || "An error occurred", errors: e.response.data.errors || {}, status: e.response.status } : e.request ? { message: "Network error. Please check your connection.", errors: {}, status: 0 } : { message: e.message || "An unexpected error occurred", errors: {}, status: 0 }; } } const w = new _o(); function ho(a) { return { namespaced: !0, state: () => ({ user: w.getStoredUser(), token: w.getStoredToken(), isLoading: !1, error: null, isAuthenticated: w.isAuthenticated() }), getters: { isAuthenticated: (e) => e.isAuthenticated, user: (e) => e.user, token: (e) => e.token, isLoading: (e) => e.isLoading, error: (e) => e.error, userRole: (e) => { var r, o; return ((o = (r = e.user) == null ? void 0 : r.role) == null ? void 0 : o.name) || null; }, userStatus: (e) => { var r, o; return ((o = (r = e.user) == null ? void 0 : r.status) == null ? void 0 : o.name) || null; }, isAdmin: (e) => { var r, o; return ((o = (r = e.user) == null ? void 0 : r.role) == null ? void 0 : o.name) === "Admin"; }, isStaff: (e) => { var r, o; return ((o = (r = e.user) == null ? void 0 : r.role) == null ? void 0 : o.name) === "Staff"; }, isActive: (e) => { var r, o; return ((o = (r = e.user) == null ? void 0 : r.status) == null ? void 0 : o.name) === "Active"; }, fullName: (e) => { if (!e.user) return ""; const { first_name: r, middle_name: o, last_name: n } = e.user; return [r, o, n].filter(Boolean).join(" "); } }, mutations: { SET_LOADING(e, r) { e.isLoading = r; }, SET_ERROR(e, r) { e.error = r; }, SET_AUTH_DATA(e, { user: r, token: o }) { e.user = r, e.token = o, e.isAuthenticated = !0, e.error = null; }, CLEAR_AUTH_DATA(e) { e.user = null, e.token = null, e.isAuthenticated = !1, e.error = null; }, UPDATE_USER(e, r) { e.user && (e.user = { ...e.user, ...r }); } }, actions: { /** * Login user * @param {Object} context - Vuex context * @param {Object} credentials - Login credentials */ async login({ commit: e, dispatch: r }, o) { e("SET_LOADING", !0), e("SET_ERROR", null); try { const n = await w.login(o); return e("SET_AUTH_DATA", { user: n.user, token: n.token }), r("app/addHeaderMenuItem", { id: "user-menu", type: "dropdown", label: n.user.first_name, icon: "fa-solid fa-user", items: [ { id: "logout", label: "Logout", icon: "fa-solid fa-sign-out-alt", action: () => r("logout") } ] }, { root: !0 }), n; } catch (n) { throw e("SET_ERROR", n), n; } finally { e("SET_LOADING", !1); } }, /** * Register new user * @param {Object} context - Vuex context * @param {Object} userData - Registration data */ async register({ commit: e, dispatch: r }, o) { e("SET_LOADING", !0), e("SET_ERROR", null); try { const n = await w.register(o); return e("SET_AUTH_DATA", { user: n.user, token: n.token }), r("app/addHeaderMenuItem", { id: "user-menu", type: "dropdown", label: n.user.first_name, icon: "fa-solid fa-user", items: [ { id: "logout", label: "Logout", icon: "fa-solid fa-sign-out-alt", action: () => r("logout") } ] }, { root: !0 }), n; } catch (n) { throw e("SET_ERROR", n), n; } finally { e("SET_LOADING", !1); } }, /** * Logout user * @param {Object} context - Vuex context */ async logout({ commit: e, dispatch: r }) { e("SET_LOADING", !0); try { await w.logout(); } catch (o) { console.warn("Logout API call failed:", o); } finally { e("CLEAR_AUTH_DATA"), r("app/removeHeaderMenuItem", "user-menu", { root: !0 }), e("SET_LOADING", !1); } }, /** * Initialize auth state from localStorage * @param {Object} context - Vuex context */ initializeAuth({ commit: e, dispatch: r }) { const o = w.getStoredToken(), n = w.getStoredUser(); o && n && (e("SET_AUTH_DATA", { user: n, token: o }), r("app/addHeaderMenuItem", { id: "user-menu", type: "dropdown", label: n.first_name, icon: "fa-solid fa-user", items: [ { id: "logout", label: "Logout", icon: "fa-solid fa-sign-out-alt", action: () => r("logout") } ] }, { root: !0 })); }, /** * Clear error state * @param {Object} context - Vuex context */ clearError({ commit: e }) { e("SET_ERROR", null); } } }; } function bo(a) { return [ { path: "/login", name: "Login", component: F, meta: { layout: "auth", requiresGuest: !0, title: "Login" }, beforeEnter: (e, r, o) => { localStorage.getItem(a.tokenKey) ? o(a.afterLogin) : o(); } }, { path: "/register", name: "Register", component: K, meta: { layout: "auth", requiresGuest: !0, title: "Register" }, beforeEnter: (e, r, o) => { localStorage.getItem(a.tokenKey) ? o(a.afterRegister) : o(); } } ]; } function Eo(a = {}) { const r = { ...{ apiBaseUrl: {}.VITE_API_URL || "http://localhost:8000/api", tokenKey: {}.VITE_TOKEN_KEY || "auth_token", userKey: {}.VITE_USER_KEY || "auth_user", afterLogin: "/dashboard", afterLogout: "/", afterRegister: "/dashboard" }, ...a }; return w.init(r), { name: "authentication", config: r, // Routes to register routes: bo(r), // Store module to register store: ho(), // Components to register globally (optional) components: { LoginForm: V, RegisterForm: G, AuthGuard: po }, // Views (for manual route registration) views: { LoginPage: F, RegisterPage: K }, // Composables composables: { useAuth: () => I(r) }, // API utilities api: w, // Sidebar menu items to add sidebarItems: [], // Header menu items to add headerItems: [ { id: "auth-logout", label: "Logout", icon: "fa-solid fa-sign-out-alt", action: "logout", requiresAuth: !0 } ] }; } export { po as AuthGuard, V as LoginForm, F as LoginPage, G as RegisterForm, K as RegisterPage, w as authApi, bo as authRoutes, ho as authStore, Eo as createAuthenticationFeature, Eo as default, I as useAuth };