Files
seasoned/src/pages/SigninPage.vue

140 lines
3.4 KiB
Vue

<template>
<section>
<h1>Sign in</h1>
<form ref="formElement" class="form">
<seasoned-input
v-model="username"
placeholder="username"
icon="Email"
type="email"
@keydown.enter="focusOnNextElement"
/>
<seasoned-input
v-model="password"
placeholder="password"
icon="Keyhole"
type="password"
@keydown.enter="submit"
/>
<seasoned-button @click="submit">sign in</seasoned-button>
</form>
<router-link class="link" to="/register"
>Don't have a user? Register here</router-link
>
<seasoned-messages v-model:messages="messages" />
</section>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import SeasonedInput from "@/components/ui/SeasonedInput.vue";
import SeasonedButton from "@/components/ui/SeasonedButton.vue";
import SeasonedMessages from "@/components/ui/SeasonedMessages.vue";
import type { Ref } from "vue";
import { login } from "../api";
import { focusFirstFormInput, focusOnNextElement } from "../utils";
import { ErrorMessageTypes } from "../interfaces/IErrorMessage";
import type { IErrorMessage } from "../interfaces/IErrorMessage";
const username: Ref<string> = ref("");
const password: Ref<string> = ref("");
const messages: Ref<IErrorMessage[]> = ref([]);
const formElement: Ref<HTMLFormElement> = ref(null);
const store = useStore();
const router = useRouter();
onMounted(() => focusFirstFormInput(formElement.value));
function clearMessages() {
messages.value = [];
}
function addErrorMessage(message: string, title?: string) {
messages.value.push({
message,
title,
type: ErrorMessageTypes.Error
} as IErrorMessage);
}
function addWarningMessage(message: string, title?: string) {
messages.value.push({
message,
title,
type: ErrorMessageTypes.Warning
} as IErrorMessage);
}
function validate(): Promise<boolean> {
return new Promise((resolve, reject) => {
if (!username.value || username?.value?.length === 0) {
addWarningMessage("Missing username", "Validation error");
reject();
}
if (!password.value || password?.value?.length === 0) {
addWarningMessage("Missing password", "Validation error");
reject();
}
resolve(true);
});
}
function signin() {
login(username.value, password.value, true)
.then(data => {
if (data?.success && store.dispatch("user/login")) {
router.push({ name: "profile" });
}
})
.catch(error => {
if (error?.status === 401) {
addErrorMessage("Incorrect username or password", "Access denied");
return null;
}
addErrorMessage(error?.message, "Unexpected error");
return null;
});
}
function submit() {
clearMessages();
validate().then(signin);
}
</script>
<style lang="scss" scoped>
@import "src/scss/variables";
section {
padding: 1.3rem;
@include tablet-min {
padding: 4rem;
}
h1 {
margin: 0;
line-height: 16px;
color: $text-color;
font-weight: 300;
margin-bottom: 20px;
text-transform: uppercase;
}
.link {
display: block;
width: max-content;
margin-top: 1rem;
}
}
</style>