From 9c1de91a826f0c404369ce14ae1a911799b67883 Mon Sep 17 00:00:00 2001 From: Dodo Date: Thu, 4 Jun 2026 17:06:11 +0700 Subject: [PATCH] fix(tapops): ganti input date native dengan dd/mm/yyyy text input terpisah agar tahun max 4 digit --- groups/Tapops/css/documents.css | 57 ++++++++++----------- groups/Tapops/index.html | 16 ++++-- groups/Tapops/js/main.js | 87 +++++++++++++++++++++++---------- 3 files changed, 102 insertions(+), 58 deletions(-) diff --git a/groups/Tapops/css/documents.css b/groups/Tapops/css/documents.css index 799ac4d..0b6e850 100644 --- a/groups/Tapops/css/documents.css +++ b/groups/Tapops/css/documents.css @@ -363,36 +363,47 @@ background: white; } -.date-range-inputs .input-wrapper { - position: relative; +/* Custom dd/mm/yyyy date input */ +.custom-date-input { display: flex; align-items: center; + gap: 1px; + padding: 6px 0; } -.date-range-inputs input[type="date"] { +.date-sep { + font-size: 0.85rem; + font-weight: 700; + color: #94a3b8; + user-select: none; + padding: 0 1px; +} + +.date-part { border: none; background: transparent; - padding: 8px 0; font-family: inherit; font-size: 0.85rem; font-weight: 700; color: var(--primary-blue); - cursor: pointer; - min-width: 120px; + text-align: center; + padding: 2px 3px; + border-radius: 3px; + transition: background 0.15s ease; + min-width: 0; } -.date-range-inputs input[type="date"]:focus { +.date-dd, .date-mm { width: 2.2ch; } +.date-yyyy { width: 4.2ch; } + +.date-part::placeholder { + color: #94a3b8; + font-weight: 400; +} + +.date-part:focus { outline: none; -} - -.date-range-inputs input[type="date"]::-webkit-calendar-picker-indicator { - cursor: pointer; - opacity: 0.6; - transition: opacity 0.2s; -} - -.date-range-inputs input[type="date"]::-webkit-calendar-picker-indicator:hover { - opacity: 1; + background: rgba(0, 49, 80, 0.07); } .range-divider { @@ -701,18 +712,8 @@ a.btn-action-outline:hover { box-shadow: 0 0 0 3px rgba(0, 49, 80, 0.08); } - .date-range-inputs input[type="date"] { - width: 100%; - border: none; - background: transparent; - padding: 0; - font-family: inherit; + .date-part { font-size: 0.82rem; - font-weight: 700; - color: var(--primary-blue); - min-width: 0; - flex: 1; - cursor: pointer; } .range-divider { diff --git a/groups/Tapops/index.html b/groups/Tapops/index.html index 9e27431..898939f 100644 --- a/groups/Tapops/index.html +++ b/groups/Tapops/index.html @@ -946,12 +946,20 @@
Periode Unggahan
-
- +
+ + / + + / +
s/d -
- +
+ + / + + / +
diff --git a/groups/Tapops/js/main.js b/groups/Tapops/js/main.js index 949cab2..1633c26 100644 --- a/groups/Tapops/js/main.js +++ b/groups/Tapops/js/main.js @@ -423,14 +423,23 @@ class DocumentRepository { this.filterWrapper = document.getElementById('tag-filter-wrapper'); this.mobileFilterWrapper = document.getElementById('mobile-tag-filter-wrapper'); this.searchInput = document.getElementById('doc-search'); - this.dateStartInput = document.getElementById('date-start'); - this.dateEndInput = document.getElementById('date-end'); this.sortFilterWrapper = document.getElementById('sort-filter-wrapper'); // Hero stat values (filled from real API data after fetch). this.statActiveEl = document.getElementById('stat-active-value'); this.statUpdatesEl = document.getElementById('stat-updates-value'); + this.dateStartParts = { + dd: document.getElementById('date-start-dd'), + mm: document.getElementById('date-start-mm'), + yyyy: document.getElementById('date-start-yyyy'), + }; + this.dateEndParts = { + dd: document.getElementById('date-end-dd'), + mm: document.getElementById('date-end-mm'), + yyyy: document.getElementById('date-end-yyyy'), + }; + this.cards = []; this.paginationContainer = null; this.state = { @@ -443,6 +452,52 @@ class DocumentRepository { }; } + // Returns YYYY-MM-DD string only when dd, mm, and yyyy are all filled and valid. + _getDateString(parts) { + const dd = parts.dd?.value.trim() || ''; + const mm = parts.mm?.value.trim() || ''; + const yyyy = parts.yyyy?.value.trim() || ''; + + if (!dd || !mm || yyyy.length < 4) return ''; + + const d = parseInt(dd, 10); + const m = parseInt(mm, 10); + const y = parseInt(yyyy, 10); + + if (isNaN(d) || isNaN(m) || isNaN(y)) return ''; + if (d < 1 || d > 31 || m < 1 || m > 12 || y < 1 || y > 9999) return ''; + + return `${String(y).padStart(4, '0')}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`; + } + + // Wire up a set of dd/mm/yyyy text inputs: + // • numeric-only keydown guard + // • auto-advance dd→mm after 2 chars, mm→yyyy after 2 chars + // • backspace from empty field navigates back + // • calls onUpdate() on every change + _bindDateParts(parts, onUpdate) { + const { dd, mm, yyyy } = parts; + const CTRL_KEYS = new Set(['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'Enter']); + + const setup = (input, prev, next) => { + if (!input) return; + input.addEventListener('keydown', (e) => { + if (!/^\d$/.test(e.key) && !CTRL_KEYS.has(e.key)) e.preventDefault(); + if (e.key === 'Backspace' && !input.value && prev) prev.focus(); + }); + input.addEventListener('input', () => { + input.value = input.value.replace(/\D/g, ''); + onUpdate(); + const max = parseInt(input.getAttribute('maxlength'), 10); + if (next && input.value.length >= max) next.focus(); + }); + }; + + setup(dd, null, mm); + setup(mm, dd, yyyy); + setup(yyyy, mm, null); + } + async init() { if (!this.gridContainer) return; this._bindControls(); @@ -581,40 +636,20 @@ class DocumentRepository { } _bindControls() { - // Limit date inputs to a 4-digit year (max 9999). - [this.dateStartInput, this.dateEndInput].forEach(input => { - if (!input) return; - input.setAttribute('max', '9999-12-31'); - input.setAttribute('min', '1000-01-01'); - // Clamp year on both input (fires while typing) and change (fires on blur). - const clampYear = () => { - if (!input.value) return; - const parts = input.value.split('-'); - if (parts.length !== 3) return; - const year = parseInt(parts[0], 10); - if (!Number.isNaN(year) && year > 9999) { - parts[0] = '9999'; - input.value = parts.join('-'); - } - }; - input.addEventListener('input', clampYear); - input.addEventListener('change', clampYear); - }); - this.searchInput?.addEventListener('input', (e) => { this.state.search = e.target.value.toLowerCase().trim(); this.state.page = 1; this._applyFilters(); }); - this.dateStartInput?.addEventListener('change', (e) => { - this.state.startDate = e.target.value; + this._bindDateParts(this.dateStartParts, () => { + this.state.startDate = this._getDateString(this.dateStartParts); this.state.page = 1; this._applyFilters(); }); - this.dateEndInput?.addEventListener('change', (e) => { - this.state.endDate = e.target.value; + this._bindDateParts(this.dateEndParts, () => { + this.state.endDate = this._getDateString(this.dateEndParts); this.state.page = 1; this._applyFilters(); });