Jobangebote: Favoriten (Stern) und Startseiten-Sektion ganz oben
Stellen lassen sich per Stern merken — unabhängig vom Status (offen / uebernommen / abgelehnt). Neue Spalte jobangebote.favorit (PRAGMA-Migration), JSON-Toggle-Endpunkt /jobangebote/:id/favorit, Stern-Button auf den Karten sowie eine "Gemerkte Stellen"-Sektion ganz oben auf der Startseite. Toggle laeuft per fetch mit optimistischem UI; beim Entfernen auf der Startseite verschwindet die Zeile sofort. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1438,6 +1438,16 @@ async function initializeDatabase() {
|
||||
await exec('CREATE INDEX IF NOT EXISTS idx_jobangebote_url_norm ON jobangebote(url_norm)');
|
||||
await exec('CREATE INDEX IF NOT EXISTS idx_jobangebote_firma_slug ON jobangebote(firma_slug)');
|
||||
|
||||
// Favoriten-Merkmal (Stern): 0 = nicht gemerkt, 1 = favorisiert. Favoriten
|
||||
// erscheinen oben auf der Startseite — unabhängig vom Status (offen /
|
||||
// uebernommen / abgelehnt). Spalte wird nur bei Bedarf angelegt.
|
||||
{
|
||||
const jobSpalten = await dbAll('PRAGMA table_info(jobangebote)');
|
||||
if (!jobSpalten.some((s) => s.name === 'favorit')) {
|
||||
await exec('ALTER TABLE jobangebote ADD COLUMN favorit INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
}
|
||||
|
||||
// Blacklist of job offers that must never (re)appear in the list (per user).
|
||||
await exec(`
|
||||
CREATE TABLE IF NOT EXISTS jobangebote_blacklist (
|
||||
@@ -1744,6 +1754,17 @@ initializeDatabase().then(async () => {
|
||||
};
|
||||
}
|
||||
|
||||
// Gemerkte Stellen (Favoriten) für die Sektion ganz oben auf der
|
||||
// Startseite — unabhängig vom Angebot-Status (offen/uebernommen/…).
|
||||
const favoriten = await dbAll(
|
||||
`SELECT j.id, j.firma, j.stelle, j.ort, j.status, j.quelle_url,
|
||||
j.verknuepfte_bewerbung_id, j.gehalt, j.favorit
|
||||
FROM jobangebote j
|
||||
WHERE j.user_id = ? AND j.favorit = 1
|
||||
ORDER BY j.updated_at DESC, j.id DESC`,
|
||||
[U]
|
||||
);
|
||||
|
||||
res.render('index', {
|
||||
applications,
|
||||
statistics: {
|
||||
@@ -1760,7 +1781,8 @@ initializeDatabase().then(async () => {
|
||||
artOptions: ART_OPTIONS,
|
||||
statusOptions: STATUS_OPTIONS,
|
||||
labelOptions: LABEL_OPTIONS,
|
||||
setupWizard
|
||||
setupWizard,
|
||||
favoriten
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
@@ -3602,6 +3624,22 @@ initializeDatabase().then(async () => {
|
||||
}
|
||||
});
|
||||
|
||||
// Favorit umschalten (Stern). JSON-Antwort, damit der Client den Stern
|
||||
// sofort umschalten kann, ohne die Seite neu zu laden. Favoriten sind
|
||||
// unabhängig vom Angebot-Status sichtbar — auch „uebernommen“ bleibt merkbar.
|
||||
app.post('/jobangebote/:id/favorit', async (req, res) => {
|
||||
try {
|
||||
const angebot = await dbGet('SELECT favorit FROM jobangebote WHERE id = ? AND user_id = ?', [req.params.id, uid()]);
|
||||
if (!angebot) return res.status(404).json({ error: 'Jobangebot nicht gefunden' });
|
||||
const neu = angebot.favorit ? 0 : 1;
|
||||
await dbRun('UPDATE jobangebote SET favorit = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND user_id = ?', [neu, req.params.id, uid()]);
|
||||
res.json({ success: true, favorit: neu });
|
||||
} catch (error) {
|
||||
console.error('Error toggling favorite:', error);
|
||||
res.status(500).json({ error: 'Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
// Blacklist management page — see what is blocked and remove entries.
|
||||
app.get('/blacklist', async (req, res) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user