-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
253 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,9 @@ | ||
import { storeToRefs } from "pinia"; | ||
|
||
export default defineNuxtRouteMiddleware((to) => { | ||
const { authenticated } = storeToRefs(useAuthStore()); | ||
const token = useCookie("token"); | ||
const { user } = storeToRefs(useAuthStore()); | ||
|
||
if (token.value) authenticated.value = true; | ||
console.log(user.value); | ||
|
||
if (token.value && to.name === "login") return navigateTo("/"); | ||
|
||
if (!token.value && to.name !== "login") { | ||
abortNavigation(); | ||
return navigateTo("/login"); | ||
} | ||
if (to.fullPath === "/login" && user.value.id) return navigateTo("/"); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,112 @@ | ||
<template> | ||
<Layout title="Login | Readconquista" description="Login to Readconquista"> | ||
<div | ||
class="flex h-full items-center justify-center flex-col gap-4 md:gap-8 pt-24" | ||
class="flex h-full items-center justify-center flex-col gap-4 md:gap-8" | ||
> | ||
<h2 class="text-xl md:text-2xl font-semibold">Login</h2> | ||
<h2 class="text-3xl md:text-5xl font-black">Login</h2> | ||
<h3 | ||
v-if="formIsEmail === true" | ||
class="underline underline-offset-4 decoration-grayscale-800 font-light text-lg md:text-xl text-grayscale-800 cursor-pointer" | ||
@click="formIsEmail = !formIsEmail" | ||
> | ||
Using a username? | ||
</h3> | ||
<h3 | ||
v-else | ||
class="underline underline-offset-4 decoration-grayscale-800 font-light text-lg text-grayscale-800 cursor-pointer" | ||
@click="formIsEmail = !formIsEmail" | ||
> | ||
Using an email address? | ||
</h3> | ||
<form class="flex flex-col gap-4" @submit.prevent="login()"> | ||
<div> | ||
<input | ||
v-if="formIsEmail === true" | ||
v-model="email" | ||
type="email" | ||
class="rounded-lg resize-none w-full block bg-grayscale-400 px-4 py-2 placeholder:justify-center" | ||
placeholder="Email address" | ||
/> | ||
<input | ||
v-else | ||
v-model="username" | ||
class="rounded-lg resize-none w-full block bg-grayscale-400 px-4 py-2 placeholder:justify-center" | ||
placeholder="Username" | ||
/> | ||
</div> | ||
<div> | ||
<input | ||
v-model="password" | ||
type="password" | ||
class="rounded-lg resize-none w-full block bg-grayscale-400 px-4 py-2 placeholder:justify-center" | ||
placeholder="Password" | ||
/> | ||
</div> | ||
<div class="mt-4"> | ||
<button | ||
v-if="formIsEmail === true" | ||
type="submit" | ||
class="rounded-xl w-full p-2" | ||
:disabled="!email || !password" | ||
:class=" | ||
email && password | ||
? 'bg-grayscale-900 text-grayscale-400' | ||
: 'bg-grayscale-400 text-grayscale-900' | ||
" | ||
> | ||
Log In | ||
</button> | ||
<button | ||
v-else | ||
type="submit" | ||
class="rounded-xl w-full p-2" | ||
:disabled="!username || !password" | ||
:class=" | ||
username && password | ||
? 'bg-grayscale-900 text-grayscale-400' | ||
: 'bg-grayscale-400 text-grayscale-900' | ||
" | ||
> | ||
Log In | ||
</button> | ||
</div> | ||
<div v-if="error" class="mt-2 flex flex-row"> | ||
<span class="text-red-500 font-bold">{{ error }}</span> | ||
</div> | ||
</form> | ||
</div> | ||
</Layout> | ||
</template> | ||
|
||
<script setup lang="ts"> | ||
import { storeToRefs } from "pinia"; | ||
import { ref } from "vue"; | ||
import { useAuthStore } from "~/utils/authStore"; | ||
import { pinia } from "~/utils/pinia"; | ||
// import { pinia } from "~/utils/pinia"; | ||
const { authenticated } = storeToRefs(useAuthStore(pinia)); | ||
const userStore = useAuthStore(); | ||
// Check if the user has selected username or email | ||
const formIsEmail = ref(false); | ||
const email = ref(""); | ||
const username = ref(""); | ||
const password = ref(""); | ||
// I'm so fucking sorry. | ||
const error = ref(); | ||
const router = useRouter(); | ||
const login = async () => { | ||
const { data, requestState } = await userStore.login( | ||
password.value, | ||
username.value, | ||
email.value, | ||
); | ||
if (requestState.error) error.value = requestState.error; | ||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition | ||
else if (data) await router.push("/"); | ||
}; | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,76 @@ | ||
import { defineStore } from "pinia"; | ||
|
||
interface RequestState { | ||
loading: boolean; | ||
error: Error | null; | ||
} | ||
|
||
interface UserState { | ||
id: string; | ||
username: string; | ||
email: string; | ||
accessToken: string; | ||
refreshToken: string; | ||
} | ||
|
||
export const useAuthStore = defineStore("auth", { | ||
state: () => ({ | ||
accessToken: "", | ||
refreshToken: "", | ||
username: "", | ||
email: "", | ||
authenticated: false, | ||
user: {} as UserState, | ||
}), | ||
actions: { | ||
async login(password: string, username?: string, email?: string) { | ||
const { data } = await useFetch("/api/auth/login", { | ||
method: "post", | ||
headers: { "Content-Type": "application/json" }, | ||
body: { | ||
password, | ||
username, | ||
email, | ||
}, | ||
}); | ||
|
||
if (data.value) { | ||
this.$state.accessToken = data.value.accessToken; | ||
this.$state.refreshToken = data.value.refreshToken; | ||
this.$state.username = data.value.username; | ||
this.$state.email = data.value.email; | ||
|
||
this.authenticated = true; | ||
} | ||
async login( | ||
password: string, | ||
username?: string, | ||
email?: string, | ||
): Promise<{ data: UserState; requestState: RequestState }> { | ||
const requestState: RequestState = { | ||
loading: true, | ||
error: null, | ||
}; | ||
|
||
if (username === "") | ||
try { | ||
const data: UserState = await $fetch("/api/auth/login", { | ||
method: "post", | ||
headers: { "Content-Type": "application/json" }, | ||
body: { | ||
password, | ||
email, | ||
}, | ||
}); | ||
requestState.loading = false; | ||
return { data, requestState }; | ||
} catch (error) { | ||
requestState.loading = false; | ||
requestState.error = error as Error; | ||
return { data: {} as UserState, requestState }; | ||
} | ||
|
||
if (email === "") | ||
try { | ||
const data: UserState = await $fetch("/api/auth/login", { | ||
method: "post", | ||
headers: { "Content-Type": "application/json" }, | ||
body: { | ||
username, | ||
password, | ||
}, | ||
}); | ||
|
||
requestState.loading = false; | ||
return { data, requestState }; | ||
} catch (error) { | ||
requestState.loading = false; | ||
requestState.error = error as Error; | ||
return { data: {} as UserState, requestState }; | ||
} | ||
return { data: {} as UserState, requestState }; | ||
}, | ||
|
||
async logout() { | ||
await revokeTokensByIdentifier({ email: this.$state.email }); | ||
await revokeTokensByIdentifier({ email: this.user.email }); | ||
|
||
this.$state.accessToken = ""; | ||
this.$state.refreshToken = ""; | ||
this.$state.username = ""; | ||
this.$state.email = ""; | ||
this.authenticated = false; | ||
this.user = {} as UserState; | ||
}, | ||
}, | ||
}); |
Oops, something went wrong.