131 lines
5.1 KiB
Vue
131 lines
5.1 KiB
Vue
<script lang="ts" setup>
|
|
import { useHub } from '@/hub';
|
|
import /* * as */structs from '@thriftgen/structs_types';
|
|
import { EyeIcon, EyeSlashIcon } from '@heroicons/vue/24/solid';
|
|
import { computed, ref, watch } from 'vue';
|
|
import AlertBox from '@/components/AlertBox.vue';
|
|
import SpinnerIcon from '@/components/SpinnerIcon.vue';
|
|
|
|
const hub = useHub();
|
|
const emit = defineEmits(['togglePassword', 'onInputChange', 'onLoginSuccess', 'onLoginFailed']);
|
|
|
|
const isPasswordShow = ref(false);
|
|
const isLoading = ref(false);
|
|
const txtUsername = ref('');
|
|
const txtPassword = ref('');
|
|
const formData = computed(() => ({ username: txtUsername.value, password: txtPassword.value }));
|
|
|
|
// togglePassword to show/hide the password
|
|
function togglePassword(ev: Event) {
|
|
ev.preventDefault();
|
|
isPasswordShow.value = !isPasswordShow.value;
|
|
emit('togglePassword', isPasswordShow);
|
|
}
|
|
|
|
// emit event if there's change in username and/or password
|
|
watch(txtUsername, () => {
|
|
emit('onInputChange');
|
|
});
|
|
watch(txtPassword, () => {
|
|
emit('onInputChange');
|
|
});
|
|
|
|
// form submit handler
|
|
async function formSubmit(ev: Event) {
|
|
ev.preventDefault();
|
|
isLoading.value = true; // set this to true first
|
|
try {
|
|
const req = new structs.LoginRequest({
|
|
...formData.value,
|
|
});
|
|
const res = await hub.BizCore.client.login(req);
|
|
if (res) {
|
|
emit('onLoginSuccess', res);
|
|
return;
|
|
}
|
|
console.error('unreachable');
|
|
} catch (e: any) {
|
|
emit('onLoginFailed', e);
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
}
|
|
</script>
|
|
<template>
|
|
<div
|
|
class="block p-6 max-w-lg w-2/3 bg-white rounded-lg border border-gray-200 shadow-md hover:bg-gray-100 dark:bg-gray-800 dark:border-gray-700 dark:hover:bg-gray-700"
|
|
>
|
|
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Login</h5>
|
|
|
|
<form class="mt-6" @submit="formSubmit">
|
|
<AlertBox />
|
|
|
|
<div class="space-y-4">
|
|
<!-- username -->
|
|
<div class="relative">
|
|
<input
|
|
v-model="txtUsername"
|
|
type="text"
|
|
id="txt_username"
|
|
:disabled="isLoading"
|
|
:class="[
|
|
{ disabled: isLoading },
|
|
'block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer',
|
|
]"
|
|
placeholder=" "
|
|
/>
|
|
<label
|
|
for="txt_username"
|
|
class="absolute text-sm text-gray-500 dark:text-gray-400 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 left-1"
|
|
>Username</label
|
|
>
|
|
</div>
|
|
|
|
<!-- password -->
|
|
<div class="flex relative">
|
|
<input
|
|
v-model="txtPassword"
|
|
:type="isPasswordShow ? 'text' : 'password'"
|
|
id="txt_password"
|
|
:disabled="isLoading"
|
|
:class="[
|
|
{ disabled: isLoading },
|
|
'block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded-lg border-1 border-gray-300 appearance-none dark:text-white dark:border-gray-600 dark:focus:border-blue-500 focus:outline-none focus:ring-0 focus:border-blue-600 peer',
|
|
]"
|
|
placeholder=" "
|
|
/>
|
|
<label
|
|
for="txt_password"
|
|
class="absolute text-sm text-gray-500 dark:text-gray-400 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] bg-white dark:bg-gray-900 px-2 peer-focus:px-2 peer-focus:text-blue-600 peer-focus:dark:text-blue-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 left-1"
|
|
>Password</label
|
|
>
|
|
<div class="absolute right-1.5 bottom-1.5">
|
|
<div href="#" @click="togglePassword" class="p-2">
|
|
<EyeIcon v-if="!isPasswordShow" class="w-5 h-5 text-sm text-gray-900" />
|
|
<EyeSlashIcon v-else class="w-5 h-5 text-sm text-gray-900" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-baseline justify-between mt-7">
|
|
<button
|
|
type="submit"
|
|
:disabled="isLoading"
|
|
:class="[
|
|
{ disabled: isLoading },
|
|
'text-white w-full bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800',
|
|
]"
|
|
>
|
|
<span v-if="!isLoading">Login</span>
|
|
<span v-else>
|
|
<SpinnerIcon class="text-white" />
|
|
Loading...
|
|
</span>
|
|
</button>
|
|
|
|
<!-- <a href="#" class="text-sm text-blue-600 hover:underline">Forgot password?</a> -->
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</template>
|