forked from izu/student-web-if-development-kit
refactor(tapops): modularize page code
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
export class DateRangeCalculator {
|
||||
static clearTime(date) {
|
||||
if (!date) return null;
|
||||
const d = new Date(date);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
}
|
||||
|
||||
static datesEqual(left, right) {
|
||||
if (!left || !right) return false;
|
||||
return left.getFullYear() === right.getFullYear()
|
||||
&& left.getMonth() === right.getMonth()
|
||||
&& left.getDate() === right.getDate();
|
||||
}
|
||||
|
||||
static calculatePreset(presetName, todayInput = new Date()) {
|
||||
const today = this.clearTime(todayInput);
|
||||
let start = null;
|
||||
let end = null;
|
||||
|
||||
switch (presetName) {
|
||||
case 'today':
|
||||
start = new Date(today);
|
||||
end = new Date(today);
|
||||
break;
|
||||
case 'yesterday':
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - 1);
|
||||
end = new Date(start);
|
||||
break;
|
||||
case 'last7':
|
||||
end = new Date(today);
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - 6);
|
||||
break;
|
||||
case 'last14':
|
||||
end = new Date(today);
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - 13);
|
||||
break;
|
||||
case 'last30':
|
||||
end = new Date(today);
|
||||
start = new Date(today);
|
||||
start.setDate(today.getDate() - 29);
|
||||
break;
|
||||
case 'thisWeek': {
|
||||
end = new Date(today);
|
||||
start = new Date(today);
|
||||
const day = today.getDay();
|
||||
const diff = today.getDate() - day + (day === 0 ? -6 : 1);
|
||||
start.setDate(diff);
|
||||
break;
|
||||
}
|
||||
case 'lastWeek': {
|
||||
const temp = new Date(today);
|
||||
const day = temp.getDay();
|
||||
const diff = temp.getDate() - day + (day === 0 ? -6 : 1);
|
||||
start = new Date(temp);
|
||||
start.setDate(diff - 7);
|
||||
end = new Date(temp);
|
||||
end.setDate(diff - 1);
|
||||
break;
|
||||
}
|
||||
case 'thisMonth':
|
||||
start = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
end = new Date(today);
|
||||
break;
|
||||
case 'lastMonth':
|
||||
start = new Date(today.getFullYear(), today.getMonth() - 1, 1);
|
||||
end = new Date(today.getFullYear(), today.getMonth(), 0);
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
start = null;
|
||||
end = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return { start, end };
|
||||
}
|
||||
|
||||
static formatDisplay(date) {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
return `${day}/${month}/${d.getFullYear()}`;
|
||||
}
|
||||
|
||||
static parseDisplayDate(value) {
|
||||
const match = String(value || '').trim().match(/^(\d{1,2})[\/\-.](\d{1,2})[\/\-.](\d{4})$/);
|
||||
if (!match) return null;
|
||||
|
||||
const day = Number.parseInt(match[1], 10);
|
||||
const month = Number.parseInt(match[2], 10) - 1;
|
||||
const year = Number.parseInt(match[3], 10);
|
||||
if (month < 0 || month > 11 || day < 1 || day > 31 || year < 1000 || year > 9999) return null;
|
||||
|
||||
const date = new Date(year, month, day);
|
||||
if (date.getFullYear() !== year || date.getMonth() !== month || date.getDate() !== day) return null;
|
||||
return date;
|
||||
}
|
||||
|
||||
static toDateKey(date) {
|
||||
if (!date) return '';
|
||||
const d = new Date(date);
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
export class DocumentFormatter {
|
||||
static MONTHS_ID = ['Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des'];
|
||||
|
||||
static CATEGORY_RULES = [
|
||||
{ key: 'skripsi', match: ['skripsi', 'tugas akhir', 'ta'] },
|
||||
{ key: 'akademik', match: ['akademik', 'kalender', 'kaldik'] },
|
||||
{ key: 'praktik', match: ['praktik', 'praktek', 'kerja praktik', 'kp'] },
|
||||
];
|
||||
|
||||
static formatDate(iso) {
|
||||
if (!iso) return '';
|
||||
const date = new Date(iso);
|
||||
if (Number.isNaN(date.getTime())) return '';
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const month = this.MONTHS_ID[date.getMonth()];
|
||||
return `${day} ${month} ${date.getFullYear()}`;
|
||||
}
|
||||
|
||||
static categoryFromTags(tags) {
|
||||
if (!tags || tags.length === 0) return 'umum';
|
||||
const lower = tags.map(tag => tag.toLowerCase());
|
||||
for (const rule of this.CATEGORY_RULES) {
|
||||
if (rule.match.some(match => lower.includes(match))) return rule.key;
|
||||
}
|
||||
return 'umum';
|
||||
}
|
||||
|
||||
static fileTypeFromName(name) {
|
||||
const lower = (name || '').toLowerCase();
|
||||
if (lower.endsWith('.docx') || lower.endsWith('.doc')) return 'docx';
|
||||
return 'pdf';
|
||||
}
|
||||
|
||||
static downloadFilename(name, type) {
|
||||
const ext = `.${type}`;
|
||||
return name.toLowerCase().endsWith(ext) ? name : `${name}${ext}`;
|
||||
}
|
||||
|
||||
static escapeHtml(str) {
|
||||
if (str == null) return '';
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
static escapeAttr(str) {
|
||||
return this.escapeHtml(str);
|
||||
}
|
||||
|
||||
static parseTags(raw) {
|
||||
if (!raw) return [];
|
||||
const str = String(raw).trim();
|
||||
if (!str) return [];
|
||||
|
||||
if (str.startsWith('[')) {
|
||||
try {
|
||||
const arr = JSON.parse(str);
|
||||
if (Array.isArray(arr)) {
|
||||
return arr.map(tag => String(tag).trim()).filter(Boolean);
|
||||
}
|
||||
} catch {
|
||||
// Fall through to comma-separated parsing.
|
||||
}
|
||||
}
|
||||
|
||||
return str.split(',').map(tag => tag.trim()).filter(Boolean);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user