diff --git a/src/components/authentication/TheForgotPassword.vue b/src/components/authentication/TheForgotPassword.vue index eff721b..e732f96 100644 --- a/src/components/authentication/TheForgotPassword.vue +++ b/src/components/authentication/TheForgotPassword.vue @@ -1,115 +1,412 @@ \ No newline at end of file + +.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; + } +} + diff --git a/src/components/authentication/TheLogin.vue b/src/components/authentication/TheLogin.vue index ab75060..7e08a3b 100644 --- a/src/components/authentication/TheLogin.vue +++ b/src/components/authentication/TheLogin.vue @@ -123,7 +123,28 @@ export default { const authenticationStore = useAuthenticationUserStore(); return { authenticationStore }; }, + mounted() { + this.showEmailVerificationToast(); + }, methods: { + showEmailVerificationToast() { + const { email_verified, message } = this.$route.query; + if (email_verified === undefined) { + return; + } + + const verified = String(email_verified) === "1"; + this.$toast.add({ + severity: verified ? "success" : "error", + summary: verified ? "Pengesahan Emel" : "Pengesahan Emel Gagal", + detail: message || (verified + ? "Emel berjaya disahkan. Sila log masuk." + : "Pautan pengesahan tidak sah."), + life: 10000, + }); + + this.$router.replace({ query: {} }); + }, doLogin() { this.v$.$validate(); if (!this.v$.$error) { @@ -132,24 +153,9 @@ export default { .post("/user/login", this.form) .then((response) => { if (response.data.statusAkaun == 1) { - localStorage.setItem("token", response.data.token); - localStorage.setItem("id", response.data.user.id); - localStorage.setItem("nokp", response.data.user.nokp); - localStorage.setItem("name", response.data.user.name); - localStorage.setItem("email", response.data.user.email); - localStorage.setItem( - "notelbimbit", - response.data.user.notelbimbit - ); - localStorage.setItem("username", response.data.user.username); - this.authenticationStore.$patch({ + this.authenticationStore.setSession({ token: response.data.token, - id: response.data.user.id, - nokp: response.data.user.nokp, - name: response.data.user.name, - email: response.data.user.email, - notelbimbit: response.data.user.notelbimbit, - username: response.data.user.username, + user: response.data.user, }); this.$router.push({ name: "home" }); } else if (response.data.statusAkaun == 0) { @@ -198,6 +204,15 @@ export default { "Sila log masuk menggunakan url https://adminlelong.erahn.com.my ", life: 10000, }); + } else if (response.data.statusAkaun == 7) { + this.$toast.add({ + severity: "warn", + summary: "Emel Belum Disahkan", + detail: + response.data.message || + "Sila sahkan emel anda sebelum log masuk.", + life: 10000, + }); } this.isLoading = false; }) diff --git a/src/components/authentication/TheRegister.vue b/src/components/authentication/TheRegister.vue index c76c481..cd02cd3 100644 --- a/src/components/authentication/TheRegister.vue +++ b/src/components/authentication/TheRegister.vue @@ -334,27 +334,17 @@ export default { .post("/register", this.form) .then((response) => { if (response.data.success == true) { - localStorage.setItem("token", response.data.token); - localStorage.setItem("id", response.data.user.id); - localStorage.setItem("nokp", response.data.user.nokp); - localStorage.setItem("name", response.data.user.name); - localStorage.setItem("email", response.data.user.email); - localStorage.setItem( - "notelbimbit", - response.data.user.notelbimbit - ); - localStorage.setItem("username", response.data.user.username); - this.authenticationStore.$patch({ - token: response.data.token, - id: response.data.user.id, - nokp: response.data.user.nokp, - name: response.data.user.name, - email: response.data.user.email, - notelbimbit: response.data.user.notelbimbit, - username: response.data.user.username, - }); - this.$router.push({ name: "home" }); this.isLoading = false; + this.isDisplayTNC = false; + this.$toast.add({ + severity: "success", + summary: "Pendaftaran Berjaya", + detail: + response.data.message || + "Sila semak emel anda untuk pautan pengesahan.", + life: 10000, + }); + this.$router.push({ name: "login" }); } else if (response.data.success == false) { this.isLoading = false; this.isDisplayTNC = false; @@ -442,11 +432,13 @@ export default { position: relative; min-height: 100vh; + min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 1.5rem; - overflow: hidden; + overflow-x: hidden; + overflow-y: auto; font-family: "Manrope", sans-serif; color: var(--ink); } @@ -901,6 +893,169 @@ export default { overflow: auto; padding-right: 0.25rem; } + +@media (max-width: 960px) { + .register-page { + align-items: flex-start; + padding: 0.85rem; + } + + .register-shell { + grid-template-columns: 1fr; + border-radius: 22px; + width: 100%; + } + + .register-brand { + min-height: auto; + padding: 1.25rem 1.25rem 1rem; + justify-content: flex-start; + } + + .brand-mark { + margin-bottom: 1rem; + } + + .brand-seal { + width: 40px; + height: 40px; + } + + .brand-wordmark { + width: min(140px, 42vw); + } + + .brand-title { + font-size: 1.85rem; + margin-bottom: 0.4rem; + } + + .brand-copy { + max-width: none; + font-size: 0.92rem; + line-height: 1.45; + } + + .register-panel { + max-height: none; + overflow: visible; + padding: 1.25rem 1.15rem 1.5rem; + } + + .panel-header h2 { + font-size: 1.45rem; + } + + .panel-header p { + margin-bottom: 1rem; + font-size: 0.92rem; + } + + .stepper { + grid-template-columns: auto minmax(12px, 1fr) auto minmax(12px, 1fr) auto; + align-items: start; + gap: 0.25rem; + margin-bottom: 1.15rem; + } + + .stepper-item { + flex-direction: column; + align-items: center; + gap: 0.3rem; + padding: 0.15rem; + text-align: center; + } + + .stepper-meta { + justify-items: center; + } + + .stepper-label { + font-size: 0.72rem; + line-height: 1.2; + white-space: normal; + } + + .stepper-hint { + display: none; + } + + .stepper-line { + align-self: start; + margin-top: 0.9rem; + } + + .form-grid, + .actions { + grid-template-columns: 1fr; + } + + .actions { + gap: 0.65rem; + margin-top: 0.5rem; + } + + .ghost-btn, + .submit-btn { + width: 100%; + } + + .field-control-phone { + padding: 0.35rem; + } + + .field-control-phone :deep(.m-phone-number-input) { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; + } + + .field-control-phone :deep(.m-input-wrapper), + .field-control-phone :deep(.m-phone-number-input > *) { + min-width: 0; + max-width: 100%; + } +} + +@media (max-width: 560px) { + .register-page { + padding: 0; + } + + .register-shell { + border-radius: 0; + border: 0; + min-height: 100vh; + min-height: 100dvh; + } + + .register-brand { + padding: 1rem 1rem 0.85rem; + } + + .brand-copy { + display: none; + } + + .register-panel { + padding: 1.1rem 1rem 1.35rem; + flex: 1; + } + + .stepper-index { + width: 1.7rem; + height: 1.7rem; + font-size: 0.78rem; + } + + .stepper-label { + font-size: 0.68rem; + } + + .agree-row { + font-size: 0.88rem; + } +} - diff --git a/src/components/bid-record/BidRecordList.vue b/src/components/bid-record/BidRecordList.vue index 6785f3b..c497544 100644 --- a/src/components/bid-record/BidRecordList.vue +++ b/src/components/bid-record/BidRecordList.vue @@ -231,6 +231,7 @@