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