Compare commits
2 Commits
ad76bfb535
...
21ca04f044
| Author | SHA1 | Date |
|---|---|---|
|
|
21ca04f044 | |
|
|
2dbf591c8f |
|
|
@ -0,0 +1,59 @@
|
|||
import { useAuthStore } from "@/stores";
|
||||
|
||||
export const fetchWrapper = {
|
||||
get: request("GET"),
|
||||
post: request("POST"),
|
||||
put: request("PUT"),
|
||||
delete: request("DELETE"),
|
||||
};
|
||||
|
||||
function request(method) {
|
||||
return (url, body) => {
|
||||
console.log("url: " + url, "body: ", body);
|
||||
const requestOptions = {
|
||||
method,
|
||||
headers: authHeader(url),
|
||||
};
|
||||
if (body) {
|
||||
requestOptions.headers["Content-Type"] = "application/json";
|
||||
requestOptions.body = JSON.stringify(body);
|
||||
}
|
||||
return fetch(url, requestOptions).then(handleResponse);
|
||||
};
|
||||
}
|
||||
|
||||
// helper functions
|
||||
|
||||
function authHeader(url) {
|
||||
// return auth header with jwt if user is logged in and request is to the api url
|
||||
const { user } = useAuthStore();
|
||||
const isLoggedIn = !!user?.token;
|
||||
const isApiUrl = url.startsWith(import.meta.env.VITE_API_URL);
|
||||
if (isLoggedIn && isApiUrl) {
|
||||
return { Authorization: `Bearer ${user.token}` };
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
async function handleResponse(response) {
|
||||
const isJson = response.headers
|
||||
?.get("content-type")
|
||||
?.includes("application/json");
|
||||
const data = isJson ? await response.json() : null;
|
||||
|
||||
// check for error response
|
||||
if (!response.ok) {
|
||||
const { user, logout } = useAuthStore();
|
||||
if ([401, 403].includes(response.status) && user) {
|
||||
// auto logout if 401 Unauthorized or 403 Forbidden response returned from api
|
||||
logout();
|
||||
}
|
||||
|
||||
// get error message from body or default to response status
|
||||
const error = (data && data.message) || response.status;
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export * from "./fetch-wrapper";
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { defineStore } from "pinia";
|
||||
|
||||
export const useAlertStore = defineStore({
|
||||
id: "alert",
|
||||
state: () => ({
|
||||
alert: null,
|
||||
}),
|
||||
actions: {
|
||||
success(message) {
|
||||
this.alert = { message, type: "alert-success" };
|
||||
},
|
||||
error(message) {
|
||||
this.alert = { message, type: "alert-danger" };
|
||||
},
|
||||
clear() {
|
||||
this.alert = null;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { defineStore } from "pinia";
|
||||
|
||||
import { fetchWrapper } from "@/api";
|
||||
// import { router } from "@/router";
|
||||
import { useAlertStore } from "@/stores";
|
||||
|
||||
const baseUrl = `${import.meta.env.VITE_API_URL}/api`;
|
||||
|
||||
export const useAuthStore = defineStore({
|
||||
id: "auth",
|
||||
state: () => ({
|
||||
// initialize state from local storage to enable user to stay logged in
|
||||
user: JSON.parse(localStorage.getItem("user")),
|
||||
returnUrl: null,
|
||||
}),
|
||||
actions: {
|
||||
async login(email, password) {
|
||||
return fetchWrapper
|
||||
.post(`${baseUrl}/login`, { email, password })
|
||||
.then((response) => {
|
||||
console.log("response: " + response);
|
||||
|
||||
console.log("user: " + response["success"]["token"]["plainTextToken"]);
|
||||
|
||||
// update pinia state
|
||||
this.user = user;
|
||||
|
||||
// store user details and jwt in local storage to keep user logged in between page refreshes
|
||||
// localStorage.setItem("user", JSON.stringify(user));
|
||||
|
||||
// redirect to previous url or default to home page
|
||||
// router.push(this.returnUrl || "/");
|
||||
})
|
||||
.catch((error) => {
|
||||
const alertStore = useAlertStore();
|
||||
alertStore.error(error);
|
||||
});
|
||||
},
|
||||
logout() {
|
||||
// this.user = null;
|
||||
// localStorage.removeItem("user");
|
||||
// router.push("/account/login");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./alert.store";
|
||||
export * from "./auth";
|
||||
|
|
@ -6,28 +6,17 @@
|
|||
<!-- BEGIN: Login Info -->
|
||||
<div class="hidden xl:flex flex-col min-h-screen">
|
||||
<a href="" class="-intro-x flex items-center pt-5">
|
||||
<img
|
||||
alt="Midone Tailwind HTML Admin Template"
|
||||
class="w-6"
|
||||
src="@/assets/images/logo.svg"
|
||||
/>
|
||||
<img alt="Midone Tailwind HTML Admin Template" class="w-6" src="@/assets/images/logo.svg" />
|
||||
<span class="text-white text-lg ml-3"> Icewall </span>
|
||||
</a>
|
||||
<div class="my-auto">
|
||||
<img
|
||||
alt="Midone Tailwind HTML Admin Template"
|
||||
class="-intro-x w-1/2 -mt-16"
|
||||
src="@/assets/images/illustration.svg"
|
||||
/>
|
||||
<div
|
||||
class="-intro-x text-white font-medium text-4xl leading-tight mt-10"
|
||||
>
|
||||
<img alt="Midone Tailwind HTML Admin Template" class="-intro-x w-1/2 -mt-16"
|
||||
src="@/assets/images/illustration.svg" />
|
||||
<div class="-intro-x text-white font-medium text-4xl leading-tight mt-10">
|
||||
A few more clicks to <br />
|
||||
sign in to your account.
|
||||
</div>
|
||||
<div
|
||||
class="-intro-x mt-5 text-lg text-white text-opacity-70 dark:text-slate-400"
|
||||
>
|
||||
<div class="-intro-x mt-5 text-lg text-white text-opacity-70 dark:text-slate-400">
|
||||
Manage all your e-commerce accounts in one place
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -36,67 +25,39 @@
|
|||
<!-- BEGIN: Login Form -->
|
||||
<div class="h-screen xl:h-auto flex py-5 xl:py-0 my-10 xl:my-0">
|
||||
<div
|
||||
class="my-auto mx-auto xl:ml-20 bg-white dark:bg-darkmode-600 xl:bg-transparent px-5 sm:px-8 py-8 xl:p-0 rounded-md shadow-md xl:shadow-none w-full sm:w-3/4 lg:w-2/4 xl:w-auto"
|
||||
>
|
||||
<h2
|
||||
class="intro-x font-bold text-2xl xl:text-3xl text-center xl:text-left"
|
||||
>
|
||||
class="my-auto mx-auto xl:ml-20 bg-white dark:bg-darkmode-600 xl:bg-transparent px-5 sm:px-8 py-8 xl:p-0 rounded-md shadow-md xl:shadow-none w-full sm:w-3/4 lg:w-2/4 xl:w-auto">
|
||||
<h2 class="intro-x font-bold text-2xl xl:text-3xl text-center xl:text-left">
|
||||
Sign In
|
||||
</h2>
|
||||
<div class="intro-x mt-2 text-slate-400 xl:hidden text-center">
|
||||
A few more clicks to sign in to your account. Manage all your
|
||||
e-commerce accounts in one place
|
||||
A few more clicks to sign in to your account. Manage all your e-commerce
|
||||
accounts in one place
|
||||
</div>
|
||||
<div class="intro-x mt-8">
|
||||
<input
|
||||
type="text"
|
||||
class="intro-x login__input form-control py-3 px-4 block"
|
||||
placeholder="Email"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
class="intro-x login__input form-control py-3 px-4 block mt-4"
|
||||
placeholder="Password"
|
||||
/>
|
||||
<input type="text" class="intro-x login__input form-control py-3 px-4 block" placeholder="Email" />
|
||||
<input type="password" class="intro-x login__input form-control py-3 px-4 block mt-4"
|
||||
placeholder="Password" />
|
||||
</div>
|
||||
<div
|
||||
class="intro-x flex text-slate-600 dark:text-slate-500 text-xs sm:text-sm mt-4"
|
||||
>
|
||||
<div class="intro-x flex text-slate-600 dark:text-slate-500 text-xs sm:text-sm mt-4">
|
||||
<div class="flex items-center mr-auto">
|
||||
<input
|
||||
id="remember-me"
|
||||
type="checkbox"
|
||||
class="form-check-input border mr-2"
|
||||
/>
|
||||
<label class="cursor-pointer select-none" for="remember-me"
|
||||
>Remember me</label
|
||||
>
|
||||
<input id="remember-me" type="checkbox" class="form-check-input border mr-2" />
|
||||
<label class="cursor-pointer select-none" for="remember-me">Remember me</label>
|
||||
</div>
|
||||
<a href="">Forgot Password?</a>
|
||||
</div>
|
||||
<div class="intro-x mt-5 xl:mt-8 text-center xl:text-left">
|
||||
<button
|
||||
class="btn btn-primary py-3 px-4 w-full xl:w-32 xl:mr-3 align-top"
|
||||
>
|
||||
<button class="btn btn-primary py-3 px-4 w-full xl:w-32 xl:mr-3 align-top" @click.prevent="onSubmit">
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-outline-secondary py-3 px-4 w-full xl:w-32 mt-3 xl:mt-0 align-top"
|
||||
>
|
||||
<button class="btn btn-outline-secondary py-3 px-4 w-full xl:w-32 mt-3 xl:mt-0 align-top">
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="intro-x mt-10 xl:mt-24 text-slate-600 dark:text-slate-500 text-center xl:text-left"
|
||||
>
|
||||
<div class="intro-x mt-10 xl:mt-24 text-slate-600 dark:text-slate-500 text-center xl:text-left">
|
||||
By signin up, you agree to our
|
||||
<a class="text-primary dark:text-slate-200" href=""
|
||||
>Terms and Conditions</a
|
||||
>
|
||||
<a class="text-primary dark:text-slate-200" href="">Terms and Conditions</a>
|
||||
&
|
||||
<a class="text-primary dark:text-slate-200" href=""
|
||||
>Privacy Policy</a
|
||||
>
|
||||
<a class="text-primary dark:text-slate-200" href="">Privacy Policy</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -110,6 +71,14 @@
|
|||
import { onMounted } from "vue";
|
||||
import DarkModeSwitcher from "@/components/dark-mode-switcher/Main.vue";
|
||||
import dom from "@left4code/tw-starter/dist/js/dom";
|
||||
import { useAuthStore } from '@/stores'
|
||||
|
||||
const onSubmit = () => {
|
||||
console.log("onSubmit");
|
||||
const authStore = useAuthStore();
|
||||
// const { username, password } = values;
|
||||
return authStore.login("ilmedovamahri@gmail.com", "12345678");
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
dom("body").removeClass("main").removeClass("error-page").addClass("login");
|
||||
|
|
|
|||
Loading…
Reference in New Issue