fix(ui): resolve dark mode layout gray colors in light-mode browser and fix row index looping on paginated tables

This commit is contained in:
Rafif-Riqullah-Siregar committed 2026-07-16 14:30:23 +07:00
1 parent 46f33eb088
commit 202ecfa485
19 files changed
+374 -34

No files matched your search

+22 -3
View File
@@ -101,26 +101,45 @@ router.post('/change-account-name', requireAuth, async (req, res) => {
});
// ─── POST /api/auth/upload-profile-picture ───────────────────────────────────
router.post('/upload-profile-picture', requireAuth, upload.single('profile_picture'), async (req, res) => {
// Multer errors TIDAK tertangkap oleh try/catch di route handler.
// Wajib menggunakan callback agar error multer dikembalikan sebagai JSON, bukan HTML.
router.post('/upload-profile-picture', requireAuth, (req, res, next) => {
upload.single('profile_picture')(req, res, (multerErr) => {
if (multerErr) {
console.error('[Upload] Multer error:', multerErr.message);
return res.status(400).json({ error: `Upload gagal: ${multerErr.message}` });
}
next();
});
}, async (req, res) => {
try {
if (!req.file) return res.status(400).json({ error: 'No image uploaded' });
if (!req.file) return res.status(400).json({ error: 'No image uploaded. Please select an image file first.' });
const user = await User.findById(req.user.id);
if (!user) return res.status(404).json({ error: 'User not found' });
// Hapus foto profil lama jika ada
if (user.profile_picture) {
const oldPath = path.join(getUploadsDir(), user.profile_picture);
if (fs.existsSync(oldPath)) {
try { fs.unlinkSync(oldPath); } catch (_) {}
}
}
user.profile_picture = req.file.filename;
await user.save();
const newToken = makeToken(user);
setCookieToken(res, newToken);
res.json({ ok: true, message: 'Foto profil berhasil diperbarui', profile_picture: req.file.filename });
res.json({ ok: true, message: 'Profile picture updated successfully.', profile_picture: req.file.filename });
} catch (err) {
console.error('[Upload Error]', err);
res.status(500).json({ error: err.message });
}
});
// ─── POST /api/auth/remove-profile-picture ───────────────────────────────────
router.post('/remove-profile-picture', requireAuth, async (req, res) => {
try {
+13
View File
@@ -122,6 +122,19 @@ app.get('/api/health', (req, res) => {
});
});
// ─── Global JSON Error Handler ────────────────────────────────────────────────
// Menangkap semua error yang tidak di-handle (termasuk multer, mongoose, dll.)
// dan memastikan response selalu JSON, BUKAN HTML default Express.
// eslint-disable-next-line no-unused-vars
app.use((err, req, res, next) => {
console.error('[Global Error Handler]', err.message || err);
const status = err.status || err.statusCode || 500;
res.status(status).json({
error: err.message || 'Internal server error',
code: err.code || undefined,
});
});
// ─── Start Server ─────────────────────────────────────────────────────────────
// Bind to 127.0.0.1 in production to prevent direct external access to port 3001.
// All external traffic must go through the reverse proxy (Apache/Nginx) at port 80/443.