const express = require('express');
const mysql = require('mysql2/promise');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const port = 3000;
app.use(cors());
app.use(bodyParser.json());
// Konfigurasi koneksi MySQL
const dbConfig = {
host: 'localhost',
user: 'root', // Ganti sesuai user MySQL Anda
password: '', // Ganti sesuai password MySQL Anda
database: 'kanban_db',
};
let pool;
async function initDb() {
pool = await mysql.createPool(dbConfig);
}
initDb().catch((err) => {
console.error('Failed to initialize database pool:', err);
process.exit(1);
});
// Endpoint untuk mendapatkan daftar PIC
app.get('/api/pics', async (req, res) => {
try {
const [rows] = await pool.query('SELECT id, name FROM pic ORDER BY name');
res.json(rows.map((r) => r.name));
} catch (error) {
console.error('Error fetching PICs:', error);
res.status(500).json({ error: 'Failed to fetch PICs' });
}
});
// Endpoint untuk menambah PIC baru
app.post('/api/pics', async (req, res) => {
try {
const { name } = req.body;
if (!name || !name.trim()) {
return res.status(400).json({ error: 'Name is required' });
}
await pool.query('INSERT INTO pic (name) VALUES (?)', [name.trim()]);
res.json({ message: 'PIC added successfully' });
} catch (error) {
console.error('Error adding PIC:', error);
res.status(500).json({ error: 'Failed to add PIC' });
}
});
// Endpoint untuk mendapatkan daftar Activity (Task options)
app.get('/api/task-options', async (req, res) => {
try {
const [rows] = await pool.query('SELECT id, name FROM activity ORDER BY name');
res.json(rows.map((r) => r.name));
} catch (error) {
console.error('Error fetching task options:', error);
res.status(500).json({ error: 'Failed to fetch task options' });
}
});
// Endpoint untuk menambah Activity baru
app.post('/api/task-options', async (req, res) => {
try {
const { name } = req.body;
if (!name || !name.trim()) {
return res.status(400).json({ error: 'Name is required' });
}
await pool.query('INSERT INTO activity (name) VALUES (?)', [name.trim()]);
res.json({ message: 'Activity added successfully' });
} catch (error) {
console.error('Error adding Activity:', error);
res.status(500).json({ error: 'Failed to add Activity' });
}
});
// Endpoint untuk mendapatkan daftar task lengkap
app.get('/api/tasks', async (req, res) => {
try {
const [rows] = await pool.query(`
SELECT
t.id, t.content, t.detail, t.status,
p.name AS pic,
t.timestamp_todo, t.timestamp_progress, t.timestamp_done,
t.timestamp_archived
FROM task t
JOIN pic p ON t.pic_id = p.id
ORDER BY t.id
`);
const tasks = rows.map((row) => ({
id: row.id.toString(),
content: row.content,
pic: row.pic,
detail: row.detail,
status: row.status,
timestamps: {
todo: row.timestamp_todo ? row.timestamp_todo.toISOString() : null,
progress: row.timestamp_progress ? row.timestamp_progress.toISOString() :
null,
done: row.timestamp_done ? row.timestamp_done.toISOString() : null,
archived: row.timestamp_archived ? row.timestamp_archived.toISOString() :
null,
},
}));
res.json(tasks);
} catch (error) {
console.error('Error fetching tasks:', error);
res.status(500).json({ error: 'Failed to fetch tasks' });
}
});
// Endpoint untuk menambah task baru
app.post('/api/tasks', async (req, res) => {
try {
const { content, pic, detail, status, timestamps } = req.body;
if (!content || !pic || !status) {
return res.status(400).json({ error: 'content, pic, and status are
required' });
}
// Cari pic_id dari nama PIC
const [picRows] = await pool.query('SELECT id FROM pic WHERE name = ?', [pic]);
if (picRows.length === 0) {
return res.status(400).json({ error: 'PIC not found' });
}
const pic_id = picRows[0].id;
// Insert task
const [result] = await pool.query(
`INSERT INTO task
(content, pic_id, detail, status, timestamp_todo, timestamp_progress,
timestamp_done, timestamp_archived)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[
content,
pic_id,
detail || '',
status,
timestamps?.todo ? new Date(timestamps.todo) : null,
timestamps?.progress ? new Date(timestamps.progress) : null,
timestamps?.done ? new Date(timestamps.done) : null,
timestamps?.archived ? new Date(timestamps.archived) : null,
]
);
res.json({ message: 'Task added successfully', id: result.insertId });
} catch (error) {
console.error('Error adding task:', error);
res.status(500).json({ error: 'Failed to add task' });
}
});
// Endpoint untuk update task status dan timestamps
app.post('/api/tasks/update', async (req, res) => {
try {
const { id, status, timestamps } = req.body;
if (!id || !status || !timestamps) {
return res.status(400).json({ error: 'id, status, and timestamps are
required' });
}
// Update task
await pool.query(
`UPDATE task SET
status = ?,
timestamp_todo = ?,
timestamp_progress = ?,
timestamp_done = ?,
timestamp_archived = ?
WHERE id = ?`,
[
status,
timestamps.todo ? new Date(timestamps.todo) : null,
timestamps.progress ? new Date(timestamps.progress) : null,
timestamps.done ? new Date(timestamps.done) : null,
timestamps.archived ? new Date(timestamps.archived) : null,
id,
]
);
res.json({ message: 'Task updated successfully' });
} catch (error) {
console.error('Error updating task:', error);
res.status(500).json({ error: 'Failed to update task' });
}
});
app.listen(port, () => {
console.log(`Kanban backend listening at http://localhost:${port}`);
});