106 lines
3.1 KiB
Vue
106 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
import { AuthApiClient } from '@/api/auth';
|
|
import { ApiError } from '@/api/base';
|
|
import AppButton from '@/components/AppButton.vue';
|
|
import AppForm from '@/components/form/AppForm.vue';
|
|
import FormControl from '@/components/form/FormControl.vue';
|
|
import FormGroup from '@/components/form/FormGroup.vue';
|
|
import { useAuthStore } from '@/stores/auth-store';
|
|
import { showAlert } from '@/util/alert';
|
|
import { hideLoader, showLoader } from '@/util/loader';
|
|
import { ref } from 'vue';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
|
const router = useRouter()
|
|
const route = useRoute()
|
|
const authStore = useAuthStore()
|
|
const apiClient = new AuthApiClient()
|
|
const isDev = import.meta.env.DEV
|
|
|
|
const username = ref('')
|
|
const password = ref('')
|
|
const disableForm = ref(false)
|
|
|
|
async function doLogin() {
|
|
disableForm.value = true
|
|
showLoader()
|
|
try {
|
|
const token = await apiClient.login(username.value, password.value)
|
|
authStore.onUserLoggedIn(username.value, token)
|
|
hideLoader()
|
|
if ('next' in route.query && typeof (route.query.next) === 'string') {
|
|
await router.replace(route.query.next)
|
|
} else {
|
|
await router.replace('/')
|
|
}
|
|
} catch (err) {
|
|
hideLoader()
|
|
if (err instanceof ApiError) {
|
|
await showAlert(err.message)
|
|
} else {
|
|
await showAlert('Request failed: ' + JSON.stringify(err))
|
|
}
|
|
} finally {
|
|
disableForm.value = false
|
|
}
|
|
}
|
|
|
|
async function doRegister() {
|
|
disableForm.value = true
|
|
showLoader()
|
|
try {
|
|
await apiClient.register(username.value, password.value)
|
|
await doLogin()
|
|
} catch (err) {
|
|
hideLoader()
|
|
if (err instanceof ApiError) {
|
|
await showAlert(err.message)
|
|
} else {
|
|
await showAlert('Request failed: ' + JSON.stringify(err))
|
|
}
|
|
} finally {
|
|
disableForm.value = false
|
|
}
|
|
}
|
|
|
|
function isDataValid() {
|
|
return username.value.length > 0 && password.value.length >= 8
|
|
}
|
|
|
|
function generateSampleData() {
|
|
fetch(import.meta.env.VITE_API_BASE_URL + '/sample-data', {
|
|
method: 'POST'
|
|
})
|
|
}
|
|
</script>
|
|
<template>
|
|
<div class="app-login-panel">
|
|
<h1 style="text-align: center;">Login to <span style="font-family: 'PlaywriteNL';">Finnow</span></h1>
|
|
<AppForm @submit="doLogin()">
|
|
<FormGroup>
|
|
<FormControl label="Username">
|
|
<input type="text" v-model="username" :disabled="disableForm" />
|
|
</FormControl>
|
|
<FormControl label="Password">
|
|
<input id="password-input" type="password" v-model="password" :disabled="disableForm" />
|
|
</FormControl>
|
|
</FormGroup>
|
|
<div style="display: flex; margin-left: 1rem; margin-right: 1rem;">
|
|
<AppButton type="submit" :disabled="disableForm || !isDataValid()" style="flex-grow: 1;">Login
|
|
</AppButton>
|
|
<AppButton button-type="button" button-style="secondary" :disabled="disableForm || !isDataValid()"
|
|
@click="doRegister()">Register</AppButton>
|
|
</div>
|
|
<div v-if="isDev">
|
|
<AppButton button-type="button" @click="generateSampleData()">Generate Sample Data</AppButton>
|
|
</div>
|
|
</AppForm>
|
|
</div>
|
|
</template>
|
|
<style lang="css">
|
|
.app-login-panel {
|
|
max-width: 40ch;
|
|
margin: 0 auto;
|
|
}
|
|
</style>
|