Files
lelong-web-pembida/src/components/authentication/TheForgotPassword.vue
T

413 lines
9.3 KiB
Vue

<template>
<Toast :breakpoints="{ '767px': { width: '100%', right: '0', left: '0' } }" />
<div class="forgot-page">
<div class="forgot-backdrop" aria-hidden="true"></div>
<div class="forgot-shell">
<section class="forgot-brand">
<div class="brand-mark">
<img src="img/e-Rahn_Logo_FA-01.png" alt="" class="brand-seal" />
<img src="img/e-rahn-lelong.png" alt="E-Rahn Lelong" class="brand-wordmark" />
</div>
<h1 class="brand-title">ArrahnBid</h1>
<p class="brand-copy">
Masukkan emel akaun anda dan kami akan hantar pautan untuk tetapkan semula kata laluan.
</p>
</section>
<section class="forgot-panel">
<header class="panel-header">
<h2>Lupa Kata Laluan</h2>
<p>
Belum punya akaun?
<router-link :to="{ name: 'register' }">Daftar sekarang</router-link>
</p>
</header>
<form class="forgot-form" @submit.prevent="doForgotPassword">
<label class="field">
<span class="field-label">Emel</span>
<div class="field-control">
<Mail class="field-icon" :size="18" :stroke-width="1.75" />
<InputText
v-model="email"
type="email"
placeholder="nama@emel.com"
autocomplete="email"
required
/>
</div>
</label>
<button class="submit-btn" type="submit" :disabled="isLoading">
<span>{{ isLoading ? "Sedang hantar..." : "Hantar Pautan" }}</span>
<LoaderCircle v-if="isLoading" class="spin" :size="18" :stroke-width="2" />
<ArrowRight v-else :size="18" :stroke-width="2" />
</button>
</form>
<router-link class="back-link" :to="{ name: 'login' }">
<ChevronLeft :size="16" :stroke-width="2" />
<span>Kembali ke Log Masuk</span>
</router-link>
</section>
</div>
</div>
</template>
<script>
import axios from "axios";
import { ArrowRight, ChevronLeft, LoaderCircle, Mail } from "@lucide/vue";
export default {
name: "ForgotPassword",
components: {
ArrowRight,
ChevronLeft,
LoaderCircle,
Mail,
},
data() {
return {
isLoading: false,
email: "",
};
},
methods: {
doForgotPassword() {
this.isLoading = true;
axios
.post("/forgotPassword", { email: this.email })
.then((response) => {
console.log(response);
if (response.data.success == true) {
this.$swal.fire({
icon: "success",
title: "Pautan Lupa Katalaluan Telah Dihantar!",
text: "Sila semak emel anda untuk tindakan lebih lanjut",
confirmButtonColor: "#344871",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
});
this.email = "";
this.isLoading = false;
} else if (response.data.success == false) {
if (response.data.status == 0) {
this.$toast.add({
severity: "error",
summary: "Emel tidak dijumpai",
detail: "Sila semak emel anda",
life: 10000,
});
this.isLoading = false;
} else if (response.data.status == 500) {
this.$swal.fire({
icon: "error",
title: "Failed!",
text: "There is some issue with email provider, please contact admin.",
confirmButtonColor: "#344871",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
});
this.isLoading = false;
}
}
})
.catch((response) => {
alert(response);
this.isLoading = false;
});
},
},
};
</script>
<style scoped>
@import url("https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Sora:wght@500;600;700&display=swap");
.forgot-page {
--ink: #132a4f;
--navy: #1e417b;
--blue: #2f68c5;
--gold: #fec234;
--panel: rgba(255, 252, 247, 0.94);
--line: rgba(19, 42, 79, 0.12);
--muted: rgba(19, 42, 79, 0.68);
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 1.5rem;
overflow: hidden;
font-family: "Manrope", sans-serif;
color: var(--ink);
}
.forgot-backdrop {
position: absolute;
inset: 0;
background:
linear-gradient(115deg, rgba(19, 42, 79, 0.78) 0%, rgba(30, 65, 123, 0.55) 42%, rgba(254, 194, 52, 0.35) 100%),
url("/src/assets/background-lelong.png") center / cover no-repeat;
transform: scale(1.04);
animation: backdrop-drift 18s ease-in-out infinite alternate;
}
.forgot-shell {
position: relative;
z-index: 1;
width: min(980px, 100%);
display: grid;
grid-template-columns: 1.05fr 0.95fr;
border-radius: 28px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.28);
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(10px);
animation: shell-enter 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.forgot-brand {
padding: 3rem 2.75rem;
color: #fffdf8;
background:
linear-gradient(160deg, rgba(19, 42, 79, 0.28), rgba(47, 104, 197, 0.1)),
radial-gradient(circle at top left, rgba(254, 194, 52, 0.35), transparent 55%);
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 560px;
}
.brand-mark {
display: flex;
align-items: center;
gap: 0.85rem;
margin-bottom: auto;
animation: rise 0.8s 0.1s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.brand-seal {
width: 52px;
height: 52px;
object-fit: contain;
filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.18));
}
.brand-wordmark {
width: min(180px, 50vw);
height: auto;
object-fit: contain;
}
.brand-title {
margin: 0 0 0.75rem;
font-family: "Sora", sans-serif;
font-size: clamp(2.4rem, 4vw, 3.4rem);
font-weight: 700;
letter-spacing: -0.04em;
line-height: 1.05;
animation: rise 0.8s 0.18s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.brand-copy {
margin: 0;
max-width: 30ch;
font-size: 1.05rem;
line-height: 1.55;
color: rgba(255, 253, 248, 0.88);
animation: rise 0.8s 0.26s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.forgot-panel {
background: var(--panel);
padding: 2.75rem 2.5rem;
display: flex;
flex-direction: column;
justify-content: center;
animation: rise 0.8s 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.panel-header h2 {
margin: 0 0 0.4rem;
font-family: "Sora", sans-serif;
font-size: 1.85rem;
letter-spacing: -0.03em;
}
.panel-header p {
margin: 0 0 1.75rem;
color: var(--muted);
}
.panel-header a,
.back-link {
color: var(--blue);
font-weight: 600;
text-decoration: none;
}
.panel-header a:hover,
.back-link:hover {
color: var(--navy);
text-decoration: underline;
}
.forgot-form {
display: grid;
gap: 1rem;
}
.field {
display: grid;
gap: 0.45rem;
}
.field-label {
font-size: 0.92rem;
font-weight: 600;
color: var(--ink);
}
.field-control {
display: flex;
align-items: center;
gap: 0.65rem;
min-height: 3.15rem;
padding: 0 0.95rem;
border: 1px solid var(--line);
border-radius: 14px;
background: #fff;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.field-control:focus-within {
border-color: var(--blue);
box-shadow: 0 0 0 3px rgba(47, 104, 197, 0.14);
}
.field-icon {
flex: 0 0 auto;
color: var(--navy);
opacity: 0.72;
}
.field-control :deep(.p-inputtext) {
flex: 1 1 auto;
width: 100%;
min-width: 0;
border: 0 !important;
box-shadow: none !important;
background: transparent !important;
padding: 0.85rem 0 !important;
font-family: inherit;
font-size: 0.98rem;
color: var(--ink);
}
.submit-btn {
margin-top: 0.35rem;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.55rem;
width: 100%;
min-height: 3.2rem;
border: 0;
border-radius: 14px;
background: linear-gradient(135deg, var(--navy) 0%, var(--blue) 100%);
color: #fff;
font-family: "Sora", sans-serif;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s ease, filter 0.2s ease;
}
.submit-btn:hover:not(:disabled) {
filter: brightness(1.05);
transform: translateY(-1px);
}
.submit-btn:disabled {
opacity: 0.8;
cursor: wait;
}
.back-link {
margin-top: 1.5rem;
display: inline-flex;
align-items: center;
gap: 0.35rem;
width: fit-content;
}
.spin {
animation: spin 0.8s linear infinite;
}
@keyframes shell-enter {
from {
opacity: 0;
transform: translateY(18px) scale(0.985);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes rise {
from {
opacity: 0;
transform: translateY(14px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes backdrop-drift {
from {
transform: scale(1.04) translate3d(0, 0, 0);
}
to {
transform: scale(1.08) translate3d(-1.2%, -0.8%, 0);
}
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@media (max-width: 900px) {
.forgot-shell {
grid-template-columns: 1fr;
}
.forgot-brand {
min-height: auto;
padding: 2rem 1.6rem 1.4rem;
}
.brand-title {
font-size: 2.2rem;
}
.brand-copy {
max-width: none;
}
.forgot-panel {
padding: 1.75rem 1.4rem 2rem;
}
}
</style>