Security/register account (#1)

Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Reviewed-on: #1
Co-authored-by: ISMAIL MASSERAN <ismail@koppkb.com>
Co-committed-by: ISMAIL MASSERAN <ismail@koppkb.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-10-19 13:31:05 +08:00
committed by ismailmasseran
parent 34144ad73e
commit 8b83144617
42 changed files with 12000 additions and 1803 deletions
+3
View File
@@ -0,0 +1,3 @@
BASE_URL = http://localhost:8083
VUE_APP_ROOT_URL = http://localhost:8082/api
+3
View File
@@ -0,0 +1,3 @@
BASE_URL=https://lelong.erahn.com.my
VUE_APP_ROOT_URL=https://adminbid-kopkb.erahn.com.my/api
-1
View File
@@ -2,7 +2,6 @@
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
+3
View File
@@ -7,6 +7,7 @@
"build": "vue-cli-service build"
},
"dependencies": {
"@lucide/vue": "^1.52.0",
"@popperjs/core": "^2.11.5",
"@vuelidate/core": "^2.0.0-alpha.41",
"@vuelidate/validators": "^2.0.0-alpha.29",
@@ -26,7 +27,9 @@
"primeflex": "^3.2.1",
"primeicons": "^6.0.1",
"primevue": "^3.17.0",
"sweetalert2": "^11.26.25",
"v-viewer": "^3.0.11",
"viewerjs": "^1.15.2",
"vue": "^3.2.13",
"vue-html2pdf": "^1.8.0",
"vue-router": "^4.0.14",
+8516
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -22,11 +22,11 @@
odit.</span
>
</div>
<a class="flex align-items-center ml-2 mr-8">
<a class="text-blue" href="#"
><span class="underline font-bold">Learn More</span></a
>
</a>
<div class="flex align-items-center ml-2 mr-8">
<a class="text-blue" href="#">
<span class="underline font-bold">Learn More</span>
</a>
</div>
</div>
<div class="surface-section px-4 py-5 md:px-6 lg:px-8">
<div class="grid">
@@ -1,40 +1,42 @@
<template>
<a href="#" data-bs-toggle="modal" data-bs-target="#exampleModal" class="text-white">
<a href="#" data-bs-toggle="modal" data-bs-target="#exampleModal" class="terms-link">
Terma & Syarat
</a>
<div
class="modal fade"
id="exampleModal"
tabindex="-1"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">
Terma & Syarat
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
<terms-and-conditions-details></terms-and-conditions-details>
</div>
<div class="modal-footer">
<Button
data-bs-dismiss="modal"
class="p-button-sm"
label="Kembali"
></Button>
<Teleport to="body">
<div
class="modal fade terms-modal"
id="exampleModal"
tabindex="-1"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">
Terma & Syarat
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
<terms-and-conditions-details></terms-and-conditions-details>
</div>
<div class="modal-footer">
<Button
data-bs-dismiss="modal"
class="p-button-sm"
label="Kembali"
></Button>
</div>
</div>
</div>
</div>
</div>
</Teleport>
</template>
<script>
@@ -50,4 +52,17 @@ export default {
.paragraph-align {
text-align: justify;
}
.terms-link {
color: inherit;
font-weight: 600;
text-decoration: underline;
}
</style>
<style>
/* Keep modal above login shell (backdrop-filter/transform create a stacking context). */
.terms-modal {
z-index: 2000;
}
</style>
@@ -1,115 +1,412 @@
<template>
<Toast :breakpoints="{ '767px': { width: '100%', right: '0', left: '0' } }" />
<div class="flex main-container min-h-screen align-items-center justify-content-center">
<div class="surface-card fadein p-4 shadow-2 border-round w-11 md:w-10 lg:w-8 xl:w-7 content-bg">
<div class="text-center mb-5">
<div class="text-900 text-3xl font-semibold mb-3">
Lelong Erahn
<!-- <img class="logo-img" src="img/logo_arrahn.png" alt="arrahn-logo" /> -->
</div>
<span class="text-600 font-medium line-height-3">Belum punyai akaun?</span>
<router-link v-bind:to="{ name: 'register' }"
class="font-medium no-underline ml-2 text-blue-500 cursor-pointer">Daftar sekarang!</router-link>
</div>
<form @submit.prevent="submit">
<div class="px-0 text-center md:px-8">
<div class="field grid">
<label for="firstname3" class="justify-content-end" style="width: 170px">Emel</label>
<div class="col">
<span class="p-input-icon-right">
<i class="pi pi-user"></i>
<InputText class="mb-2" type="text" v-model="email" required></InputText>
</span>
</div>
</div>
<div class="">
<Button @click="doForgotPassword()" type="submit" class="p-button-sm" label="Lupa Katalaluan"
icon="pi pi-sign-in" :loading="isLoading" iconPos="right"></Button>
</div>
</div>
</form>
<div class="mt-3 text-center">
<router-link v-bind:to="{ name: 'login' }">Kembali ke Log Masuk</router-link>
</div>
<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: "Login",
data() {
return {
isLoading: false,
email: "",
};
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;
});
},
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,
});
}
}
})
.catch((response) => {
alert(response);
this.isLoading = false;
});
}
}
}
},
};
</script>
<style scoped>
.main-container {
background: url("/src/assets/background-lelong.png");
background-position: center;
background-size: cover;
@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);
}
.content-bg {
background: #fff9f9eb !important;
.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;
}
.logo-img {
width: 84px;
height: 44px;
.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>
+436 -113
View File
@@ -1,73 +1,91 @@
<template>
<Toast :breakpoints="{ '767px': { width: '100%', right: '0', left: '0' } }" />
<div class="flex main-container min-h-screen align-items-center justify-content-center">
<div class="surface-card fadein p-4 shadow-8 border-round w-11 md:w-10 lg:w-8 xl:w-7">
<div>
<div class="row">
<div class="col-md-2 d-flex flex-column justify-content-center align-items-left" style="margin-right: -65px">
<img class="logo-img1" src="img/e-Rahn_Logo_FA-01.png" alt="erahn-logo" />
</div>
<!-- <div class="col-md-2 d-flex flex-column justify-content-center align-items-left">
<img class="logo-img2" src="img/Logo KoPKB_Final.png" alt="erahn-logo" />
</div> -->
<div class="col-md-2 d-flex flex-column justify-content-center align-items-left" style="margin-left: -65px">
<div class="login-page">
<div class="login-backdrop" aria-hidden="true"></div>
</div>
<div class="login-shell">
<section class="login-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>
</div>
<div class="text-center mb-5">
<!-- <img class="logo-img" src="img/bidder.png" alt="erahn-logo" /> -->
<img class="logo-img3 mb-3" src="img/e-rahn-lelong.png" alt="erahn-logo">
<div class="text-200 text-3xl font-semibold mb-3">Log Masuk</div>
<span class="text-200 font-medium line-height-3">Belum punyai akaun?</span>
<router-link v-bind:to="{ name: 'register' }" class="font-medium ml-2 text-blue cursor-pointer">Daftar sekarang!
</router-link>
</div>
<form @submit.prevent="submit">
<div class="px-0 text-center md:px-8">
<div class="field grid">
<!-- <label for="firstname3" class="justify-content-end"
style="width: 170px">Username</label> -->
<div class="col">
<span class="p-input-icon-right">
<i class="pi pi-user" />
<InputText class="mb-2" v-model="form.username" type="text" placeholder="ID Pengguna" required>
</InputText>
</span>
<h1 class="brand-title">ArrahnBid</h1>
<p class="brand-copy">
Platform bidaan Ar-Rahn yang lebih pantas, jelas, dan selamat untuk anda.
</p>
</section>
<section class="login-panel">
<header class="panel-header">
<h2>Log Masuk</h2>
<p>
Belum punya akaun?
<router-link :to="{ name: 'register' }">Daftar sekarang</router-link>
</p>
</header>
<form class="login-form" @submit.prevent="doLogin">
<label class="field">
<span class="field-label">ID Pengguna</span>
<div class="field-control" :class="{ 'is-invalid': v$.form.username.$error }">
<User class="field-icon" :size="18" :stroke-width="1.75" />
<InputText
v-model="form.username"
type="text"
placeholder="Masukkan ID pengguna"
autocomplete="username"
required
/>
</div>
<InlineMessage class="flex-auto" v-if="v$.form.username.$error">Username diperlukan</InlineMessage>
</div>
<div class="field grid">
<!-- <label for="firstname3"
class="justify-content-end"
style="width: 170px">Kata Laluan</label> -->
<div class="col">
<span class="p-input-icon-left">
<i class="pi pi-user" />
<Password class="mb-2" v-model="form.password" placeholder="Katalaluan" toggleMask :feedback="false" />
</span>
<InlineMessage v-if="v$.form.username.$error" class="field-error">
Username diperlukan
</InlineMessage>
</label>
<label class="field">
<span class="field-label">Kata Laluan</span>
<div class="field-control" :class="{ 'is-invalid': v$.form.password.$error }">
<Lock class="field-icon" :size="18" :stroke-width="1.75" />
<InputText
v-model="form.password"
:type="showPassword ? 'text' : 'password'"
placeholder="Masukkan kata laluan"
autocomplete="current-password"
required
/>
<button
class="reveal-btn"
type="button"
:aria-label="showPassword ? 'Sembunyikan kata laluan' : 'Tunjuk kata laluan'"
@click="showPassword = !showPassword"
>
<EyeOff v-if="showPassword" :size="18" :stroke-width="1.75" />
<Eye v-else :size="18" :stroke-width="1.75" />
</button>
</div>
<InlineMessage class="flex-auto" v-if="v$.form.password.$error">Kata laluan diperlukan</InlineMessage>
</div>
<div class="">
<Button @click="doLogin()" type="submit" class="p-button-sm" label="Log Masuk" icon="pi pi-sign-in"
:loading="isLoading" iconPos="right"></Button>
</div>
<div class="mt-3">
<router-link v-bind:to="{ name: 'forgot-password' }">Lupa Katalaluan
<InlineMessage v-if="v$.form.password.$error" class="field-error">
Kata laluan diperlukan
</InlineMessage>
</label>
<div class="form-row">
<router-link class="forgot-link" :to="{ name: 'forgot-password' }">
Lupa kata laluan?
</router-link>
</div>
<div class="flex alin justify-content-center mt-4 text-hover">
<div class="btn btn-warning btn-sm">
<terms-and-conditions></terms-and-conditions>
</div>
<!-- <a class="btn btn-info btn-sm" href="https://lelong.arrahn.com.my"
>Pautan Sistem Lelong</a
> -->
</div>
</div>
</form>
<button class="submit-btn" type="submit" :disabled="isLoading">
<span>{{ isLoading ? "Sedang log masuk..." : "Log Masuk" }}</span>
<LoaderCircle v-if="isLoading" class="spin" :size="18" :stroke-width="2" />
<ArrowRight v-else :size="18" :stroke-width="2" />
</button>
</form>
<footer class="panel-footer">
<FileText :size="16" :stroke-width="1.75" />
<terms-and-conditions />
</footer>
</section>
</div>
</div>
</template>
@@ -76,10 +94,20 @@
import axios from "axios";
import useVuelidate from "@vuelidate/core";
import { required } from "@vuelidate/validators";
import { useAuthenticationUserStore } from "@/store/modules/authentication"
import { ArrowRight, Eye, EyeOff, FileText, LoaderCircle, Lock, User } from "@lucide/vue";
import { useAuthenticationUserStore } from "@/store/modules/authentication";
export default {
name: "Login",
components: {
ArrowRight,
Eye,
EyeOff,
FileText,
LoaderCircle,
Lock,
User,
},
data() {
return {
v$: useVuelidate(),
@@ -88,13 +116,35 @@ export default {
password: "",
},
isLoading: false,
showPassword: false,
};
},
setup() {
const authenticationStore = useAuthenticationUserStore()
return { authenticationStore }
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) {
@@ -102,27 +152,11 @@ export default {
axios
.post("/user/login", this.form)
.then((response) => {
// console.log("doLogin", 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) {
this.$toast.add({
@@ -170,11 +204,19 @@ 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;
})
.catch((response) => {
// alert(response.message);
console.log(response);
this.isLoading = false;
});
@@ -193,45 +235,326 @@ export default {
</script>
<style scoped>
.main-container {
/* background: linear-gradient(
135deg,
rgba(139, 198, 236, 0.3) 0%,
#9599e2 100%
),
url("/src/assets/background_arrahn.jpg"); */
background-image: url("/src/assets/background-lelong.png");
background-color: #fec234;
background-position: center;
background-size: cover;
@import url("https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&family=Sora:wght@500;600;700&display=swap");
.login-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);
}
.content-bg {
background: #fff9f9eb !important;
.login-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;
}
.logo-img {
color: white;
width: 180px;
height: 150px;
.login-shell {
position: relative;
z-index: 1;
width: min(980px, 100%);
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 0;
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;
}
.logo-img1 {
width: 50px;
height: 50px;
.login-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;
}
.logo-img2 {
width: 50px;
height: 60px;
.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;
}
.logo-img3 {
width: 150px;
height: 30px;
.brand-seal {
width: 52px;
height: 52px;
object-fit: contain;
filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.18));
}
/* .border-round{
border-radius:50px;
} */
.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: 28ch;
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;
}
.login-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,
.forgot-link,
.panel-footer :deep(.terms-link) {
color: var(--blue);
font-weight: 600;
text-decoration: none;
}
.panel-header a:hover,
.forgot-link:hover,
.panel-footer :deep(.terms-link):hover {
color: var(--navy);
text-decoration: underline;
}
.login-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-control.is-invalid {
border-color: #d14343;
}
.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);
}
.reveal-btn {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0.2rem;
border: 0;
background: transparent;
color: var(--navy);
opacity: 0.7;
cursor: pointer;
border-radius: 8px;
}
.reveal-btn:hover {
opacity: 1;
background: rgba(30, 65, 123, 0.06);
}
.field-error {
width: fit-content;
}
.form-row {
display: flex;
justify-content: flex-end;
margin-top: -0.15rem;
}
.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;
}
.panel-footer {
margin-top: 1.75rem;
display: inline-flex;
align-items: center;
gap: 0.45rem;
color: var(--muted);
font-size: 0.92rem;
}
.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) {
.login-shell {
grid-template-columns: 1fr;
}
.login-brand {
min-height: auto;
padding: 2rem 1.6rem 1.4rem;
}
.brand-title {
font-size: 2.2rem;
}
.brand-copy {
max-width: none;
}
.login-panel {
padding: 1.75rem 1.4rem 2rem;
}
}
</style>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,547 @@
<template>
<Toast :breakpoints="{ '767px': { width: '100%', right: '0', left: '0' } }" />
<div class="reset-page">
<div class="reset-backdrop" aria-hidden="true"></div>
<div class="reset-shell">
<section class="reset-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">
Tetapkan kata laluan baharu untuk akaun anda dan teruskan bidaan dengan selamat.
</p>
</section>
<section class="reset-panel">
<header class="panel-header">
<h2>Tukar Kata Laluan</h2>
<p v-if="email">Emel: {{ email }}</p>
<p v-else-if="isValidating">Sedang mengesahkan pautan...</p>
<p v-else-if="!isTokenValid">Pautan tidak sah atau telah tamat tempoh.</p>
</header>
<form
v-if="isTokenValid"
class="reset-form"
@submit.prevent="doResetPassword"
>
<label class="field">
<span class="field-label">Kata Laluan Baru</span>
<div class="field-control" :class="{ 'is-invalid': passwordError }">
<Lock class="field-icon" :size="18" :stroke-width="1.75" />
<InputText
v-model="password"
:type="showPassword ? 'text' : 'password'"
placeholder="Masukkan kata laluan baru"
autocomplete="new-password"
required
minlength="6"
/>
<button
class="reveal-btn"
type="button"
:aria-label="showPassword ? 'Sembunyikan kata laluan' : 'Tunjuk kata laluan'"
@click="showPassword = !showPassword"
>
<EyeOff v-if="showPassword" :size="18" :stroke-width="1.75" />
<Eye v-else :size="18" :stroke-width="1.75" />
</button>
</div>
<InlineMessage v-if="passwordError" class="field-error">
{{ passwordError }}
</InlineMessage>
</label>
<label class="field">
<span class="field-label">Ulang Kata Laluan Baru</span>
<div class="field-control" :class="{ 'is-invalid': confirmError }">
<Lock class="field-icon" :size="18" :stroke-width="1.75" />
<InputText
v-model="confirmPassword"
:type="showConfirmPassword ? 'text' : 'password'"
placeholder="Ulang kata laluan baru"
autocomplete="new-password"
required
minlength="6"
/>
<button
class="reveal-btn"
type="button"
:aria-label="showConfirmPassword ? 'Sembunyikan kata laluan' : 'Tunjuk kata laluan'"
@click="showConfirmPassword = !showConfirmPassword"
>
<EyeOff v-if="showConfirmPassword" :size="18" :stroke-width="1.75" />
<Eye v-else :size="18" :stroke-width="1.75" />
</button>
</div>
<InlineMessage v-if="confirmError" class="field-error">
{{ confirmError }}
</InlineMessage>
</label>
<button class="submit-btn" type="submit" :disabled="isLoading">
<span>{{ isLoading ? "Sedang kemaskini..." : "Tukar Kata Laluan" }}</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,
Eye,
EyeOff,
LoaderCircle,
Lock,
} from "@lucide/vue";
export default {
name: "ResetPassword",
components: {
ArrowRight,
ChevronLeft,
Eye,
EyeOff,
LoaderCircle,
Lock,
},
data() {
return {
isValidating: true,
isTokenValid: false,
isLoading: false,
email: "",
password: "",
confirmPassword: "",
passwordError: "",
confirmError: "",
showPassword: false,
showConfirmPassword: false,
};
},
computed: {
token() {
return this.$route.params.token;
},
},
created() {
this.validateToken();
},
methods: {
validateToken() {
this.isValidating = true;
axios
.get(`/resetPassword/${this.token}`)
.then((response) => {
if (response.data.success) {
this.isTokenValid = true;
this.email = response.data.email || "";
} else {
this.isTokenValid = false;
}
})
.catch(() => {
this.isTokenValid = false;
this.$toast.add({
severity: "error",
summary: "Pautan tidak sah",
detail: "Pautan tetapan semula kata laluan tidak sah atau telah tamat tempoh.",
life: 8000,
});
})
.finally(() => {
this.isValidating = false;
});
},
doResetPassword() {
this.passwordError = "";
this.confirmError = "";
if (!this.password || this.password.length < 6) {
this.passwordError = "Kata laluan mestilah sekurang-kurangnya 6 aksara.";
return;
}
if (this.password !== this.confirmPassword) {
this.confirmError = "Kata laluan tidak sepadan.";
return;
}
this.isLoading = true;
axios
.post("/resetPassword", {
token: this.token,
password: this.password,
confirm_password: this.confirmPassword,
})
.then((response) => {
if (response.data.success) {
this.$swal
.fire({
icon: "success",
title: "Katalaluan Dikemaskini!",
text: response.data.message || "Sila log masuk dengan kata laluan baharu anda.",
confirmButtonColor: "#344871",
confirmButtonText: "Log Masuk",
allowOutsideClick: false,
allowEscapeKey: false,
})
.then(() => {
this.$router.push({ name: "login" });
});
} else {
this.$toast.add({
severity: "error",
summary: "Gagal",
detail: response.data.message || "Tidak dapat kemaskini kata laluan.",
life: 8000,
});
}
})
.catch((error) => {
const message =
error.response?.data?.message ||
"Tidak dapat kemaskini kata laluan. Sila cuba lagi.";
this.$toast.add({
severity: "error",
summary: "Gagal",
detail: message,
life: 8000,
});
})
.finally(() => {
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");
.reset-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);
}
.reset-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;
}
.reset-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;
}
.reset-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;
}
.reset-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;
}
.reset-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-control.is-invalid {
border-color: #d14343;
}
.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);
}
.reveal-btn {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
padding: 0.2rem;
border: 0;
background: transparent;
color: var(--navy);
opacity: 0.7;
cursor: pointer;
border-radius: 8px;
}
.reveal-btn:hover {
opacity: 1;
background: rgba(30, 65, 123, 0.06);
}
.field-error {
width: fit-content;
}
.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) {
.reset-shell {
grid-template-columns: 1fr;
}
.reset-brand {
min-height: auto;
padding: 2rem 1.6rem 1.4rem;
}
.brand-title {
font-size: 2.2rem;
}
.brand-copy {
max-width: none;
}
.reset-panel {
padding: 1.75rem 1.4rem 2rem;
}
}
</style>
+64 -68
View File
@@ -1,6 +1,6 @@
<template>
<div>
<VueSidebarMenuAkahon />
<VueSidebarMenuAkahon />
</div>
<div v-if="isLoading" class="fadein animation-duration-400">
<div class="flex align-items-center justify-content-center container-height">
@@ -16,24 +16,25 @@
<template #title>
<div class="grid justify-content-between">
<div class="font-normal">Rekod Bidaan Hari Ini : <span class="white-space-nowrap">{{ date }}</span></div>
<div class="text-xs align-self-center fst-italic fw-lighter text-danger">*Sistem akan menjana pemenang setelah masa bidaan tamat pada {{lelongDetail.masatamat_lelong}}</div>
<div class="text-xs align-self-center fst-italic fw-lighter text-danger">*Sistem akan menjana pemenang
setelah masa bidaan tamat pada {{ lelongDetail.masatamat_lelong }}</div>
</div>
</template>
<template #content>
<Accordion :multiple="true">
<AccordionTab v-for="bid in listBid" v-bind:key="bid">
<Accordion :multiple="true" class="bid-accordion">
<AccordionTab v-for="bid in listBid" :key="bid.caw_name || bid.id">
<template #header>
<div class="flex justify-content-between w-100">
<div class="align-self-center" style="margin: 5px">
<div class="bid-accordion-header">
<span class="bid-accordion-title">
{{ bid.caw_name }}
</div>
<div class="style-info">
</span>
<span class="style-info">
Jumlah RM{{
bid.total_bidaan
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}
</div>
</span>
</div>
</template>
<div class="overflow-x-auto">
@@ -46,19 +47,12 @@
<td>Berat</td>
<td style="min-width: 120px">Harga Bida</td>
</tr>
<tr
v-for="(item, index) in bid.lelongbid"
v-bind:key="item"
>
<tr v-for="(item, index) in bid.lelongbid" v-bind:key="item">
<td>{{ index + 1 }}</td>
<td>
<a
href="#"
data-bs-toggle="modal"
data-bs-target="#marhunModal"
v-on:click="marhunModal(item)"
>{{ item.norujukan }}</a
>
<a href="#" data-bs-toggle="modal" data-bs-target="#marhunModal"
v-on:click="marhunModal(item)">{{
item.norujukan }}</a>
</td>
<td>{{ item.masa_bidaan }}</td>
<td>{{ item.berat }}g</td>
@@ -91,9 +85,7 @@
</div>
</div>
<div v-else>
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-book text-8xl text-400"></i>
@@ -102,43 +94,28 @@
<span class="text-400">Tiada Rekod Bidaan Hari Ini.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'home' }">Utama</router-link>
untuk jadual lelongan.</span
>
untuk jadual lelongan.</span>
</div>
</div>
</div>
</div>
<!-- MARHUN MODAL -->
<div
class="modal fade"
id="marhunModal"
tabindex="-1"
aria-labelledby="marhunModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
>
<div class="modal fade" id="marhunModal" tabindex="-1" aria-labelledby="marhunModalLabel" aria-hidden="true"
data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="marhunModalLabel">
{{ theData.norujukan }}
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="grid">
<div
class="col-12 lg:col-6"
style="
<div class="col-12 lg:col-6" style="
display: flex;
justify-content: center;
align-items: center;
@@ -146,14 +123,10 @@
min-width: 300px;
max-height: 600px;
max-width: 600px;
"
>
<item-master-image-modal
v-if="theData.filemarhun"
v-bind:key="reloadImageComponent"
">
<item-master-image-modal v-if="theData.filemarhun" v-bind:key="reloadImageComponent"
v-bind:norujukan="theData.norujukan"
v-bind:filemarhun_id="theData.filemarhun[0].id"
></item-master-image-modal>
v-bind:filemarhun_id="theData.filemarhun[0].id"></item-master-image-modal>
<p v-else style="text-align: center; width: 100%">
Image Unavailable
</p>
@@ -169,10 +142,7 @@
<th style="min-width: 42px">Berat</th>
<th style="min-width: 102px">Harga Asas</th>
</tr>
<tr
v-for="(marhun, index) in theData.lelongbidmarhun"
v-bind:key="marhun"
>
<tr v-for="(marhun, index) in theData.lelongbidmarhun" v-bind:key="marhun">
<td>{{ index + 1 }}</td>
<td>{{ marhun.marhun }}</td>
<td>{{ marhun.karat }}</td>
@@ -218,11 +188,7 @@
</div>
</div>
<div class="modal-footer">
<Button
class="p-button-sm"
label="Kembali"
data-bs-dismiss="modal"
/>
<Button class="p-button-sm" label="Kembali" data-bs-dismiss="modal" />
</div>
</div>
</div>
@@ -231,6 +197,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import ItemMasterImageModal from "../list/ItemMasterImageModal.vue";
@@ -248,7 +215,7 @@ export default {
date: "",
lelongDetail: "",
reloadImageComponent: 0,
// userId: localStorage.getItem("id"),
// userId: useAuthenticationUserStore().id,
};
},
mounted: function () {
@@ -268,9 +235,9 @@ export default {
bidRecord() {
this.isLoading = true;
axios
.get("/bidRecordByCawangan/" + localStorage.getItem("id"), {
.get("/bidRecordByCawangan/" + useAuthenticationUserStore().id, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -303,17 +270,46 @@ export default {
min-height: 70vh;
}
.bid-accordion :deep(.p-accordion-header-link) {
display: flex;
align-items: center;
gap: 0.75rem;
}
.bid-accordion :deep(.p-accordion-toggle-icon) {
flex-shrink: 0;
margin-right: 0;
}
.bid-accordion-header {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1 1 auto;
min-width: 0;
gap: 0.75rem;
}
.bid-accordion-title {
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.style-info {
background: #e4f8f0;
border: solid #1ea97c;
border-width: 0px;
border-width: 0.1px;
color: #1ea97c;
font-size: 1rem;
font-size: 0.95rem;
align-items: center;
display: flex;
padding: 0.4rem 0.9rem;
display: inline-flex;
padding: 0.35rem 0.75rem;
margin: 0;
border-radius: 6px;
font-weight: 400;
font-weight: 700;
white-space: nowrap;
flex-shrink: 0;
}
</style>
+223 -336
View File
@@ -1,18 +1,12 @@
<template>
<div v-if="isLoading" class="fadein animation-duration-400">
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<div
v-else
style="min-height: 70vh"
class="container fadein animation-duration-400"
>
<div v-else style="min-height: 70vh" class="container fadein animation-duration-400">
<div v-if="isSuccess" class="row">
<div class="col-12 lg:col-9">
<Card>
@@ -20,24 +14,24 @@
<div class="font-normal">Senarai Troli</div>
</template>
<template #content>
<Accordion :multiple="true">
<AccordionTab v-for="item in listItems" v-bind:key="item">
<Accordion :multiple="true" class="cart-accordion">
<AccordionTab v-for="item in listItems" :key="item.caw_name || item.id">
<template #header>
<div class="flex justify-content-between w-100">
<div class="align-self-center" style="margin: 5px">
<div class="cart-accordion-header">
<span class="cart-accordion-title">
{{ item.caw_name }}
</div>
<div class="style-info">
</span>
<span class="style-info">
Jumlah RM{{
item.total_bidaan
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}
</div>
</span>
</div>
</template>
<div class="overflow-x-auto">
<table class="table text-center table-bordered table-hover">
<table class="table text-center table-bordered table-hover mb-0">
<tbody>
<tr class="table-light">
<td>Bil</td>
@@ -48,18 +42,11 @@
<td style="min-width: 170px">Tambahan Bidaan</td>
<td>Tindakan</td>
</tr>
<tr
v-for="(surat, index) in item.lelongbid"
:key="surat.id"
>
<tr v-for="(surat, index) in item.lelongbid" :key="surat.id">
<td>{{ index + 1 }}</td>
<td>
<a
href="#"
data-bs-toggle="modal"
data-bs-target="#marhunModal"
v-on:click="openModal(surat)"
>
<a href="#" data-bs-toggle="modal" data-bs-target="#marhunModal"
v-on:click="openModal(surat)">
{{ surat.norujukan }}
</a>
</td>
@@ -78,28 +65,18 @@
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}
</td>
<th>
<td class="font-bold">
RM{{
surat.tambahanbidaan
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}
</th>
<td>
<Button
icon="pi pi-trash"
data-bs-toggle="modal"
data-bs-target="#deleteModal"
v-on:click="openModal(surat)"
class="p-button-text p-button-danger"
/>
<Button
icon="pi pi-file-edit"
data-bs-toggle="modal"
data-bs-target="#editModal"
v-on:click="openModal(surat)"
class="p-button-warning p-button-text"
/>
</td>
<td class="white-space-nowrap">
<Button icon="pi pi-trash" data-bs-toggle="modal" data-bs-target="#deleteModal"
v-on:click="openModal(surat)" class="p-button-text p-button-danger" />
<Button icon="pi pi-file-edit" data-bs-toggle="modal" data-bs-target="#editModal"
v-on:click="openModal(surat)" class="p-button-warning p-button-text" />
</td>
</tr>
<tr style="text-transform: uppercase">
@@ -130,15 +107,11 @@
</template>
<template #content>
<div>
<i class="pi pi-paperclip text-primary"
><span class="ml-1">Jumlah Surat</span></i
>
<i class="pi pi-paperclip text-primary"><span class="ml-1">Jumlah Surat</span></i>
<p>{{ masterTotalSurat }}</p>
</div>
<div>
<i class="pi pi-wallet text-primary"
><span class="ml-1">Jumlah Kesuluruhan Bidaan</span></i
>
<i class="pi pi-wallet text-primary"><span class="ml-1">Jumlah Kesuluruhan Bidaan</span></i>
<p class="font-bold text-xl">
RM{{
@@ -148,17 +121,10 @@
}}
</p>
</div>
<Button
label="Teruskan"
class="p-button-sm w-full"
v-on:click="openModalNew()"
/>
<Button label="Teruskan" class="p-button-sm w-full" v-on:click="openModalNew()" />
<div class="bounce-up-down">
<div class="info-teruskan-icon">
<i
class="pi pi-arrow-circle-up text-3xl"
style="color: #ff5757"
></i>
<i class="pi pi-arrow-circle-up text-3xl" style="color: #ff5757"></i>
</div>
<div class="info-teruskan">
Sila klik 'Teruskan' jika pasti untuk meneruskan bidaan ini.
@@ -169,9 +135,7 @@
</div>
</div>
<div v-else>
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-shopping-cart text-8xl text-400"></i>
@@ -180,43 +144,28 @@
<span class="text-400">Tiada Data Dalam Troli.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'list' }">Senarai</router-link>
untuk tambah item ke troli.</span
>
untuk tambah item ke troli.</span>
</div>
</div>
</div>
</div>
<!-- MARHUN MODAL -->
<div
class="modal fade"
id="marhunModal"
tabindex="-1"
aria-labelledby="marhunModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
>
<div class="modal fade" id="marhunModal" tabindex="-1" aria-labelledby="marhunModalLabel" aria-hidden="true"
data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="marhunModalLabel">
{{ theSurat.norujukan }}
</h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="grid">
<div
class="col-12 lg:col-6"
style="
<div class="col-12 lg:col-6" style="
display: flex;
justify-content: center;
align-items: center;
@@ -224,14 +173,10 @@
min-width: 300px;
max-height: 600px;
max-width: 600px;
"
>
<item-master-image-modal
v-if="theSurat.filemarhun"
v-bind:key="reloadImageComponent"
">
<item-master-image-modal v-if="theSurat.filemarhun" v-bind:key="reloadImageComponent"
v-bind:norujukan="theSurat.norujukan"
v-bind:filemarhun_id="theSurat.filemarhun[0].id"
></item-master-image-modal>
v-bind:filemarhun_id="theSurat.filemarhun[0].id"></item-master-image-modal>
<p v-else style="text-align: center; width: 100%">
Image Unavailable
</p>
@@ -247,10 +192,7 @@
<td style="min-width: 42px">Berat</td>
<td style="min-width: 102px">Harga Asas</td>
</tr>
<tr
v-for="(data, index) in theSurat.lelongbidmarhun"
v-bind:key="data"
>
<tr v-for="(data, index) in theSurat.lelongbidmarhun" v-bind:key="data">
<td>{{ index + 1 }}</td>
<td>{{ data.marhun }}</td>
<td>{{ data.karat }}</td>
@@ -292,59 +234,30 @@
</div>
</div>
</div>
<Button
icon="pi pi-trash"
label="Padam Surat"
data-bs-toggle="modal"
iconPos="right"
data-bs-target="#deleteModal"
v-on:click="openModal(theSurat)"
class="p-button-text p-button-danger"
/>
<Button
icon="pi pi-file-edit"
label="Ubah Bidaan"
data-bs-toggle="modal"
iconPos="right"
data-bs-target="#editModal"
v-on:click="openModal(theSurat)"
class="p-button-warning p-button-text"
/>
<Button icon="pi pi-trash" label="Padam Surat" data-bs-toggle="modal" iconPos="right"
data-bs-target="#deleteModal" v-on:click="openModal(theSurat)"
class="p-button-text p-button-danger" />
<Button icon="pi pi-file-edit" label="Ubah Bidaan" data-bs-toggle="modal" iconPos="right"
data-bs-target="#editModal" v-on:click="openModal(theSurat)" class="p-button-warning p-button-text" />
</div>
</div>
</div>
<div class="modal-footer">
<Button
class="p-button-sm"
label="Kembali"
data-bs-dismiss="modal"
/>
<Button class="p-button-sm" label="Kembali" data-bs-dismiss="modal" />
</div>
</div>
</div>
</div>
<!-- EDIT MODAL -->
<div
class="modal fade"
id="editModal"
tabindex="-1"
aria-labelledby="editModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
>
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true"
data-bs-backdrop="static">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">
{{ theSurat.norujukan }}
</h5>
<button
type="button"
class="btn-close"
ref="editClose"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" ref="editClose" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
@@ -352,18 +265,13 @@
<div class="col">
<div class="row justify-content-center">
<div class="col-6">
<label class="col-form-label text-end"
>Jumlah Harga Asas (A)</label
>
<label class="col-form-label text-end">Jumlah Harga Asas (A)</label>
</div>
<div class="col-6">
<div class="input-group mb-3">
<span class="input-group-text">RM</span>
<div
style="background-color: #e9ecef; padding-bottom: 0px"
class="form-control text-start justify-content-start"
disabled
>
<div style="background-color: #e9ecef; padding-bottom: 0px"
class="form-control text-start justify-content-start" disabled>
{{
theSurat.hargaasas
?.toString()
@@ -375,19 +283,12 @@
</div>
<div class="row justify-content-center">
<div class="col-6">
<label class="col-form-label text-end"
>Jumlah Harga Bida (B)</label
>
<label class="col-form-label text-end">Jumlah Harga Bida (B)</label>
</div>
<div class="col-6">
<div class="input-group mb-3">
<span class="input-group-text">RM</span>
<input
type="text"
class="form-control"
v-model="jumlahBidaan"
v-on:keyup="calcDiff()"
/>
<input type="text" class="form-control" v-model="jumlahBidaan" v-on:keyup="calcDiff()" />
</div>
</div>
</div>
@@ -422,43 +323,21 @@
</div>
</div>
<div class="modal-footer">
<Button
class="p-button-sm p-button-danger m-1"
label="Batal"
data-bs-dismiss="modal"
/>
<Button
class="p-button-sm p-button-success m-1"
icon="pi pi-file-edit"
iconPos="right"
label="Ubah"
:loading="isLoadingUbah"
@click="updateItem(theSurat)"
/>
<Button class="p-button-sm p-button-danger m-1" label="Batal" data-bs-dismiss="modal" />
<Button class="p-button-sm p-button-success m-1" icon="pi pi-file-edit" iconPos="right" label="Ubah"
:loading="isLoadingUbah" @click="updateItem(theSurat)" />
</div>
</div>
</div>
</div>
<!-- DELETE MODAL -->
<div
class="modal fade"
id="deleteModal"
tabindex="-1"
aria-labelledby="deleteModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true"
data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content text-center">
<div class="modal-header">
<button
type="button"
class="btn-close"
ref="deleteClose"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" ref="deleteClose" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
@@ -491,44 +370,22 @@
</p>
</div>
<div class="modal-footer">
<Button
class="p-button-sm p-button-danger mr-2"
label="Batal"
data-bs-dismiss="modal"
/>
<Button
class="p-button-sm p-button-success"
icon="pi pi-trash"
iconPos="right"
label="Padam"
:loading="isLoadingPadam"
@click="deleteItem(theSurat)"
/>
<Button class="p-button-sm p-button-danger mr-2" label="Batal" data-bs-dismiss="modal" />
<Button class="p-button-sm p-button-success" icon="pi pi-trash" iconPos="right" label="Padam"
:loading="isLoadingPadam" @click="deleteItem(theSurat)" />
</div>
</div>
</div>
</div>
<!-- DAFTAR BIDAAN MODAL -->
<div
class="modal fade"
id="bidModal"
tabindex="-1"
aria-labelledby="bidModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal fade" id="bidModal" tabindex="-1" aria-labelledby="bidModalLabel" aria-hidden="true"
data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content text-center">
<div class="modal-header">
<h5 class="modal-title" id="bidModalLabel">Daftar Bidaan</h5>
<button
type="button"
class="btn-close"
ref="daftarBidaanClose"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" ref="daftarBidaanClose" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
@@ -541,11 +398,7 @@
jam 4:00pm hari ini.
<p>Jika tidak selesai, saya akan dibanned.</p>
</div>
<div
class="alert alert-danger"
role="alert"
v-if="v$.akadLelong.$error"
>
<div class="alert alert-danger" role="alert" v-if="v$.akadLelong.$error">
Sila tick kotak akad lelong sebelum meneruskan.
</div>
</div>
@@ -554,36 +407,20 @@
</p>
</div>
<div class="modal-footer">
<button
type="submit"
class="btn btn-danger me-2"
data-bs-dismiss="modal"
>
<button type="submit" class="btn btn-danger me-2" data-bs-dismiss="modal">
Tidak
</button>
<button
type="submit"
class="btn btn-success"
v-on:click="bidderSelectBidItem()"
>
<button type="submit" class="btn btn-success" v-on:click="bidderSelectBidItem()">
Ya
</button>
<p
class="fst-italic mt-3 fw-lighter"
style="text-align: right; font-size: small"
></p>
<p class="fst-italic mt-3 fw-lighter" style="text-align: right; font-size: small"></p>
</div>
</div>
</div>
</div>
<!-- DAFTAR BIDAAN MODAL - PRIMEVUE -->
<Dialog
header="Daftar Bidaan"
v-model:visible="displayModal"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }"
:style="{ width: '50vw' }"
:modal="true"
>
<Dialog header="Daftar Bidaan" v-model:visible="displayModal" :breakpoints="{ '960px': '75vw', '640px': '90vw' }"
:style="{ width: '50vw' }" :modal="true">
<div class="text-center">
<h1><i class="bi bi-exclamation-triangle text-warning"></i></h1>
<h3>ADAKAH ANDA PASTI?</h3>
@@ -610,14 +447,14 @@
</table>
</div>
<div class="mt-3 mb-1">
<label>
<label class="akad-checkbox">
<input type="checkbox" v-model="akadLelong" />
Saya bersetuju untuk membayar kesemua bidaan yang menang.
</label>
</div>
<InlineMessage v-if="v$.akadLelong.$error"
>Anda mestilah bersetuju dengan akad lelong.</InlineMessage
>
<InlineMessage v-if="showAkadError" severity="error">
Anda mestilah bersetuju dengan akad lelong.
</InlineMessage>
</div>
<div class="text-center mt-5">
<p class="text-danger">
@@ -625,42 +462,25 @@
</p>
</div>
<template #footer>
<Button
label="Tidak"
icon="pi pi-times"
iconPos="right"
@click="closeModalNew()"
class="p-button-text"
/>
<Button label="Tidak" icon="pi pi-times" iconPos="right" @click="closeModalNew()" class="p-button-text" />
<Button
label="Ya"
icon="pi pi-check"
iconPos="right"
:loading="isLoadingDaftar"
:disabled="!akadLelong"
v-on:click="bidderSelectBidItem()"
/>
</template>
</Dialog>
<!-- GAGAL DAFTAR BIDAAN MODAL -->
<div
class="modal fade"
id="gagalDaftarBidaanModal"
tabindex="-1"
aria-labelledby="gagalDaftarBidaanModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal fade" id="gagalDaftarBidaanModal" tabindex="-1" aria-labelledby="gagalDaftarBidaanModalLabel"
aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="gagalDaftarBidaanModalLabel"></h5>
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<h1><i class="bi bi-x-circle text-danger"></i></h1>
@@ -669,11 +489,7 @@
<p>Sila tambah surat ke dalam troli anda.</p>
</div>
<div class="modal-footer">
<button
type="submit"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
<button type="submit" class="btn btn-secondary" data-bs-dismiss="modal">
Kembali
</button>
</div>
@@ -684,9 +500,11 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import { useCartStore } from "@/store/modules/cart";
import axios from "axios";
import useVuelidate from "@vuelidate/core";
import { required, integer, numeric, minValue } from "@vuelidate/validators";
import { required, integer, numeric, minValue, sameAs } from "@vuelidate/validators";
import ItemMasterImageModal from "../list/ItemMasterImageModal.vue";
export default {
@@ -710,47 +528,59 @@ export default {
tambahanBidaan: "",
reloadImageComponent: 0,
jumlahBidaan: "",
akadLelong: null,
akadLelong: false,
showAkadError: false,
hargaAsas: "",
formDelete: {
userId: "",
lelongBidId: "",
},
formEdit: {
userId: localStorage.getItem("id"),
userId: useAuthenticationUserStore().id,
lelongBidId: "",
hargabida: "",
},
formRegisterBid: {
lelong_id: localStorage.getItem("lelong_id"),
user_id: localStorage.getItem("id"),
name: localStorage.getItem("name"),
user_id: useAuthenticationUserStore().id,
name: useAuthenticationUserStore().name,
},
};
},
validations() {
return {
tambahanBidaan: { required, numeric, integer, minValue: minValue(1) },
akadLelong: { required },
akadLelong: { checked: sameAs(true) },
};
},
watch: {
akadLelong(value) {
if (value) {
this.showAkadError = false;
}
},
},
mounted: function () {
this.listCart();
},
methods: {
openModalNew() {
this.displayModal = true;
this.akadLelong = null;
this.akadLelong = false;
this.showAkadError = false;
this.isLoadingDaftar = false;
},
closeModalNew() {
this.displayModal = false;
this.akadLelong = false;
this.showAkadError = false;
},
listCart() {
this.isLoading = true;
axios
.get("/cartByCawangan/" + localStorage.getItem("id"), {
.get("/cartByCawangan/" + useAuthenticationUserStore().id, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -778,12 +608,12 @@ export default {
},
deleteItem(value) {
this.isLoadingPadam = true;
this.formDelete.userId = localStorage.getItem("id");
this.formDelete.userId = useAuthenticationUserStore().id;
this.formDelete.lelongBidId = value.id;
axios
.post("/deleteItem", this.formDelete, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -798,6 +628,7 @@ export default {
allowOutsideClick: false,
allowEscapeKey: false,
});
useCartStore().fetchCount();
this.$emit("reloadComponent");
} else if (response.data.success == false) {
console.log(response);
@@ -811,6 +642,7 @@ export default {
timer: 5000,
timerProgressBar: true,
});
useCartStore().fetchCount();
this.$emit("reloadComponent");
}
})
@@ -836,7 +668,7 @@ export default {
axios
.post("/updateItem", this.formEdit, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -874,67 +706,13 @@ export default {
}
},
bidderSelectBidItem() {
if (this.isSuccess == true) {
this.v$.$validate();
if (!this.v$.akadLelong.$error) {
// this.loading = true;
this.isLoadingDaftar = true;
axios
.post("/bidder/biditem", this.formRegisterBid, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
})
.then((response) => {
// console.log("bidderSelectBidItem", response);
if (response.data.success == "success") {
this.isLoadingDaftar = false;
this.$refs.daftarBidaanClose.click();
this.$swal.fire({
icon: "success",
title: "Bidaan Berjaya Didaftarkan",
text: "Sila ke halaman rekod untuk senarai rekod bidaan.",
confirmButtonColor: "#344871",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
});
// this.loading = false;
this.$emit("reloadComponent");
} else {
this.isLoadingDaftar = false;
console.log(response);
this.$swal.fire({
toast: true,
icon: "error",
title: "Gagal! Sila refresh page semula.",
animation: false,
position: "bottom",
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
});
}
})
.catch((error) => {
// this.$refs.daftarBidaanClose.click();
// this.loading = false;
console.log(error);
this.$swal.fire({
toast: true,
icon: "error",
title: "Gagal! Sila refresh page semula.",
animation: false,
position: "bottom",
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
});
});
} else {
}
} else {
this.$refs.daftarBidaanClose.click();
if (!this.akadLelong) {
this.showAkadError = true;
return;
}
if (this.isSuccess != true) {
this.closeModalNew();
this.$swal.fire({
icon: "error",
title: "Gagal Daftar Bidaan",
@@ -944,7 +722,61 @@ export default {
allowOutsideClick: false,
allowEscapeKey: false,
});
return;
}
this.showAkadError = false;
this.isLoadingDaftar = true;
axios
.post("/bidder/biditem", this.formRegisterBid, {
headers: {
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
// console.log("bidderSelectBidItem", response);
this.isLoadingDaftar = false;
if (response.data.success == "success") {
this.closeModalNew();
this.$swal.fire({
icon: "success",
title: "Bidaan Berjaya Didaftarkan",
text: "Sila ke halaman rekod untuk senarai rekod bidaan.",
confirmButtonColor: "#344871",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
});
useCartStore().fetchCount();
this.$emit("reloadComponent");
} else {
console.log(response);
this.$swal.fire({
toast: true,
icon: "error",
title: "Gagal! Sila refresh page semula.",
animation: false,
position: "bottom",
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
});
}
})
.catch((error) => {
this.isLoadingDaftar = false;
console.log(error);
this.$swal.fire({
toast: true,
icon: "error",
title: "Gagal! Sila refresh page semula.",
animation: false,
position: "bottom",
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
});
});
},
},
};
@@ -955,6 +787,49 @@ export default {
min-height: 70vh;
}
.cart-accordion :deep(.p-accordion-header-link) {
display: flex;
align-items: center;
gap: 0.75rem;
}
.cart-accordion :deep(.p-accordion-toggle-icon) {
flex-shrink: 0;
margin-right: 0;
}
.cart-accordion-header {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1 1 auto;
min-width: 0;
gap: 0.75rem;
}
.cart-accordion-title {
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.style-info {
background: #e4f8f0;
border: solid #1ea97c;
border-width: 0.1px;
color: #1ea97c;
font-size: 0.95rem;
align-items: center;
display: inline-flex;
padding: 0.35rem 0.75rem;
margin: 0;
border-radius: 6px;
font-weight: 700;
white-space: nowrap;
flex-shrink: 0;
}
.info-teruskan {
background: #ffe7e6;
border: solid #ff5757;
@@ -975,4 +850,16 @@ export default {
.icon-color {
color: #ff5757;
}
.akad-checkbox {
display: inline-flex;
align-items: flex-start;
gap: 0.5rem;
text-align: left;
cursor: pointer;
}
.akad-checkbox input {
margin-top: 0.25rem;
}
</style>
+5 -4
View File
@@ -1,7 +1,7 @@
<template>
<Card style="margin-bottom: 1em">
<template #title>
<div class="flex justify-content-center flex-wrap card-container">
<div class="flex align-items-center justify-content-center flex-wrap gap-2 card-container">
<div class="font-normal">Harga Emas Lelongan</div>
<Button
class="button-standard p-button-rounded p-button-outlined"
@@ -37,9 +37,10 @@ export default {
</script>
<style scoped>
/* Shrink icon-only button; reset theme padding so the icon stays centered. */
.button-standard {
height: 30px !important;
width: 30px !important;
margin-top: 3px !important;
width: 2rem;
height: 2rem;
padding: 0;
}
</style>
@@ -16,6 +16,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -36,10 +37,10 @@ export default {
axios
.get("/itemInCart", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
},
})
+8 -6
View File
@@ -1,14 +1,15 @@
<template>
<Card style="margin-bottom: 1em">
<template #title>
<div class="flex justify-content-center flex-wrap card-container purple-container">
<div class="flex align-items-center justify-content-center flex-wrap gap-2 card-container purple-container">
<div class="font-normal">Lelongan Seterusnya</div>
<Button
class="button-standard p-button-rounded p-button-outlined"
icon="pi pi-refresh"
@click="toggleReloadComponent()"
/></div
></template>
/>
</div>
</template>
<template #content>
<lelong-next-detail v-bind:key="componentKey"></lelong-next-detail>
</template>
@@ -37,9 +38,10 @@ export default {
</script>
<style scoped>
/* Shrink icon-only button; reset theme padding so the icon stays centered. */
.button-standard {
height: 30px !important;
width: 30px !important;
margin-top: 3px !important;
width: 2rem;
height: 2rem;
padding: 0;
}
</style>
+7 -9
View File
@@ -1,13 +1,10 @@
<template>
<Card style="margin-bottom: 1em">
<template #title>
<div class="flex justify-content-center flex-wrap card-container">
<div class="flex align-items-center justify-content-center flex-wrap gap-2 card-container">
<div class="font-semibold">Lelongan Hari Ini : <span class="white-space-nowrap">{{ date }}</span></div>
<Button
class="button-standard p-button-rounded p-button-outlined"
icon="pi pi-refresh"
@click="toggleReloadComponent()"
/>
<Button class="button-standard p-button-rounded p-button-outlined" icon="pi pi-refresh"
@click="toggleReloadComponent()" />
</div>
</template>
<template #content>
@@ -51,9 +48,10 @@ export default {
</script>
<style scoped>
/* Shrink icon-only button; reset theme padding so the icon stays centered. */
.button-standard {
height: 30px !important;
width: 30px !important;
margin-top: 3px !important;
width: 2rem;
height: 2rem;
padding: 0;
}
</style>
+4 -3
View File
@@ -14,6 +14,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -28,17 +29,17 @@ export default {
},
methods: {
resultStatus() {
// "/resultStatus/" + localStorage.getItem("id") + "/" + this.lelongId,
// "/resultStatus/" + useAuthenticationUserStore().id + "/" + this.lelongId,
},
getLelong() {
this.loading = true;
axios
.get("/resultLelong", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
},
})
+12 -23
View File
@@ -255,12 +255,13 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
data() {
return {
username: localStorage.getItem("username"),
username: useAuthenticationUserStore().username,
visibleLeft: false,
lelongOnline: "",
};
@@ -274,27 +275,15 @@
this.getLelongOnline();
},
methods: {
doLogout() {
axios
.post(
"/user/logout",
{},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
}
)
.then((response) => {
localStorage.clear();
this.authenticationStore.$reset();
this.$router.push({ name: "login" });
})
.catch((error) => {
console.log(error);
});
localStorage.clear();
this.$router.push({ name: "login" });
async doLogout() {
try {
await axios.post("/user/logout");
} catch (error) {
console.log(error);
} finally {
this.authenticationStore.clearSession();
this.$router.push({ name: "login" });
}
},
toHome() {
this.$router.push({ name: "home" });
@@ -306,7 +295,7 @@
axios
.get("/lelongOnline", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
+104 -163
View File
@@ -1,65 +1,45 @@
<template>
<!-- Navbar for laptop screen size (width>992px) -->
<div class="card sticky-top lg:flex hidden border-none">
<Toast :breakpoints="{ '992px': { display: 'none' }, }"/>
<Toast :breakpoints="{ '992px': { display: 'none' }, }" />
<div class="flex justify-content-between px-3 md:px-6 h-3rem flex-wrap main-color">
<div class="flex align-items-center justify-content-center">
<div class="company-title" type="button" v-on:click="toHome()">
<!-- <div class="logo-title">E-Rahn Lelong</div> -->
<!-- <img class="logo-img" src="img/logo_arrahn.png" alt="arrahn-logo" /> -->
<img class="logo-img" src="img/e-rahn-lelong.png" alt="arrahn-logo" type="button" v-on:click="toHome()"/>
<img class="logo-img" src="/img/e-rahn-lelong.png" alt="arrahn-logo" type="button" v-on:click="toHome()" />
</div>
</div>
<div class="flex align-items-center justify-content-center">
<nav class="main-nav">
<router-link class="nav-button" v-bind:to="{ name: 'home' }"
>Utama</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'list' }"
>Senarai</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'cart' }"
>Troli</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'bid-record' }"
>Rekod</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'result' }"
>Keputusan</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'policy' }"
>Polisi</router-link
>
<router-link class="nav-button" v-bind:to="{ name: 'home' }">Utama</router-link>
<router-link class="nav-button" v-bind:to="{ name: 'list' }">Senarai</router-link>
<router-link class="nav-button cart-nav-link" v-bind:to="{ name: 'cart' }">
Troli
<span v-if="cartStore.hasItems" class="cart-count-badge">{{ cartStore.badgeLabel }}</span>
</router-link>
<router-link class="nav-button" v-bind:to="{ name: 'bid-record' }">Rekod</router-link>
<router-link class="nav-button" v-bind:to="{ name: 'result' }">Keputusan</router-link>
<router-link class="nav-button" v-bind:to="{ name: 'policy' }">Polisi</router-link>
</nav>
</div>
<div class="flex align-items-center justify-content-center">
<div class="profile-title hidden lg:flex">
<div class="dropdown">
<div
class="dropdown-toggle"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<div class="dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-person-circle me-1"></i>{{ username }}
</div>
<ul class="dropdown-menu">
<li>
<div
type="button"
class="dropdown-item"
v-on:click="toProfile()"
>
<div type="button" class="dropdown-item" v-on:click="toProfile()">
Profil <i class="bi bi-person-workspace"></i>
</div>
</li>
<li><hr class="dropdown-divider" /></li>
<li>
<div
type="button"
v-on:click="doLogout()"
class="dropdown-item"
>
<hr class="dropdown-divider" />
</li>
<li>
<div type="button" v-on:click="doLogout()" class="dropdown-item">
Log Keluar <i class="bi bi-box-arrow-right"></i>
</div>
</li>
@@ -71,8 +51,7 @@
</div>
<!-- Navbar for phone, tab screen size (width<992px) -->
<div class="card sticky-top lg:hidden md:flex border-none">
<div
class="
<div class="
flex
justify-content-between
px-3
@@ -80,14 +59,9 @@
h-3rem
flex-wrap
main-color
"
>
">
<div class="flex align-items-center justify-content-center">
<i
class="pi pi-bars text-white lg:hidden mr-3"
style="cursor: pointer"
@click="visibleRight = true"
></i>
<i class="pi pi-bars text-white lg:hidden mr-3" style="cursor: pointer" @click="visibleRight = true"></i>
<div class="company-title" type="button" v-on:click="toHome()">
<div class="logo-title">E-Rahn Lelong</div>
<!-- <img class="logo-img" src="img/logo_arrahn.png" alt="arrahn-logo" /> -->
@@ -95,34 +69,19 @@
</div>
<div class="flex align-items-center justify-content-center">
<!-- <i
class="pi pi-shopping-cart text-white lg:hidden"
style="cursor: pointer"
@click="visibleRight = true"
></i> -->
<!-- <i
class="pi pi-shopping-cart mr-1 p-text-primary"
style="font-size: 1.5rem; color: #eaf0f9"
v-badge.success="itemInCart"
v-on:click="toCart()"
v-if="isSuccessCart"
></i> -->
<i
class="pi pi-shopping-cart mr-1 p-text-primary"
style="font-size: 1.5rem; color: #eaf0f9"
v-on:click="toCart()"
></i>
<span class="cart-nav-icon" v-on:click="toCart()">
<i class="pi pi-shopping-cart p-text-primary" style="font-size: 1.5rem; color: #eaf0f9"></i>
<span v-if="cartStore.hasItems" class="cart-count-badge">{{ cartStore.badgeLabel }}</span>
</span>
</div>
</div>
<div v-if="lelongOnline != ''">
<div
class="
<div class="
flex
align-items-center
justify-content-center
notification-mobile
"
>
">
<i class="blink pi pi-info-circle mr-2"></i> Lelongan akan tamat pada
{{ lelongOnline }}
</div>
@@ -136,53 +95,29 @@
</div>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'home' }"
>Utama</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'home' }">Utama</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'list' }"
>Senarai</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'list' }">Senarai</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'cart' }"
>Troli</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar cart-nav-link" v-bind:to="{ name: 'cart' }">
Troli
<span v-if="cartStore.hasItems" class="cart-count-badge cart-count-badge-sidebar">{{ cartStore.badgeLabel
}}</span>
</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'bid-record' }"
>Rekod</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'bid-record' }">Rekod</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'result' }"
>Keputusan</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'result' }">Keputusan</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'policy' }"
>Polisi</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'policy' }">Polisi</router-link>
</div>
<div class="col-12">
<router-link
class="main-nav-link main-nav-link-sidebar"
v-bind:to="{ name: 'profile' }"
>Profil</router-link
>
<router-link class="main-nav-link main-nav-link-sidebar" v-bind:to="{ name: 'profile' }">Profil</router-link>
</div>
<div class="col-12">
<!-- <router-link
@@ -192,12 +127,8 @@
> -->
</div>
<div class="col-12">
<a
class="main-nav-link main-nav-link-sidebar"
v-on:click="doLogout()"
href="#"
><i class="bi bi-box-arrow-right me-1"></i> Log Keluar</a
>
<a class="main-nav-link main-nav-link-sidebar" v-on:click="doLogout()" href="#"><i
class="bi bi-box-arrow-right me-1"></i> Log Keluar</a>
</div>
</div>
</Sidebar>
@@ -205,49 +136,43 @@
<script>
import axios from "axios";
import { useAuthenticationUserStore } from "@/store/modules/authentication"
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import { useCartStore } from "@/store/modules/cart";
export default {
data() {
return {
username: localStorage.getItem("username"),
username: useAuthenticationUserStore().username,
visibleRight: false,
lelongOnline: "",
isSuccessCart: false,
itemInCart: 0,
};
},
setup() {
const authenticationStore = useAuthenticationUserStore()
const authenticationStore = useAuthenticationUserStore();
const cartStore = useCartStore();
return { authenticationStore }
return { authenticationStore, cartStore };
},
mounted: function () {
mounted() {
this.getLelongOnline();
// this.getItemInCart();
this.cartStore.fetchCount();
},
watch: {
"$route.fullPath"() {
this.cartStore.fetchCount();
},
},
methods: {
doLogout() {
axios
.post(
"/user/logout",
{},
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
}
)
.then((response) => {
localStorage.clear();
this.authenticationStore.$reset();
this.$router.push({ name: "login" });
})
.catch((error) => {
console.log(error);
});
localStorage.clear();
this.$router.push({ name: "login" });
async doLogout() {
try {
await axios.post("/user/logout");
} catch (error) {
console.log(error);
} finally {
this.cartStore.clear();
this.authenticationStore.clearSession();
this.$router.push({ name: "login" });
}
},
toHome() {
this.$router.push({ name: "home" });
@@ -262,7 +187,7 @@ export default {
axios
.get("/lelongOnline", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
@@ -282,31 +207,6 @@ export default {
console.log(error);
});
},
getItemInCart() {
this.loading = true;
axios
.get("/itemInCart", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
params: {
user_id: localStorage.getItem("id"),
},
})
.then((response) => {
// console.log('getItemInCart', response);
if (response.data.success === true) {
this.isSuccessCart = true;
this.itemInCart = response.data.cart;
} else {
this.isSuccessCart = false;
}
})
.catch((error) => {
console.log(error);
});
},
},
};
</script>
@@ -350,6 +250,7 @@ router-link:hover {
height: 2.5rem;
padding: 25px 10px;
}
.main-color {
background-color: #0D908B;
}
@@ -443,4 +344,44 @@ a.router-link-exact-active:hover {
.arrow-logo {
font-size: 0.5rem;
}
.cart-nav-link,
.cart-nav-icon {
position: relative;
display: inline-flex;
align-items: center;
}
.cart-nav-icon {
cursor: pointer;
}
.cart-count-badge {
position: absolute;
top: -0.45rem;
right: -0.7rem;
min-width: 1.15rem;
height: 1.15rem;
padding: 0 0.3rem;
border-radius: 999px;
background: #ef4444;
color: #ffffff;
font-size: 0.7rem;
font-weight: 700;
line-height: 1.15rem;
text-align: center;
box-shadow: 0 0 0 1.5px #0d908b;
pointer-events: none;
}
.cart-count-badge-sidebar {
position: static;
margin-left: 0.5rem;
box-shadow: none;
}
a.router-link-exact-active .cart-count-badge {
box-shadow: 0 0 0 1.5px #fae79a;
color: #ffffff;
}
</style>
+2 -1
View File
@@ -6,6 +6,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -34,7 +35,7 @@ export default {
axios
.get("/photoMarhun", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
norujukan: this.norujukan,
+2 -1
View File
@@ -8,6 +8,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -36,7 +37,7 @@ export default {
axios
.get("/photoMarhun", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
norujukan: this.norujukan,
+7 -4
View File
@@ -411,6 +411,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import useVuelidate from "@vuelidate/core";
import { required, integer, numeric, minValue } from "@vuelidate/validators";
@@ -418,6 +419,7 @@ import { read } from "@popperjs/core";
import ItemMasterImage from "./ItemMasterImage.vue";
import ItemMultipleImage from "./ItemMultipleImage.vue";
import ItemMasterImageModal from "./ItemMasterImageModal.vue";
import { useCartStore } from "@/store/modules/cart";
export default {
components: {
@@ -449,7 +451,7 @@ export default {
tambahan: "",
// image: "",
form: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelongbid_id: "",
hargabida: "",
},
@@ -483,11 +485,11 @@ export default {
axios
.get("/lelongDetails/listSuratLelong", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
caw_id: this.selectedCawangan,
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: localStorage.getItem("lelong_id"),
},
})
@@ -546,7 +548,7 @@ export default {
axios
.post("/addToCart", this.form, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -554,6 +556,7 @@ export default {
if (response.data.success == true) {
this.$refs.tambahClose.click();
this.$emit("reloadComponent");
useCartStore().fetchCount();
this.$swal.fire({
toast: true,
icon: "success",
+2 -2
View File
@@ -33,7 +33,6 @@
>
{{ data.caw_name }}
</option>
<input type="hidden" />
</select>
</div>
<list-item
@@ -74,6 +73,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import ListItem from "./ListItem.vue";
import axios from "axios";
@@ -108,7 +108,7 @@ export default {
axios
.get("/listcawlelongtodaystarted", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
+4 -3
View File
@@ -81,6 +81,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import ReceiptImage from "./ReceiptImage.vue";
@@ -112,10 +113,10 @@ export default {
axios
.get("/listPhotoResit", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: this.lelong_id,
},
})
@@ -151,7 +152,7 @@ export default {
{ fileresit_id: this.fileresit_id },
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
}
)
+2 -1
View File
@@ -8,6 +8,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -35,7 +36,7 @@ export default {
axios
.get("/showPhotoResit", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
fileresit_id: this.fileResitId,
+7 -6
View File
@@ -69,6 +69,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
emits: ["back-is-click"],
@@ -80,10 +81,10 @@ export default {
return {
// changeProp: finalSurat,
form: {
email: localStorage.getItem("email"),
notel: localStorage.getItem("notelbimbit"),
name: localStorage.getItem("name"),
user_id: localStorage.getItem("id"),
email: useAuthenticationUserStore().email,
notel: useAuthenticationUserStore().notelbimbit,
name: useAuthenticationUserStore().name,
user_id: useAuthenticationUserStore().id,
lelong_id: localStorage.getItem("lelong_id"),
invoice_id: "",
invoice_no: "",
@@ -112,10 +113,10 @@ export default {
axios
.get("/invoice", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: localStorage.getItem("lelong_id"),
},
})
+34 -14
View File
@@ -212,13 +212,16 @@
:modal="true"
>
<div class="text-center">
<div>Lakukan bayaran ke akaun tersebut.</div>
<div>Lakukan bayaran ke akaun cawangan {{ cawanganPilihan }}.</div>
<div class="div-card-bank">
<div class="card-bank">
<div>
<div>Koperasi Permodalan Kelantan Berhad</div>
<div>1102084986</div>
<div>BANK RAKYAT</div>
<div class="bank-label">Nama Bank</div>
<div>{{ cawanganBank.nama_bank || "-" }}</div>
<div class="bank-label">No Akaun Bank</div>
<div>{{ cawanganBank.bank_acc_no || "-" }}</div>
<div class="bank-label">Nama Akaun</div>
<div>{{ cawanganBank.bank_acc || "-" }}</div>
</div>
</div>
</div>
@@ -259,6 +262,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import SelectId from "./SelectId.vue";
import TermsAndConditionsDetails from "../authentication/TermsAndConditionsDetails.vue";
import axios from "axios";
@@ -289,15 +293,20 @@ export default {
isDisplayFileUpload: false,
isLoading: false,
cawanganPilihan: "",
cawanganBank: {
nama_bank: "",
bank_acc: "",
bank_acc_no: "",
},
hargaBidaanPilihan: "",
hargaBidaanPilihanTambahFi: "",
lelongDetails: "",
fileSize: 0,
form: {
email: localStorage.getItem("email"),
notel: localStorage.getItem("notelbimbit"),
name: localStorage.getItem("name"),
user_id: localStorage.getItem("id"),
email: useAuthenticationUserStore().email,
notel: useAuthenticationUserStore().notelbimbit,
name: useAuthenticationUserStore().name,
user_id: useAuthenticationUserStore().id,
lelong_id: "",
invoice_id: "",
invoice_no: "",
@@ -333,10 +342,10 @@ export default {
axios
.get("/invoice", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: this.lelongIdProps,
},
})
@@ -367,6 +376,11 @@ export default {
// if (current_time < limit_datetime_bayaran === true) {
this.isDisplayPaymentMethod = true;
this.cawanganPilihan = value.cawangan;
this.cawanganBank = {
nama_bank: value.nama_bank || "",
bank_acc: value.bank_acc || "",
bank_acc_no: value.bank_acc_no || "",
};
this.form.kodcaw = value.kodcaw;
this.hargaBidaanPilihan = value.total_hargabida;
let convertHargaBidaanPilihan =
@@ -414,7 +428,7 @@ export default {
axios
.post("/initializeCdmPayment", resitFormData, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -487,8 +501,7 @@ export default {
this.$router.push({
name: "detail",
params: {
lelongId: this.lelongIdProps,
statusPayment: null,
lelongId: String(this.lelongIdProps),
},
});
},
@@ -532,10 +545,17 @@ export default {
background: #2f68c51c;
color: #2f68c5f2;
width: 300px;
height: 125px;
min-height: 125px;
border-radius: 16px;
display: flex;
justify-content: center;
align-items: center;
padding: 16px;
}
.bank-label {
margin-top: 8px;
font-size: 12px;
opacity: 0.7;
}
</style>
+18 -33
View File
@@ -1,9 +1,7 @@
<template>
<the-template>
<div v-if="isLoading" class="fadein animation-duration-400">
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
@@ -15,18 +13,14 @@
<template #title>
<div class="font-normal">
<div class="flex">
<Button
class="
<Button class="
p-button-sm
button-custom
p-button-secondary p-button-outlined
align-self-center
mr-2
"
icon="pi pi-arrow-left"
v-on:click="clickCancelButton()"
/>
Pembayaran Bidaan
" icon="pi pi-arrow-left" v-on:click="clickCancelButton()" />
Pembayaran Bidaan 1
</div>
</div>
<div class="font-normal text-base">
@@ -34,22 +28,17 @@
</div>
</template>
<template #content>
<select-outlet
v-bind:namaCawangan="lists"
v-bind:lelongIdProps="lelongId"
></select-outlet>
<select-outlet v-bind:namaCawangan="lists" v-bind:lelongIdProps="lelongId"></select-outlet>
</template>
</Card>
</div>
<div v-else>
<div
class="
<div class="
flex
align-items-center
justify-content-center
container-height
"
>
">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-book text-8xl text-400"></i>
@@ -58,13 +47,9 @@
<span class="text-400">Tiada Data.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }"
>Keputusan</router-link
>
untuk maklumat rekod bidaan menang.</span
>
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }">Keputusan</router-link>
untuk maklumat rekod bidaan menang.</span>
</div>
</div>
</div>
@@ -84,6 +69,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import SelectOutlet from "./SelectOutlet.vue";
// import SelectId from "./SelectId.vue";
@@ -121,17 +107,17 @@ export default {
methods: {
liveData() {
this.isLoading = true;
if(this.lelongId != null){
if (this.lelongId != null) {
axios
.get(
"/bayarBaki/" +
localStorage.getItem("id") +
// "/1" ,
"/" +
this.lelongId,
useAuthenticationUserStore().id +
// "/1" ,
"/" +
this.lelongId,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
}
)
@@ -157,8 +143,7 @@ export default {
this.$router.push({
name: "detail",
params: {
lelongId: this.lelongId,
statusPayment: null,
lelongId: String(this.lelongId),
},
});
},
+27 -62
View File
@@ -1,9 +1,7 @@
<template>
<the-template>
<div v-if="isLoading" class="fadein animation-duration-400">
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
@@ -14,17 +12,13 @@
<Card>
<template #title>
<div class="flex">
<Button
class="
<Button class="
p-button-sm
button-custom
p-button-secondary p-button-outlined
align-self-center
mr-2
"
icon="pi pi-arrow-left"
v-on:click="clickCancelButton()"
/>
" icon="pi pi-arrow-left" v-on:click="clickCancelButton()" />
<div class="font-normal">Pembayaran Bidaan Menggunakan CDM</div>
</div>
<div class="font-normal text-base">
@@ -39,8 +33,7 @@
<div class="font-medium p-0">No Account Bank: 1102084986 (BANK RAKYAT)</div>
<span class="text-xs fst-italic text-danger">
*Sila buat bayaran menggunakan nombor akaun ini sahaja dan muat
naik gambar resit dibawah.</span
>
naik gambar resit dibawah.</span>
<div class="overflow-x-auto">
<table class="mt-5 table text-center table-bordered">
@@ -67,26 +60,13 @@
</tbody>
</table>
</div>
<Button
class="p-button-sm mb-3"
label="Muat Naik Resit"
icon="pi pi-plus-circle"
iconPos="right"
@click="openModalFileUpload()"
/>
<list-receipt
v-bind:key="componentKey"
v-bind:lelong_id="lelongId"
v-on:reloadComponent="toggleReloadComponent"
></list-receipt>
<Button class="p-button-sm mb-3" label="Muat Naik Resit" icon="pi pi-plus-circle" iconPos="right"
@click="openModalFileUpload()" />
<list-receipt v-bind:key="componentKey" v-bind:lelong_id="lelongId"
v-on:reloadComponent="toggleReloadComponent"></list-receipt>
<Dialog
header="Muat Naik Resit Baharu"
v-model:visible="isDisplayFileUpload"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }"
:style="{ width: '50vw' }"
:modal="true"
>
<Dialog header="Muat Naik Resit Baharu" v-model:visible="isDisplayFileUpload"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }" :modal="true">
<div class="text-center m-2">
<input class="form-control" type="file" accept="image/*" v-on:change="selectPhoto" />
<!-- <FileUpload
@@ -99,32 +79,21 @@
/> -->
</div>
<template #footer>
<Button
class="p-button-sm p-button-secondary"
label="Kembali"
@click="closeModalFileUpload()"
/>
<Button
class="p-button-sm p-button-success"
label="Simpan"
icon="pi pi-check"
iconPos="right"
@click="addPhotoResit()"
/>
<Button class="p-button-sm p-button-secondary" label="Kembali" @click="closeModalFileUpload()" />
<Button class="p-button-sm p-button-success" label="Simpan" icon="pi pi-check" iconPos="right"
@click="addPhotoResit()" />
</template>
</Dialog>
</template>
</Card>
</div>
<div v-else>
<div
class="
<div class="
flex
align-items-center
justify-content-center
container-height
"
>
">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-book text-8xl text-400"></i>
@@ -133,13 +102,9 @@
<span class="text-400">Tiada Data.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }"
>Keputusan</router-link
>
untuk maklumat rekod bidaan menang.</span
>
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }">Keputusan</router-link>
untuk maklumat rekod bidaan menang.</span>
</div>
</div>
</div>
@@ -149,6 +114,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import ListReceipt from "./ListReceipt.vue";
@@ -166,7 +132,7 @@ export default {
isDisplayFileUpload: false,
componentKey: 0,
formResit: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: this.$route.params.lelongId,
gambarResit: "",
},
@@ -185,13 +151,13 @@ export default {
axios
.get(
"/bayarBaki/" +
localStorage.getItem("id") +
// "/1" ,
"/" +
this.lelongId,
useAuthenticationUserStore().id +
// "/1" ,
"/" +
this.lelongId,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
}
)
@@ -222,7 +188,7 @@ export default {
axios
.post("/addPhotoResit", resitFormData, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -266,8 +232,7 @@ export default {
this.$router.push({
name: "detail",
params: {
lelongId: this.lelongId,
statusPayment: null,
lelongId: String(this.lelongId),
},
});
},
+36 -49
View File
@@ -3,46 +3,19 @@
<div class="col-12 lg:col-11 fadein animation-duration-400">
<Card>
<template #title>
<div class="font-normal">Polisi</div>
<div class="font-normal">Panduan</div>
</template>
<template #content>
<TabView>
<TabPanel :header="'Panduan E-Rahn Lelong'">
<TabPanel :header="'Panduan ArrahnBid'">
<p>
Berikut merupakan video panduan untuk penggunaan E-Rahn Lelong. Sila
Berikut merupakan video panduan untuk penggunaan ArrahnBid. Sila
tonton
<a
class="font-bold"
target="_blank"
href="https://youtu.be/lucYE9bM_PY"
>video</a
>
<a class="font-bold" target="_blank" href="https://youtu.be/lucYE9bM_PY">video</a>
ini untuk memahami cara penggunaan.
</p>
<div class="lg:flex hidden justify-content-center">
<YouTube v-bind:src="theUrl" />
</div>
<div
class="
lg:hidden
md:flex
hidden
overflow-x-auto
justify-content-center
"
>
<YouTube v-bind:src="theUrl" width="480" height="360" />
</div>
<div
class="
lg:hidden
md:hidden
flex
overflow-x-auto
justify-content-center
"
>
<YouTube v-bind:src="theUrl" width="320" height="240" />
<div class="youtube-wrap flex justify-content-center overflow-x-auto">
<YouTube :src="theUrl" :width="playerWidth" :height="playerHeight" />
</div>
</TabPanel>
<TabPanel :header="'Terma & Syarat'">
@@ -50,21 +23,18 @@
</TabPanel>
<TabPanel :header="'Hubungi Kami'">
<div class="mt-5">
<div
class="
<div class="
grid
col-11 col-offset-1
lg:col-8 lg:col-offset-2
justify-content-center
"
>
">
<div class="col-12 lg:col-5 text-start text-400"><i class="pi pi-phone"></i> Hotline</div>
<div class="col-12 lg:col-6 text-start value-form">097414338</div>
<div class="col-12 lg:col-6 text-start value-form">1300-22-4343</div>
<div class="col-12 lg:col-5 text-start text-400"><i class="pi pi-pencil"></i> Emel</div>
<div class="col-12 lg:col-6 text-start value-form">admin@koppkb.com</div>
<!-- <div class="col-12 lg:col-5 text-start text-400"><i class="pi pi-paperclip"></i> Emel</div>
<div class="col-12 lg:col-6 text-start value-form">admin@koppkb.com</div> -->
<div class="col-12 lg:col-6 text-start value-form">arrahncareline@gmail.com</div>
<div class="col-12 lg:col-5 text-start text-400"><i class="pi pi-paperclip"></i> Emel</div>
<div class="col-12 lg:col-6 text-start value-form">arcc@pkb.net.my</div>
</div>
</div>
</TabPanel>
@@ -86,8 +56,32 @@ export default {
data() {
return {
theUrl: "https://www.youtube.com/watch?v=lucYE9bM_PY&t=53s",
playerWidth: 640,
playerHeight: 360,
};
},
mounted() {
this.updatePlayerSize();
window.addEventListener("resize", this.updatePlayerSize);
},
beforeUnmount() {
window.removeEventListener("resize", this.updatePlayerSize);
},
methods: {
updatePlayerSize() {
const width = window.innerWidth;
if (width < 768) {
this.playerWidth = 320;
this.playerHeight = 240;
} else if (width < 992) {
this.playerWidth = 480;
this.playerHeight = 360;
} else {
this.playerWidth = 640;
this.playerHeight = 360;
}
},
},
};
</script>
@@ -98,10 +92,3 @@ export default {
border-radius: 6px;
}
</style>
<!-- export default {
components: {
"terms-and-conditions-details": TermsAndConditionsDetails,
},
};
</script> -->
+8 -13
View File
@@ -9,7 +9,7 @@
</div>
</div>
</div>
<div else style="min-height: 70vh">
<div v-else style="min-height: 70vh">
<div v-if="status">
<div
class="
@@ -110,37 +110,32 @@ export default {
components: {},
data() {
return {
data: [],
data_2: [],
data: {},
loading: false,
status: false,
};
},
mounted: function () {
mounted() {
this.profile();
},
methods: {
profile() {
this.loading = true;
axios
.get("/user/profile/" + localStorage.getItem("nokp"), {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
},
})
.get("/user/profile")
.then((response) => {
if (response.data.success == true) {
this.status = true;
this.data = response.data.message[0];
this.data_2 = response.data.message[1];
this.loading = false;
this.data = response.data.message[0] || {};
} else {
this.status = false;
this.loading = false;
}
})
.catch((error) => {
alert(error);
this.status = false;
})
.finally(() => {
this.loading = false;
});
},
+3 -2
View File
@@ -59,6 +59,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
export default {
@@ -77,9 +78,9 @@ export default {
liveData() {
this.loading = true;
axios
.get("/history/" + localStorage.getItem("id"), {
.get("/history/" + useAuthenticationUserStore().id, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
+163 -249
View File
@@ -1,9 +1,6 @@
<template>
<the-template>
<div
v-if="loading"
style="min-height: 70vh; display: grid; place-items: center"
>
<div v-if="loading" style="min-height: 70vh; display: grid; place-items: center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
@@ -15,21 +12,14 @@
<template #title>
<div class="grid justify-content-between">
<div class="flex">
<Button
class="
<Button class="
p-button-sm
button-custom
p-button-secondary p-button-outlined
align-self-center
mr-2
"
icon="pi pi-arrow-left"
v-on:click="clickBackButton()"
/>
<div
class="font-normal"
style="font-size: 1.5rem; font-weight: 700"
>
" icon="pi pi-arrow-left" v-on:click="clickBackButton()" />
<div class="font-normal" style="font-size: 1.5rem; font-weight: 700">
Keputusan Tarikh Lelongan: {{ tarikhLelong }}
</div>
</div>
@@ -42,95 +32,59 @@
:disabled="disabled == 1"
v-on:click="clickPayCdmButton(lelongId)"
/> -->
<Button
label="Pembayaran"
icon="pi pi-dollar"
iconPos="right"
class="p-button-sm"
:disabled="disabled == 1"
v-on:click="clickPayButton(lelongId)"
/>
<Button label="Pembayaran" icon="pi pi-dollar" iconPos="right" class="p-button-sm"
:disabled="disabled == 1" v-on:click="clickPayButton(lelongId)" />
</div>
</div>
<div class="row" v-if="disabled != 1">
<div
class="
<div class="
text-xs
align-self-center
fst-italic
fw-lighter
text-danger
md:text-right
"
>
">
*Sila klik butang diatas untuk lakukan bayaran.
</div>
</div>
</template>
<template #content>
<Accordion :multiple="true">
<AccordionTab v-for="list in lists" v-bind:key="list">
<Accordion :multiple="true" class="result-accordion">
<AccordionTab v-for="list in lists" :key="list.cawangan || list.kodcaw">
<template #header>
<div class="flex justify-content-between w-100">
<div class="align-self-center" style="margin: 5px">
<div class="result-accordion-header">
<span class="result-accordion-title">
{{ list.cawangan }}
<span
v-if="list.status_payment_cawangan.status === null"
>
<Tag
value="Belum Bayar"
icon="pi pi-times"
severity="danger"
></Tag>
<span v-if="list.status_payment_cawangan.status === null">
<Tag value="Belum Bayar" icon="pi pi-times" severity="danger"></Tag>
</span>
<span
v-else-if="list.status_payment_cawangan.status == 9"
>
<Tag
value="Tunggu Pengesahan"
icon="pi pi-stopwatch"
severity="warning"
></Tag>
<span v-else-if="list.status_payment_cawangan.status == 9">
<Tag value="Tunggu Pengesahan" icon="pi pi-stopwatch" severity="warning"></Tag>
</span>
<span
v-else-if="list.status_payment_cawangan.status == 1"
>
<Tag
value="Selesai Bayar"
icon="pi pi-check"
severity="success"
></Tag>
<span v-else-if="list.status_payment_cawangan.status == 1">
<Tag value="Selesai Bayar" icon="pi pi-check" severity="success"></Tag>
</span>
</div>
<div class="style-info">
</span>
<span class="style-info">
Jumlah RM{{
list.total_hargabida
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}
</div>
</span>
</div>
</template>
<Button
label="Surat Hak Kepemilikan Barang"
icon="pi pi-verified"
iconPos="right"
class="p-button-sm mb-3"
v-on:click="downloadPdf(list.kodcaw)"
v-if="list.status_payment_cawangan.status == 1"
/>
<div
v-if="
list.status_payment_cawangan.status == 1 ||
list.status_payment_cawangan.status == 9
"
>
<div
class="m-2"
v-if="
list.status_payment_cawangan.payment_method_opt == 2
"
>
<Button label="Surat Hak Kepemilikan Barang" icon="pi pi-verified" iconPos="right"
class="p-button-sm mb-3" v-on:click="downloadPdf(list.kodcaw)"
v-if="list.status_payment_cawangan.status == 1" />
<div v-if="
list.status_payment_cawangan.status == 1 ||
list.status_payment_cawangan.status == 9
">
<div class="m-2" v-if="
list.status_payment_cawangan.payment_method_opt == 2
">
<div>
<div class="row">
<div>Cara Bayaran: FPX</div>
@@ -143,12 +97,9 @@
</div>
</div>
</div>
<div
class="m-2"
v-else-if="
list.status_payment_cawangan.payment_method_opt == 1
"
>
<div class="m-2" v-else-if="
list.status_payment_cawangan.payment_method_opt == 1
">
<div>
<div class="row">
<div>Cara Bayaran: TUNAI DI CAWANGAN</div>
@@ -161,36 +112,22 @@
</div>
</div>
</div>
<div
class="mt-2 mb-2"
v-else-if="
list.status_payment_cawangan.payment_method_opt == 3
"
>
<div class="mt-2 mb-2" v-else-if="
list.status_payment_cawangan.payment_method_opt == 3
">
<div>
<div class="row mb-3">
<div>Cara Bayaran: CDM</div>
</div>
<div
v-if="
list.status_payment_cawangan.status == 9 &&
list.status_payment_cawangan.file_resit.length < 15
"
>
<Button
class="p-button-sm mb-1"
label="Tambah Resit Baharu"
icon="pi pi-plus-circle"
iconPos="right"
@click="openModalFileUpload(list.kodcaw)"
/>
<Dialog
header="Muat Naik Resit Baharu"
v-model:visible="isDisplayFileUpload"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }"
:style="{ width: '50vw' }"
:modal="true"
>
<div v-if="
list.status_payment_cawangan.status == 9 &&
list.status_payment_cawangan.file_resit.length < 15
">
<Button class="p-button-sm mb-1" label="Tambah Resit Baharu" icon="pi pi-plus-circle"
iconPos="right" @click="openModalFileUpload(list.kodcaw)" />
<Dialog header="Muat Naik Resit Baharu" v-model:visible="isDisplayFileUpload"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }"
:modal="true">
<div class="text-center">
<div>Lakukan bayaran ke akaun tersebut.</div>
<div class="div-card-bank">
@@ -203,62 +140,39 @@
</div>
</div>
</div>
<div class="mt-5">Sila muat naik gambar resit dalam bentuk <strong>PNG</strong> atau <strong>JPG</strong>.</div>
<div class="mt-5">Sila muat naik gambar resit dalam bentuk <strong>PNG</strong> atau
<strong>JPG</strong>.
</div>
<div>Pastikan gambar yang dimuat naik adalah <strong>JELAS.</strong></div>
<div class="text-center m-2">
<input
class="form-control"
type="file"
accept="image/png, image/jpg, image/jpeg"
v-on:change="selectPhoto"
/>
<div
style="font-size: 13px"
class="fst-italic text-danger row"
v-if="v$.fileSize.$error"
>
<input class="form-control" type="file" accept="image/png, image/jpg, image/jpeg"
v-on:change="selectPhoto" />
<div style="font-size: 13px" class="fst-italic text-danger row" v-if="v$.fileSize.$error">
<div>
Jenis gambar yang diterima adalah PNG dan JPG.
</div>
</div>
</div>
<template #footer>
<Button
class="p-button-sm p-button-secondary"
label="Kembali"
@click="closeModalFileUpload()"
/>
<Button
class="p-button-sm p-button-success"
label="Simpan"
icon="pi pi-check"
iconPos="right"
:loading="isLoadingButton"
@click="addPhotoResit()"
/>
<Button class="p-button-sm p-button-secondary" label="Kembali"
@click="closeModalFileUpload()" />
<Button class="p-button-sm p-button-success" label="Simpan" icon="pi pi-check"
iconPos="right" :loading="isLoadingButton" @click="addPhotoResit()" />
</template>
</Dialog>
</div>
<div class="card">
<div class="card-header">Gambar Resit</div>
<div
class="
<div class="
card-body
d-flex
overflow-x-auto
align-items-center
"
>
<div
class="m-2"
v-for="receipt in list.status_payment_cawangan
.file_resit"
v-bind:key="receipt"
>
">
<div class="m-2" v-for="receipt in list.status_payment_cawangan
.file_resit" v-bind:key="receipt">
<div class="row text-center">
<receipt-image
v-bind:fileResitId="receipt.id"
></receipt-image>
<receipt-image v-bind:fileResitId="receipt.id"></receipt-image>
<div>{{ receipt.masa_upload }}</div>
</div>
</div>
@@ -268,10 +182,7 @@
</div>
</div>
<div class="overflow-x-auto">
<table
ref="content"
class="table text-center table-bordered"
>
<table ref="content" class="table text-center table-bordered">
<tbody>
<tr class="table-light font-bold">
<td>Bil</td>
@@ -281,12 +192,8 @@
<tr v-for="(data, index) in list.sag" :key="data">
<td>{{ index + 1 }}</td>
<td>
<a
href="#"
data-bs-toggle="modal"
data-bs-target="#marhunModal"
v-on:click="marhunModal(data)"
>
<a href="#" data-bs-toggle="modal" data-bs-target="#marhunModal"
v-on:click="marhunModal(data)">
{{ data.norujukan }}
</a>
</td>
@@ -316,29 +223,16 @@
</Accordion>
</template>
</Card>
<div
class="modal fade"
id="marhunModal"
tabindex="-1"
aria-labelledby="marhunModalLabel"
aria-hidden="true"
data-bs-backdrop="static"
>
<div class="modal fade" id="marhunModal" tabindex="-1" aria-labelledby="marhunModalLabel" aria-hidden="true"
data-bs-backdrop="static">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="grid">
<div
class="col-12 lg:col-6"
style="
<div class="col-12 lg:col-6" style="
display: flex;
justify-content: center;
align-items: center;
@@ -346,14 +240,10 @@
min-width: 300px;
max-height: 600px;
max-width: 600px;
"
>
<item-master-image-modal
v-if="theData.filemarhun"
v-bind:key="reloadImageComponent"
">
<item-master-image-modal v-if="theData.filemarhun" v-bind:key="reloadImageComponent"
v-bind:norujukan="theData.norujukan"
v-bind:filemarhun_id="theData.filemarhun[0].id"
></item-master-image-modal>
v-bind:filemarhun_id="theData.filemarhun[0].id"></item-master-image-modal>
<p v-else style="text-align: center; width: 100%">
Image Unavailable
</p>
@@ -369,10 +259,7 @@
<td style="min-width: 42px">Berat</td>
<td style="min-width: 102px">Harga Asas</td>
</tr>
<tr
v-for="(data, index) in theData.lelongbidmarhun"
v-bind:key="data"
>
<tr v-for="(data, index) in theData.lelongbidmarhun" v-bind:key="data">
<td>{{ index + 1 }}</td>
<td>{{ data.marhun }}</td>
<td>{{ data.karat }}</td>
@@ -401,21 +288,16 @@
</div>
<div class="row justify-content-center font-bold">
<div class="col-6">
<label class="col-form-label"
>Jumlah Harga Bida</label
>
<label class="col-form-label">Jumlah Harga Bida</label>
</div>
<div class="col-6">
<div class="input-group mb-3">
<span class="input-group-text font-bold">RM</span>
<span
class="form-control input-group-text font-bold"
>{{
theData.hargabida
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}</span
>
<span class="form-control input-group-text font-bold">{{
theData.hargabida
?.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",") || ""
}}</span>
</div>
</div>
</div>
@@ -423,11 +305,7 @@
</div>
</div>
<div class="modal-footer">
<Button
class="p-button-sm"
label="Kembali"
data-bs-dismiss="modal"
/>
<Button class="p-button-sm" label="Kembali" data-bs-dismiss="modal" />
</div>
</div>
</div>
@@ -435,14 +313,12 @@
</div>
</div>
<div v-else>
<div
class="
<div class="
flex
align-items-center
justify-content-center
container-height
"
>
">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-book text-8xl text-400"></i>
@@ -451,40 +327,20 @@
<span class="text-400">Tiada Data.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }"
>Keputusan</router-link
>
untuk maklumat rekod bidaan menang.</span
>
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'result' }">Keputusan</router-link>
untuk maklumat rekod bidaan menang.</span>
</div>
</div>
</div>
</div>
<Dialog
header="Surat Hak Kepemilikan Barang"
v-model:visible="isDisplay"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }"
:style="{ width: '50vw' }"
:modal="true"
:show-layout="false"
:float-layout="true"
:enable-download="true"
:preview-modal="true"
:paginate-elements-by-height="1400"
filename="hee hee"
:pdf-quality="2"
:manual-pagination="false"
pdf-format="a4"
pdf-orientation="landscape"
pdf-content-width="800px"
@progress="onProgress($event)"
@hasStartedGeneration="hasStartedGeneration()"
@hasGenerated="hasGenerated($event)"
ref="html2Pdf"
>
<div class="text-center">
<Dialog header="Surat Hak Kepemilikan Barang" v-model:visible="isDisplay"
:breakpoints="{ '960px': '75vw', '640px': '90vw' }" :style="{ width: '50vw' }" :modal="true"
:show-layout="false" :float-layout="true" :enable-download="true" :preview-modal="true"
:paginate-elements-by-height="1400" filename="hee hee" :pdf-quality="2" :manual-pagination="false"
pdf-format="a4" pdf-orientation="landscape" pdf-content-width="800px" @progress="onProgress($event)"
@hasStartedGeneration="hasStartedGeneration()" @hasGenerated="hasGenerated($event)" ref="html2Pdf">
<div v-if="suratHak?.user" class="text-center">
<p id="hakbarang">SURAT KETERANGAN KEPEMILIKAN BARANG</p>
<p>
Bahawasanya barang tersebut adalah hak milik
@@ -526,6 +382,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import jsPDF from "jspdf";
import "jspdf-autotable";
import html2canvas from "html2canvas";
@@ -560,7 +417,7 @@ export default {
isDisplayFileUpload: false,
fileSize: 0,
formResit: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
lelong_id: this.$route.params.lelongId,
gambarResit: "",
kodcaw: "",
@@ -574,7 +431,7 @@ export default {
},
created() {
this.lelongId = this.$route.params.lelongId;
this.statusPayment = this.$route.params.statusPayment;
this.statusPayment = this.$route.query.statusPayment ?? null;
},
mounted: function () {
this.liveData();
@@ -590,37 +447,38 @@ export default {
},
liveData() {
this.loading = true;
if(this.lelongId != null) {
if (this.lelongId) {
axios
.get("/bayar/" + localStorage.getItem("id") + "/" + this.lelongId, {
.get("/bayar/" + useAuthenticationUserStore().id + "/" + this.lelongId, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
// console.log("liveData", response);
if (response.data.success == true) {
this.isSuccess = true;
this.loading = false;
this.lists = response.data.data;
this.tarikhLelong = response.data.tarikh_lelong;
} else {
this.isSuccess = false;
}
this.loading = false;
})
.catch((error) => {
this.loading = false;
console.log(error);
});
} else {
this.loading = false;
this.$router.push({ name: "result" });
}
},
clickPayButton(value) {
this.$router.push({ name: "pay", params: { lelongId: value } });
this.$router.push({ name: "pay", params: { lelongId: String(value) } });
},
clickPayCdmButton(value) {
this.$router.push({ name: "pay-cdm", params: { lelongId: value } });
this.$router.push({ name: "pay-cdm", params: { lelongId: String(value) } });
},
clickBackButton() {
this.$router.push({ name: "result" });
@@ -647,7 +505,7 @@ export default {
axios
.post("/addPhotoResit", resitFormData, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -699,18 +557,29 @@ export default {
axios
.get("/resultInCawangan", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
lelong_id: this.lelongId,
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
kodcaw: value,
},
})
.then((response) => {
this.suratHak = response.data;
this.isDisplay = true;
this.isSuccessHak = true;
if (response.data?.success && response.data?.user) {
this.suratHak = response.data;
this.isSuccessHak = true;
this.isDisplay = true;
} else {
this.$swal?.fire({
toast: true,
icon: "error",
title: "Gagal memuatkan surat hak.",
position: "bottom",
showConfirmButton: false,
timer: 4000,
});
}
})
.catch((error) => {
console.log(error);
@@ -778,6 +647,51 @@ export default {
min-height: 70vh;
}
.result-accordion :deep(.p-accordion-header-link) {
display: flex;
align-items: center;
gap: 0.75rem;
}
.result-accordion :deep(.p-accordion-toggle-icon) {
flex-shrink: 0;
margin-right: 0;
}
.result-accordion-header {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1 1 auto;
min-width: 0;
gap: 0.75rem;
}
.result-accordion-title {
font-weight: 700;
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: 0.35rem;
min-width: 0;
}
.style-info {
background: #e4f8f0;
border: solid #1ea97c;
border-width: 0.1px;
color: #1ea97c;
font-size: 0.95rem;
align-items: center;
display: inline-flex;
padding: 0.35rem 0.75rem;
margin: 0;
border-radius: 6px;
font-weight: 700;
white-space: nowrap;
flex-shrink: 0;
}
.div-card-bank {
display: flex;
justify-content: center;
+21 -40
View File
@@ -1,17 +1,10 @@
<template>
<div
v-if="loading"
style="min-height: 70vh; display: grid; place-items: center"
>
<div v-if="loading" style="min-height: 70vh; display: grid; place-items: center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<div
v-else
style="min-height: 70vh"
class="container fadein animation-duration-400"
>
<div v-else style="min-height: 70vh" class="container fadein animation-duration-400">
<div v-if="isSuccess">
<Card>
<template #title>
@@ -39,7 +32,7 @@
<td v-on:click="selectDate(data)">
<span class="text-primary underline cursor-pointer">{{
data.tarikh_lelong
}}</span>
}}</span>
</td>
<td>
RM{{
@@ -49,29 +42,15 @@
}}
</td>
<td v-if="data.status == 1">
<Tag
value="Selesai"
icon="pi pi-check"
class="p-tag-rounded"
severity="success"
></Tag>
<Tag value="Selesai" icon="pi pi-check" class="p-tag-rounded" severity="success"></Tag>
</td>
<td v-else-if="data.status == 2">
<Tag
value="Tunggu Pengesahan"
icon="pi pi-stopwatch"
class="p-tag-rounded"
severity="warning"
></Tag>
<Tag value="Tunggu Pengesahan" icon="pi pi-stopwatch" class="p-tag-rounded" severity="warning">
</Tag>
</td>
<td v-else-if="data.status == null">
<div class="blink">
<Tag
value="Belum Selesai"
icon="pi pi-times"
class="p-tag-rounded"
severity="danger"
></Tag>
<Tag value="Belum Selesai" icon="pi pi-times" class="p-tag-rounded" severity="danger"></Tag>
</div>
</td>
<!-- <td>
@@ -87,9 +66,7 @@
</Card>
</div>
<div v-else>
<div
class="flex align-items-center justify-content-center container-height"
>
<div class="flex align-items-center justify-content-center container-height">
<div class="grid justify-content-center">
<div class="col-12 mb-4 text-center">
<i class="pi pi-info-circle text-8xl text-400"></i>
@@ -98,11 +75,9 @@
<span class="text-400">Tiada Data Dalam Keputusan.</span>
</div>
<div class="col-12 text-center">
<span class="text-400"
>Sila rujuk halaman
<span class="text-400">Sila rujuk halaman
<router-link v-bind:to="{ name: 'home' }">Utama</router-link>
untuk jadual lelongan.</span
>
untuk jadual lelongan.</span>
</div>
</div>
</div>
@@ -111,6 +86,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import axios from "axios";
import ResultDetail from "./ResultDetail.vue";
@@ -134,10 +110,10 @@ export default {
axios
.get("/resultLelong", {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
params: {
user_id: localStorage.getItem("id"),
user_id: useAuthenticationUserStore().id,
},
})
@@ -156,10 +132,15 @@ export default {
});
},
selectDate(value) {
this.$router.push({
const route = {
name: "detail",
params: { lelongId: value.id, statusPayment: value.status },
});
params: { lelongId: String(value.id) },
};
// Vue Router 4 only keeps params declared in the path; statusPayment is optional query
if (value.status != null) {
route.query = { statusPayment: String(value.status) };
}
this.$router.push(route);
},
},
};
+11 -10
View File
@@ -258,6 +258,7 @@
</template>
<script>
import { useAuthenticationUserStore } from "@/store/modules/authentication";
import Navbar from "../Navbar.vue";
import Footer from "../Footer.vue";
// import HistoryResult from "./HistoryResult.vue"
@@ -276,10 +277,10 @@ export default {
total_hargabida: "",
loading: false,
formPayment: {
email: localStorage.getItem("email"),
notel: localStorage.getItem("notel"),
name: localStorage.getItem("name"),
user_id: localStorage.getItem("id"),
email: useAuthenticationUserStore().email,
notel: useAuthenticationUserStore().notelbimbit,
name: useAuthenticationUserStore().name,
user_id: useAuthenticationUserStore().id,
lelong_id: localStorage.getItem("lelong_id"),
total: "",
},
@@ -292,9 +293,9 @@ export default {
resultBid() {
this.loading = true;
axios
.get("/result/" + localStorage.getItem("id"), {
.get("/result/" + useAuthenticationUserStore().id, {
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
Authorization: "Bearer " + useAuthenticationUserStore().token,
},
})
.then((response) => {
@@ -310,10 +311,10 @@ export default {
bidPayment() {
axios
.post("/bidpayment", {
email: localStorage.getItem("email"),
notel: localStorage.getItem("notel"),
name: localStorage.getItem("name"),
user_id: localStorage.getItem("id"),
email: useAuthenticationUserStore().email,
notel: useAuthenticationUserStore().notelbimbit,
name: useAuthenticationUserStore().name,
user_id: useAuthenticationUserStore().id,
lelong_id: localStorage.getItem("lelong_id"),
total: this.total_hargabida,
})
+33 -4
View File
@@ -1,7 +1,36 @@
import axios from "axios";
import router from "@/router";
import { useAuthenticationUserStore } from "@/store/modules/authentication";
const tokenKey = "token";
axios.defaults.headers.common['X-CSRF-TOKEN'] = tokenKey;
axios.defaults.baseURL = process.env.VUE_APP_ROOT_URL;
// axios.defaults.baseURL = process.env.VUE_APP_ROOT_URL;
axios.defaults.baseURL = 'https://adminlelong.erahn.com.my/api';
axios.interceptors.request.use(
(config) => {
const auth = useAuthenticationUserStore();
if (auth.token) {
config.headers.Authorization = `Bearer ${auth.token}`;
}
return config;
},
(error) => Promise.reject(error)
);
axios.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 401) {
const auth = useAuthenticationUserStore();
auth.clearSession();
const currentName = router.currentRoute.value.name;
if (
currentName !== "login" &&
currentName !== "register" &&
currentName !== "forgot-password" &&
currentName !== "reset-password"
) {
router.push({ name: "login" });
}
}
return Promise.reject(error);
}
);
+6 -2
View File
@@ -12,7 +12,7 @@ import 'sweetalert2/dist/sweetalert2.min.css';
import PrimeVue from 'primevue/config';
import '../public/themes/lara-light-blue/theme.css'
import 'primevue/resources/primevue.min.css'
import './styles/primevue-bootstrap.css'
import 'primeicons/primeicons.css'
import 'primeflex/primeflex.css'
import ToastService from 'primevue/toastservice';
@@ -57,6 +57,7 @@ import VueViewer from 'v-viewer';
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import { useAuthenticationUserStore } from '@/store/modules/authentication'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
@@ -106,7 +107,10 @@ app.component('MazPhoneNumberInput', MazPhoneNumberInput)
app.component('YouTube', YouTube)
app.use(router).use(pinia).use(PrimeVue).use(VueSweetalert2).use(ToastService).use(VueViewer).mount('#app');
app.use(pinia)
useAuthenticationUserStore().migrateLegacySession()
app.use(router).use(PrimeVue).use(VueSweetalert2).use(ToastService).use(VueViewer).mount('#app');
// app.use(router).use(store).use(PrimeVue).use(ToastService).mount('#app');
// createApp(App).use(router).use(store).mount('#app')
+94 -62
View File
@@ -134,101 +134,113 @@ import ThePay from "../components/pay/ThePay.vue";
import ThePayCdm from "../components/pay/ThePayCdm.vue";
import ThePolicy from "../components/policy/ThePolicy.vue";
import TheForgotPassword from "../components/authentication/TheForgotPassword.vue";
import TheResetPassword from "../components/authentication/TheResetPassword.vue";
import {
createRouter,
createWebHistory,
createMemoryHistory,
} from "vue-router";
import { useAuthenticationUserStore } from "@/store/modules/authentication";
// import Register from "../components/Register.vue";
// import IndexPaymentHistory from '../components/result/IndexPaymentHistory.vue'
// import Modals from './../components/Modal.vue'
// import { Modal } from "bootstrap";
const routes = [
{
path: "/",
redirect: (to) => ({ path: "/login", query: to.query }),
},
{
path: "/login",
name: "login",
component: TheLogin,
// meta: { guest: true }
meta: { guest: true },
},
{
path: "/register",
name: "register",
component: TheRegister,
// meta: { guest: true }
},
{
path: "/",
name: "login",
component: TheLogin,
meta: { guest: true },
},
{
path: "/forgot-password",
name: "forgot-password",
component: TheForgotPassword,
meta: { guest: true },
},
{
path: "/home",
name: "home",
component: TheHome,
},
{
path: "/cart",
name: "cart",
component: TheCart,
// meta: { requiresAuth: true }
},
{
path: "/list",
name: "list",
component: TheList,
// meta: { requiresAuth: true }
},
{
path: "/profile",
name: "profile",
component: TheProfile,
// meta: { requiresAuth: true }
},
{
path: "/bid-record",
name: "bid-record",
component: TheBidRecord,
// meta: { requiresAuth: true }
},
{
path: "/result",
name: "result",
component: TheResult,
// meta: { requiresAuth: true }
},
{
path: "/result-detail",
name: "detail",
component: ResultDetail,
// meta: { requiresAuth: true }
},
{
path: "/result/detail/receipt",
name: "receipt",
component: ResultReceipt,
// meta: { requiresAuth: true }
},
{
path: "/pay",
name: "pay",
component: ThePay,
},
{
path: "/pay-cdm",
name: "pay-cdm",
component: ThePayCdm,
path: "/reset-password/:token",
name: "reset-password",
component: TheResetPassword,
meta: { guest: true },
},
{
path: "/policy",
name: "policy",
component: ThePolicy,
meta: { guest: true },
},
{
path: "/home",
name: "home",
component: TheHome,
meta: { requiresAuth: true },
},
{
path: "/cart",
name: "cart",
component: TheCart,
meta: { requiresAuth: true },
},
{
path: "/list",
name: "list",
component: TheList,
meta: { requiresAuth: true },
},
{
path: "/profile",
name: "profile",
component: TheProfile,
meta: { requiresAuth: true },
},
{
path: "/bid-record",
name: "bid-record",
component: TheBidRecord,
meta: { requiresAuth: true },
},
{
path: "/result",
name: "result",
component: TheResult,
meta: { requiresAuth: true },
},
{
path: "/result-detail/:lelongId",
name: "detail",
component: ResultDetail,
meta: { requiresAuth: true },
},
{
path: "/result/detail/receipt",
name: "receipt",
component: ResultReceipt,
meta: { requiresAuth: true },
},
{
path: "/pay/:lelongId",
name: "pay",
component: ThePay,
meta: { requiresAuth: true },
},
{
path: "/pay-cdm/:lelongId",
name: "pay-cdm",
component: ThePayCdm,
meta: { requiresAuth: true },
},
];
@@ -239,4 +251,24 @@ const router = createRouter({
routes,
});
router.beforeEach((to, from, next) => {
const auth = useAuthenticationUserStore();
if (to.meta.requiresAuth && !auth.isAuthenticated) {
next({ name: "login", query: { redirect: to.fullPath } });
return;
}
if (
to.meta.guest &&
auth.isAuthenticated &&
(to.name === "login" || to.name === "register")
) {
next({ name: "home" });
return;
}
next();
});
export default router;
+88 -33
View File
@@ -1,39 +1,94 @@
import { defineStore } from 'pinia'
const LEGACY_KEYS = [
'token',
'id',
'nokp',
'name',
'email',
'notelbimbit',
'username',
'notel',
]
export const useAuthenticationUserStore = defineStore('authenticationUser', {
state: () => ({
token: "",
id: "",
nokp: "",
name: "",
email: "",
notelbimbit: "",
username: ""
}),
getters: {
getToken() {
return this.token;
},
getId() {
return this.id;
},
getNokp() {
return this.nokp;
},
getName() {
return this.name;
},
getEmail() {
return this.email;
},
getNoTelBimbit() {
return this.notelbimbit;
},
getUsername() {
return this.username;
},
state: () => ({
token: '',
id: '',
nokp: '',
name: '',
email: '',
notelbimbit: '',
username: '',
}),
getters: {
isAuthenticated: (state) => Boolean(state.token),
getToken() {
return this.token
},
actions: {
getId() {
return this.id
},
persist: true,
getNokp() {
return this.nokp
},
getName() {
return this.name
},
getEmail() {
return this.email
},
getNoTelBimbit() {
return this.notelbimbit
},
getUsername() {
return this.username
},
},
actions: {
setSession({ token, user }) {
this.token = token || ''
this.id = user?.id ?? ''
this.nokp = user?.nokp ?? ''
this.name = user?.name ?? ''
this.email = user?.email ?? ''
this.notelbimbit = user?.notelbimbit ?? ''
this.username = user?.username ?? ''
this.clearLegacyKeys()
},
clearSession() {
this.$reset()
this.clearLegacyKeys()
},
clearLegacyKeys() {
LEGACY_KEYS.forEach((key) => localStorage.removeItem(key))
},
migrateLegacySession() {
if (this.token) {
this.clearLegacyKeys()
return
}
const legacyToken = localStorage.getItem('token')
if (!legacyToken) {
return
}
this.setSession({
token: legacyToken,
user: {
id: localStorage.getItem('id') || '',
nokp: localStorage.getItem('nokp') || '',
name: localStorage.getItem('name') || '',
email: localStorage.getItem('email') || '',
notelbimbit:
localStorage.getItem('notelbimbit') ||
localStorage.getItem('notel') ||
'',
username: localStorage.getItem('username') || '',
},
})
},
},
persist: true,
})
+41
View File
@@ -0,0 +1,41 @@
import { defineStore } from "pinia";
import axios from "axios";
import { useAuthenticationUserStore } from "@/store/modules/authentication";
export const useCartStore = defineStore("cart", {
state: () => ({
count: 0,
}),
getters: {
hasItems: (state) => state.count > 0,
badgeLabel: (state) => (state.count > 99 ? "99+" : String(state.count)),
},
actions: {
async fetchCount() {
const auth = useAuthenticationUserStore();
if (!auth.token || !auth.id) {
this.count = 0;
return;
}
try {
const response = await axios.get("/itemInCart", {
headers: {
Authorization: "Bearer " + auth.token,
},
params: {
user_id: auth.id,
},
});
this.count =
response.data.success === true ? Number(response.data.cart) || 0 : 0;
} catch (error) {
console.log(error);
}
},
clear() {
this.count = 0;
},
},
});
+49
View File
@@ -0,0 +1,49 @@
/*
Keep the project's existing Bootstrap + public theme colors.
Newer PrimeVue emptied primevue.min.css, so TabView layout rules are
patched here instead of switching to the layered node_modules theme
(which overrides login and brand colors).
*/
.p-tabview-nav-container {
position: relative;
}
.p-tabview-nav-content {
overflow-x: auto;
overflow-y: hidden;
scroll-behavior: smooth;
scrollbar-width: none;
}
.p-tabview-nav-content::-webkit-scrollbar {
display: none;
}
.p-tabview .p-tabview-nav {
display: flex;
margin: 0;
padding: 0;
list-style-type: none;
flex: 1 1 auto;
}
.p-tabview .p-tabview-nav li {
margin-right: 0;
}
.p-tabview .p-tabview-nav li .p-tabview-nav-link,
.p-tabview .p-tabview-header-action {
cursor: pointer;
user-select: none;
display: flex;
align-items: center;
position: relative;
text-decoration: none;
overflow: hidden;
}
.p-tabview .p-tabview-title {
line-height: 1;
white-space: nowrap;
}