Files
antrean-operasi/pages/auth/Login.vue
T

174 lines
6.1 KiB
Vue

<template>
<div class="authentication bg-gray">
<v-container class="pa-3 auth-login">
<v-row class="h-100vh d-flex justify-center align-center">
<v-col cols="12" class="text-center mt-6">
</v-col>
<v-col cols="12" class="d-flex align-center">
<v-card rounded="md" elevation="10" class="mx-auto">
<div class="pa-3">
<v-row>
<v-col cols="12" md="6" class="border-e px-md-12 px-6 py-md-12 py-6 bg-primary rounded-s-md">
<div class="login-container d-flex flex-column justify-space-between h-100 w-100">
<!-- TOP AREA -->
<div>
<!-- Logo and Title -->
<div class="mb-8">
<div class="d-flex align-center mb-2">
<v-icon size="40" color="white">mdi-hospital-building</v-icon>
<div class="ml-3">
<h2 class="text-h5 font-weight-bold">Antrean Operasi</h2>
<p class="text-caption">
RSUD Dr. Saiful Anwar Provinsi Jawa Timur
</p>
</div>
</div>
</div>
</div>
<!-- Sign In Section -->
<div class="mb-8 pa-4">
<h1 class="text-h3 font-weight-bold mb-6">Login</h1>
<!-- Error Message -->
<v-alert
v-if="errorMessage"
type="error"
closable
class="mb-4"
@click:close="errorMessage = ''"
>
{{ errorMessage }}
</v-alert>
<!-- Success Message -->
<v-alert
v-if="successMessage"
type="success"
class="mb-4"
>
{{ successMessage }}
</v-alert>
<v-btn
color="default"
size="x-large"
block
class="text-none mb-4 text-primary"
elevation="0"
:loading="isLoading"
:disabled="isLoading"
@click="handleLogin"
>
<v-icon left class="mr-3">mdi-account-circle</v-icon>
Log In with Keycloak
</v-btn>
</div>
<!-- BOTTOM AREA -->
<div class="d-flex align-center text-white">
<v-icon size="small" class="mr-2">mdi-lock-outline</v-icon>
<span class="text-caption">Not Authenticated</span>
</div>
</div>
</v-col>
<v-col cols="12" md="6" class="d-md-flex d-none">
<div class="d-flex flex-column justify-center px-md-12 px-6 h-100 align-center">
<div class="mt-16">
<img src="@/assets/images/backgrounds/undraw_wait-in-line_login.svg" alt="matdash-img"
width="300" />
</div>
<v-carousel :continuous="false" :show-arrows="false" cycle height="200" hide-delimiter-background
class="text-center mt-4">
<v-carousel-item v-for="item in AuthCuroselData" :key="item.title">
<h3 class="text-h3 mb-4">{{ item.title }}</h3>
<p class="textSecondary">
{{ item.subtitle }}
</p>
</v-carousel-item>
</v-carousel>
</div>
</v-col>
</v-row>
</div>
</v-card>
</v-col>
<v-col cols="12" class="text-center mt-6">
<p class="text-caption textSecondary">&copy; 2026 RSUD Dr. Saiful Anwar Provinsi Jawa Timur. All rights reserved.</p>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import type { LoginResponse } from '~/types/auth';
const route = useRoute();
const AuthCuroselData = [
{
title: 'Sistem Antrean Operasi',
subtitle: 'Kelola antrean operasi dengan efisien menggunakan sistem antrean.'
}
];
const isLoading = ref(false);
const errorMessage = ref('');
const successMessage = ref('');
// Check for error in URL query parameters
onMounted(() => {
const errorParam = route.query.error as string;
if (errorParam) {
errorMessage.value = decodeURIComponent(errorParam);
}
});
const handleLogin = async (): Promise<void> => {
isLoading.value = true;
errorMessage.value = '';
successMessage.value = '';
try {
console.log('Starting login process...');
// Call API route to initiate Keycloak login process
const response = await $fetch<LoginResponse>('/api/auth/keycloak-login', {
method: 'POST'
});
if (response?.success && response?.data?.authUrl) {
console.log('Redirecting to Keycloak...');
successMessage.value = 'Redirecting to Keycloak...';
// Redirect the user to the Keycloak authorization URL
setTimeout(() => {
window.location.href = response.data!.authUrl;
}, 500);
} else {
throw new Error('Failed to get authorization URL');
}
} catch (error: any) {
console.error('Login error:', error);
// Display the error message
errorMessage.value = `Login failed: ${error.message || 'Please try again.'}`;
} finally {
// Only set isLoading back to false if no redirect is happening
if (!successMessage.value.includes('Redirecting')) {
isLoading.value = false;
}
}
};
/*-For Set Blank Layout-*/
definePageMeta({
layout: "blank",
middleware: "guest"
});
</script>