|
|
@@ -10,7 +10,12 @@ definePageMeta({
|
|
|
})
|
|
|
|
|
|
const router = useRouter()
|
|
|
-const { login, isAuthenticated } = useAuth()
|
|
|
+const { login, loginWithEmail, isAuthenticated } = useAuth()
|
|
|
+
|
|
|
+const showTestLogin = ref(false)
|
|
|
+const testEmail = ref('')
|
|
|
+const testLoginLoading = ref(false)
|
|
|
+const testLoginError = ref('')
|
|
|
|
|
|
onMounted(() => {
|
|
|
watch(isAuthenticated, (newIsAuthenticated) => {
|
|
|
@@ -28,16 +33,54 @@ const handleLoginSuccess = async (response: CredentialResponse) => {
|
|
|
const handleLoginError = () => {
|
|
|
console.error('Login failed')
|
|
|
}
|
|
|
+
|
|
|
+const openTestLogin = () => {
|
|
|
+ testEmail.value = ''
|
|
|
+ testLoginError.value = ''
|
|
|
+ showTestLogin.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const closeTestLogin = () => {
|
|
|
+ if (testLoginLoading.value)
|
|
|
+ return
|
|
|
+
|
|
|
+ showTestLogin.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const handleTestLogin = async () => {
|
|
|
+ if (!testEmail.value) {
|
|
|
+ testLoginError.value = 'Email is required'
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ testLoginError.value = ''
|
|
|
+ testLoginLoading.value = true
|
|
|
+ const result = await loginWithEmail(testEmail.value.trim())
|
|
|
+ testLoginLoading.value = false
|
|
|
+
|
|
|
+ if (!result) {
|
|
|
+ testLoginError.value = 'Login failed, please check email'
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ showTestLogin.value = false
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
- <div class="login-container min-h-screen flex flex-col justify-between items-center px-8">
|
|
|
+ <div class="login-container min-h-screen flex flex-col justify-end items-center px-8">
|
|
|
<img
|
|
|
src="~/assets/images/auth/logo.png"
|
|
|
alt="logo"
|
|
|
class="login-container__logo"
|
|
|
>
|
|
|
- <div class="login-container__btn">
|
|
|
+ <div class="login-container__btn flex flex-col items-center">
|
|
|
+ <div
|
|
|
+ class="login-container__btn-test"
|
|
|
+ @click="openTestLogin"
|
|
|
+ >
|
|
|
+ !!! TEST ENV LOGIN !!!
|
|
|
+ </div>
|
|
|
<GoogleSignInButton
|
|
|
size="large"
|
|
|
@success="handleLoginSuccess"
|
|
|
@@ -53,18 +96,172 @@ const handleLoginError = () => {
|
|
|
class="text-white"
|
|
|
>privacy policy</a>
|
|
|
</p>
|
|
|
+
|
|
|
+ <div
|
|
|
+ v-if="showTestLogin"
|
|
|
+ class="login-test-modal"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="login-test-modal__mask"
|
|
|
+ @click="closeTestLogin"
|
|
|
+ />
|
|
|
+ <div class="login-test-modal__content">
|
|
|
+ <h3 class="login-test-modal__title">
|
|
|
+ Test Email Login
|
|
|
+ </h3>
|
|
|
+ <input
|
|
|
+ v-model="testEmail"
|
|
|
+ type="email"
|
|
|
+ class="login-test-modal__input"
|
|
|
+ placeholder="Enter test email"
|
|
|
+ >
|
|
|
+ <p
|
|
|
+ v-if="testLoginError"
|
|
|
+ class="login-test-modal__error"
|
|
|
+ >
|
|
|
+ {{ testLoginError }}
|
|
|
+ </p>
|
|
|
+ <div class="login-test-modal__actions">
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ class="login-test-modal__btn login-test-modal__btn--cancel"
|
|
|
+ @click="closeTestLogin"
|
|
|
+ >
|
|
|
+ Cancel
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ type="button"
|
|
|
+ class="login-test-modal__btn login-test-modal__btn--confirm"
|
|
|
+ :disabled="testLoginLoading"
|
|
|
+ @click="handleTestLogin"
|
|
|
+ >
|
|
|
+ <span v-if="!testLoginLoading">Login</span>
|
|
|
+ <span v-else>Logging in...</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.login-container {
|
|
|
- @include bg('~/assets/images/auth/bg.png', 100%);
|
|
|
+ @include bg('~/assets/images/auth/bg.png', 100vw auto);
|
|
|
+ position: relative;
|
|
|
|
|
|
&__logo {
|
|
|
width: 113px;
|
|
|
+ position: absolute;
|
|
|
+ top: px2vw(200);
|
|
|
+ }
|
|
|
+
|
|
|
+ &__btn {
|
|
|
+ gap: 16px;
|
|
|
+
|
|
|
+ &-test {
|
|
|
+ display: flex;
|
|
|
+ cursor: pointer;
|
|
|
+ height: 40px;
|
|
|
+ padding: 8px 24px;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ background: #1D2129;
|
|
|
+ border-radius: 100px;
|
|
|
+ color: #FFF;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
.login-footer {
|
|
|
color: #C7C7C7;
|
|
|
}
|
|
|
+
|
|
|
+.login-test-modal {
|
|
|
+ position: fixed;
|
|
|
+ inset: 0;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ z-index: 1000;
|
|
|
+
|
|
|
+ &__mask {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
+ background: rgba(0, 0, 0, 0.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ &__content {
|
|
|
+ position: relative;
|
|
|
+ width: 80%;
|
|
|
+ max-width: 360px;
|
|
|
+ background: #111827;
|
|
|
+ border-radius: 16px;
|
|
|
+ padding: 20px 16px 16px;
|
|
|
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.4);
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__title {
|
|
|
+ margin-bottom: 12px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__input {
|
|
|
+ width: 100%;
|
|
|
+ padding: 10px 12px;
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #4B5563;
|
|
|
+ background: #1F2937;
|
|
|
+ color: #F9FAFB;
|
|
|
+ font-size: 14px;
|
|
|
+ outline: none;
|
|
|
+
|
|
|
+ &::placeholder {
|
|
|
+ color: #6B7280;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #6366F1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__error {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #FCA5A5;
|
|
|
+ text-align: left;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__actions {
|
|
|
+ margin-top: 16px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__btn {
|
|
|
+ min-width: 80px;
|
|
|
+ height: 32px;
|
|
|
+ border-radius: 999px;
|
|
|
+ font-size: 14px;
|
|
|
+ border: none;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &--cancel {
|
|
|
+ background: #374151;
|
|
|
+ color: #E5E7EB;
|
|
|
+ }
|
|
|
+
|
|
|
+ &--confirm {
|
|
|
+ background: #6366F1;
|
|
|
+ color: #F9FAFB;
|
|
|
+
|
|
|
+ &:disabled {
|
|
|
+ opacity: 0.7;
|
|
|
+ cursor: default;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|