wpw-final/frontend/src/views/core/components/LoginCard.vue
2022-12-02 20:40:23 +07:00

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>