Rapihin setup/member/lot-parking + fitur intercom, exclude WIP controller & file sampah dari git

Kumpulan perubahan yang udah numpuk di working tree: refactor Setup
(Gate/Vehicle/Member), rapihin memberin & stiker, service parking baru
(ParkingUtilsServices, NetworkService), model/migration lot-parking &
DHCP reservation, dan fitur baru Intercom (controller/model/migration/
view).

ReportTransaksiController versi lokal ini WIP (~90%, masih didebug) -
versi yang bener ada di server, jadi dikeluarin dari git (ditambahin
ke .gitignore) biar gak numpuk nindihin punya server pas git pull di
sana. Sekalian keluarin dump mentah tabel softseting (1.8MB, nyasar
ke-commit), file .bak, dan arsip ad-hoc (api.tgz, c.zip) yang emang
bukan source code.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EAJc2mrpj2cSTe4oowLPzQ
This commit is contained in:
2026-10-04 07:15:54 +07:00
co-authored by Claude Sonnet 5
parent efdea9d739
commit 2a9b28581c
91 changed files with 5716 additions and 2470 deletions
+67 -33
View File
@@ -162,19 +162,25 @@
let id = $(this).data('id');
let nama = $(this).data('nama');
// # base url tanpa parameter biar tidak dobel slash
let baseUrl = "{{ url('setup/master/gate-hardware') }}";
$.ajax({
url: "{{ route('hardware.show', '') }}/" + id,
url: baseUrl + "/" + id,
type: 'GET',
success: function (r) {
r = r || {};
console.log(r);
let colSpan = row.children('td').length;
// Field yang mau ditampilkan (pilih sendiri mau yang mana)
// # daftar field yang ditampilkan (key database + label)
let fields = [
['printer1_avail', 'Printer Status'],
['printer1_conn', 'Printer Connection'],
['printer1_spd', 'Printer Speed/Baudrate'],
['printer1_dummy', 'Jarak Potong Kertas'],
['video1_avail', 'Kamera Status'],
['video1_conn', 'Kamera URL/Path'],
['sound_avail', 'Sound Status'],
@@ -183,25 +189,32 @@
['bank_reader_avail', 'Reader BANK Status'],
['bank_reader_comm', 'Reader BANK Connection'],
['bank_reader_key', 'Reader BANK Key/Parameter'],
['smartcard_avail', 'Smartcard Status'],
['smartcard_speed', 'Smartcard Speed/Baudrate'],
['smartcard_port', 'Smartcard Port'],
];
let rows = '';
let cards = '';
for (let i = 0; i < fields.length; i ++) {
let f1 = fields[i];
let val = r[f1[0]] ?? '';
rows += `
<tr>
<td class="fw-semibold text-muted text-label"><strong>${f1[1]}</strong></td>
<td>
<span class="view-mode">${formatValue(f1[0], r[f1[0]])}</span>
<input type="text"
class="form-control form-control-sm edit-mode d-none"
data-key="${f1[0]}"
value="${r[f1[0]] ?? ''}">
</td>
</tr>
cards += `
<div class="col-12 col-sm-6 col-lg-3 mb-2">
<div class="border rounded p-2 h-100">
<div class="fw-semibold text-muted text-label mb-1"><strong>${f1[1]}</strong></div>
<div>
<span class="view-mode">${formatValue(f1[0], r[f1[0]])}</span>
<input type="text"
class="form-control form-control-sm edit-mode d-none"
data-key="${f1[0]}"
data-orig="${esc(val)}"
value="${esc(val)}">
</div>
</div>
</div>
`;
}
@@ -210,7 +223,7 @@ class="form-control form-control-sm edit-mode d-none"
<td colspan="${colSpan}">
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<strong>Hardware Configuration</strong>
<strong>Hardware Configuration - ${esc(nama)} (${esc(id)})</strong>
<div>
<button class="btn btn-sm btn-primary btn-edit">Edit</button>
<button class="btn btn-sm btn-success btn-save d-none">Save</button>
@@ -218,17 +231,9 @@ class="form-control form-control-sm edit-mode d-none"
</div>
</div>
<div class="card-body p-2">
<table class="table table-bordered table-sm align-middle mb-0">
<thead class="table-light">
<tr>
<th width="15%">Setting</th>
<th width="85%">Value</th>
</tr>
</thead>
<tbody>
${rows}
</tbody>
</table>
<div class="row">
${cards}
</div>
</div>
</div>
</td>
@@ -256,6 +261,11 @@ class="form-control form-control-sm edit-mode d-none"
// CANCEL
$(document).on('click', '.btn-cancel', function () {
// # kembalikan isian ke nilai semula
$('.edit-mode').each(function () {
$(this).val($(this).data('orig') ?? '');
});
$('.edit-mode').addClass('d-none');
$('.view-mode').removeClass('d-none');
@@ -267,6 +277,7 @@ class="form-control form-control-sm edit-mode d-none"
$(document).on('click', '.btn-save', function () {
let dataToSend = {};
let gateId = $('.edit-row').data('id');
$('.edit-mode').each(function () {
let key = $(this).data('key');
@@ -274,28 +285,48 @@ class="form-control form-control-sm edit-mode d-none"
});
console.log(dataToSend);
let gateId = $('.edit-row').data('id');
// # base url tanpa parameter biar tidak dobel slash
let baseUrl = "{{ url('setup/master/gate-hardware') }}";
$.ajax({
url: "{{ route('hardware.update', '') }}/" + gateId,
type: "PUT",
url: baseUrl + "/" + gateId,
type: "POST",
data: {
_token: "{{ csrf_token() }}",
_method: "PUT",
data: dataToSend
},
success: function () {
success: function (res) {
// # tampilkan ulang nilai yang baru disimpan
$('.edit-mode').each(function () {
let key = $(this).data('key');
let val = $(this).val();
$(this).siblings('.view-mode').text(val);
$(this).data('orig', val);
$(this).siblings('.view-mode').html(formatValue(key, val));
});
$('.btn-cancel').click();
alert('Berhasil disimpan 🔥');
alert('Berhasil disimpan');
},
error: function (xhr) {
console.error(xhr.responseText);
alert('Gagal menyimpan. Cek koneksi / hubungi admin.');
}
});
});
// # amankan teks biar tanda kutip tidak merusak HTML
function esc(value) {
if (value === null || value === undefined) return '';
return String(value)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
function formatValue(key, value) {
// kalau field *_avail kita kasih badge
@@ -309,7 +340,10 @@ function formatValue(key, value) {
}
// default
return value ?? '-';
if (value === null || value === undefined || value === '') {
return '-';
}
return esc(value);
}
});