DONE: add flexible json update saham, yuran, and pelaburan ui

This commit is contained in:
ISMAIL MASSERAN
2026-07-19 11:54:13 +08:00
parent fa2eaef6c4
commit cd1dc4b9d8
18 changed files with 4010 additions and 15 deletions
@@ -51,7 +51,33 @@
</div>
</transition>
<div class="sso-only-notice">
<!-- Local / development: OTP login via IC number -->
<form v-if="isLocalDev" @submit.prevent="login" id="login_form" class="login-form" novalidate>
<div class="form-group mb-3">
<label class="login-label" for="no_kp">No. Kad Pengenalan</label>
<div class="login-field">
<span class="login-field-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<path
d="M4 7.5A3.5 3.5 0 0 1 7.5 4h9A3.5 3.5 0 0 1 20 7.5v9A3.5 3.5 0 0 1 16.5 20h-9A3.5 3.5 0 0 1 4 16.5v-9Zm3.5-1.5A1.5 1.5 0 0 0 6 7.5v9A1.5 1.5 0 0 0 7.5 18h9a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 16.5 6h-9Zm1.5 3h6v2H9V9Zm0 4h10v2H9v-2Z" />
</svg>
</span>
<input v-model.trim="no_kp" @input="onNoKpInput" :disabled="loading" type="text" id="no_kp"
name="no_kp" class="form-control login-input" placeholder="Contoh: 901010101010"
autocomplete="off" inputmode="numeric" enterkeyhint="go" required />
</div>
<small class="login-help">Masukkan tanpa dash (-) atau jarak.</small>
</div>
<button type="submit" class="btn login-btn" :disabled="loading || !no_kp">
<span v-if="loading" class="spinner-border spinner-border-sm mr-2" role="status"
aria-hidden="true"></span>
<span>{{ loading ? 'Sedang log masuk…' : 'Masuk' }}</span>
</button>
</form>
<!-- Production: SSO only -->
<div v-else class="sso-only-notice">
<div class="sso-only-notice__icon" aria-hidden="true">
<svg viewBox="0 0 24 24" focusable="false">
<path
@@ -73,12 +99,15 @@
<script>
const SSO_LOADING_MS = 2500;
const SSO_SUCCESS_MS = 2500;
const LOCAL_ENVS = ['local', 'development'];
export default {
data() {
return {
SSO_LOADING_MS,
SSO_SUCCESS_MS,
loading: false,
no_kp: '',
ssoAlert: {
visible: false,
title: '',
@@ -96,6 +125,13 @@ export default {
};
},
computed: {
isLocalDev() {
const env = (window.config && window.config.env) || '';
return LOCAL_ENVS.indexOf(String(env).toLowerCase()) !== -1;
}
},
beforeDestroy() {
if (this.ssoRedirectTimer) {
window.clearTimeout(this.ssoRedirectTimer);
@@ -112,6 +148,45 @@ export default {
},
methods: {
onNoKpInput() {
this.no_kp = (this.no_kp || '').replace(/[\s-]+/g, '').replace(/[^\d]/g, '');
},
login() {
if (!this.isLocalDev) {
return;
}
this.startLoading();
const noKp = (this.no_kp || '').trim();
axios
.post(config.API + 'voter/login', {
no_kp: noKp,
send_otp: false
})
.then(response => {
this.stopLoading();
if (this.util.showResult(response, 'success')) {
this.$router.push({
name: 'Voter Verify',
params: {
nokp: response.data.nokp,
notel: response.data.notel,
debug_otp: response.data.debug_otp || null
}
});
}
})
.catch(error => {
this.stopLoading();
this.util.showResult(error, 'error');
});
},
startLoading() {
this.loading = true;
},
stopLoading() {
this.loading = false;
},
handleSsoCallback() {
const params = new URLSearchParams(window.location.search);
const ssoError = params.get('sso_error');
@@ -723,4 +798,4 @@ export default {
max-width: 200px;
}
}
</style>
</style>