Add roadmap management feature with database schema and user management
- Implemented roadmap.php for displaying and managing roadmap items with filters for quarter and status. - Created schema.sql to define the database structure for users, invites, daily plans, tasks, brainstorm sessions, brainstorm cards, roadmap items, and integrations. - Developed users.php for admin panel to manage team members and invitations, including functionality to create and revoke invites.
This commit is contained in:
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
/**
|
||||
* Fociz Integraties Hub (Outlook, Teams, Jira)
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
$db = get_db_connection();
|
||||
$userId = $currentUser['id'];
|
||||
|
||||
// Formulierverwerking voor integratie instellingen
|
||||
$message = null;
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$provider = $_POST['provider'] ?? '';
|
||||
$isDemo = isset($_POST['is_demo_mode']) ? 1 : 0;
|
||||
$settings = json_encode([
|
||||
'client_id' => $_POST['client_id'] ?? '',
|
||||
'client_secret' => $_POST['client_secret'] ?? '',
|
||||
'tenant_id' => $_POST['tenant_id'] ?? '',
|
||||
'jira_domain' => $_POST['jira_domain'] ?? '',
|
||||
'jira_email' => $_POST['jira_email'] ?? '',
|
||||
'jira_api_token' => $_POST['jira_api_token'] ?? '',
|
||||
]);
|
||||
|
||||
if (in_array($provider, ['OUTLOOK', 'TEAMS', 'JIRA'])) {
|
||||
$stmt = $db->prepare("
|
||||
INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, settings, last_sync_at)
|
||||
VALUES (?, ?, 1, ?, ?, NOW())
|
||||
ON DUPLICATE KEY UPDATE is_demo_mode = VALUES(is_demo_mode), settings = VALUES(settings), last_sync_at = NOW()
|
||||
");
|
||||
$stmt->execute([$userId, $provider, $isDemo, $settings]);
|
||||
$message = "Instellingen voor {$provider} succesvol opgeslagen.";
|
||||
}
|
||||
}
|
||||
|
||||
// Haal huidige configuraties op
|
||||
$stmtConfigs = $db->prepare("SELECT * FROM integrations WHERE user_id = ?");
|
||||
$stmtConfigs->execute([$userId]);
|
||||
$configsRaw = $stmtConfigs->fetchAll();
|
||||
$configs = [];
|
||||
foreach ($configsRaw as $c) {
|
||||
$configs[$c['provider']] = $c;
|
||||
$configs[$c['provider']]['settings_parsed'] = json_decode($c['settings'] ?? '{}', true) ?: [];
|
||||
}
|
||||
|
||||
// Jira demo issues
|
||||
$jiraIssues = [
|
||||
[
|
||||
'key' => 'FOC-101',
|
||||
'summary' => 'Tweestapsverificatie (2FA TOTP) flow implementeren',
|
||||
'status' => 'In Progress',
|
||||
'priority' => 'High',
|
||||
'epic' => 'Security & Access',
|
||||
],
|
||||
[
|
||||
'key' => 'FOC-102',
|
||||
'summary' => 'Interactief whiteboard canvas voor brainstormsessies',
|
||||
'status' => 'To Do',
|
||||
'priority' => 'High',
|
||||
'epic' => 'Brainstorming Module',
|
||||
],
|
||||
[
|
||||
'key' => 'FOC-103',
|
||||
'summary' => 'Koppeling met Microsoft Outlook Calendar & Teams Graph API',
|
||||
'status' => 'In Review',
|
||||
'priority' => 'Medium',
|
||||
'epic' => 'Integrations Hub',
|
||||
],
|
||||
[
|
||||
'key' => 'FOC-104',
|
||||
'summary' => 'Roadmap kwartaalweergave en voortgangsindicatoren',
|
||||
'status' => 'To Do',
|
||||
'priority' => 'Medium',
|
||||
'epic' => 'Roadmap Module',
|
||||
]
|
||||
];
|
||||
?>
|
||||
|
||||
<div class="space-y-6">
|
||||
<!-- Header -->
|
||||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl">
|
||||
<div class="flex items-center space-x-2 text-blue-400 text-xs font-semibold uppercase tracking-wider mb-1">
|
||||
<i data-lucide="layers" class="w-4 h-4"></i>
|
||||
<span>Connectiviteit & Synchronisatie</span>
|
||||
</div>
|
||||
<h1 class="text-2xl sm:text-3xl font-black text-white tracking-tight">
|
||||
Integraties Hub
|
||||
</h1>
|
||||
<p class="text-slate-400 text-xs sm:text-sm mt-1">
|
||||
Beheer uw koppelingen met Microsoft Outlook (agenda & taken), Microsoft Teams (meetings) en Atlassian Jira (issues & roadmap).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="p-4 rounded-xl bg-emerald-500/10 border border-emerald-500/30 text-emerald-400 text-xs font-semibold flex items-center space-x-2">
|
||||
<i data-lucide="check-circle" class="w-4 h-4"></i>
|
||||
<span><?= htmlspecialchars($message) ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Integratie Cards Grid -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
|
||||
<!-- 1. OUTLOOK -->
|
||||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="w-10 h-10 rounded-xl bg-blue-500/10 border border-blue-500/30 text-blue-400 flex items-center justify-center font-bold">
|
||||
<i data-lucide="calendar" class="w-5 h-5"></i>
|
||||
</div>
|
||||
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-medium flex items-center space-x-1">
|
||||
<i data-lucide="check-circle" class="w-3 h-3"></i>
|
||||
<span>Actief</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 class="text-base font-bold text-white mb-1">Microsoft Outlook</h3>
|
||||
<p class="text-xs text-slate-400 mb-4">
|
||||
Synchroniseert uw agenda-afspraken en e-mails automatisch naar uw dagplanning en time-blocks.
|
||||
</p>
|
||||
|
||||
<div class="bg-slate-950/60 rounded-xl p-3 border border-slate-800/80 text-xs space-y-2 mb-4">
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Status:</span>
|
||||
<span class="text-emerald-400 font-semibold">Gekoppeld</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Sync frequentie:</span>
|
||||
<span class="text-slate-200">Elke 15 min</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Instellingen formulier -->
|
||||
<form method="POST" action="/integrations.php" class="pt-3 border-t border-slate-800 space-y-3">
|
||||
<input type="hidden" name="provider" value="OUTLOOK">
|
||||
|
||||
<label class="flex items-center space-x-2 text-xs text-slate-300">
|
||||
<input type="checkbox" name="is_demo_mode" value="1" <?= empty($configs['OUTLOOK']) || !empty($configs['OUTLOOK']['is_demo_mode']) ? 'checked' : '' ?> class="rounded bg-slate-900 border-slate-700 text-emerald-500">
|
||||
<span>Gebruik interactieve Sandbox data</span>
|
||||
</label>
|
||||
|
||||
<button type="submit" class="w-full py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold transition">
|
||||
Instellingen Bijwerken
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 2. MICROSOFT TEAMS -->
|
||||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="w-10 h-10 rounded-xl bg-indigo-500/10 border border-indigo-500/30 text-indigo-400 flex items-center justify-center font-bold">
|
||||
<i data-lucide="video" class="w-5 h-5"></i>
|
||||
</div>
|
||||
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-medium flex items-center space-x-1">
|
||||
<i data-lucide="check-circle" class="w-3 h-3"></i>
|
||||
<span>Actief</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 class="text-base font-bold text-white mb-1">Microsoft Teams</h3>
|
||||
<p class="text-xs text-slate-400 mb-4">
|
||||
Toont vandaag geplande Teams meetings met directe 'Deelnemen' links en kanaalupdates.
|
||||
</p>
|
||||
|
||||
<div class="bg-slate-950/60 rounded-xl p-3 border border-slate-800/80 text-xs space-y-2 mb-4">
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Direct Deelnemen:</span>
|
||||
<span class="text-emerald-400 font-semibold">Ondersteund</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Meldingen:</span>
|
||||
<span class="text-slate-200">Ingeschakeld</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="/integrations.php" class="pt-3 border-t border-slate-800 space-y-3">
|
||||
<input type="hidden" name="provider" value="TEAMS">
|
||||
|
||||
<label class="flex items-center space-x-2 text-xs text-slate-300">
|
||||
<input type="checkbox" name="is_demo_mode" value="1" <?= empty($configs['TEAMS']) || !empty($configs['TEAMS']['is_demo_mode']) ? 'checked' : '' ?> class="rounded bg-slate-900 border-slate-700 text-emerald-500">
|
||||
<span>Gebruik interactieve Sandbox data</span>
|
||||
</label>
|
||||
|
||||
<button type="submit" class="w-full py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold transition">
|
||||
Instellingen Bijwerken
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- 3. ATLASSIAN JIRA -->
|
||||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-5 shadow-xl flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="w-10 h-10 rounded-xl bg-sky-500/10 border border-sky-500/30 text-sky-400 flex items-center justify-center font-bold">
|
||||
<i data-lucide="trello" class="w-5 h-5"></i>
|
||||
</div>
|
||||
<span class="px-2.5 py-0.5 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-medium flex items-center space-x-1">
|
||||
<i data-lucide="check-circle" class="w-3 h-3"></i>
|
||||
<span>Actief</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 class="text-base font-bold text-white mb-1">Atlassian Jira</h3>
|
||||
<p class="text-xs text-slate-400 mb-4">
|
||||
Koppelt Jira Epics en Issues direct aan uw roadmap items en takenlijst.
|
||||
</p>
|
||||
|
||||
<div class="bg-slate-950/60 rounded-xl p-3 border border-slate-800/80 text-xs space-y-2 mb-4">
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Two-way Status Sync:</span>
|
||||
<span class="text-emerald-400 font-semibold">Ondersteund</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between text-slate-400">
|
||||
<span>Roadmap Linkage:</span>
|
||||
<span class="text-slate-200">Actief</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST" action="/integrations.php" class="pt-3 border-t border-slate-800 space-y-2">
|
||||
<input type="hidden" name="provider" value="JIRA">
|
||||
|
||||
<div>
|
||||
<label class="block text-[10px] text-slate-400 mb-0.5">Jira Cloud Domein</label>
|
||||
<input type="text" name="jira_domain" placeholder="uwbedrijf.atlassian.net" value="<?= htmlspecialchars($configs['JIRA']['settings_parsed']['jira_domain'] ?? '') ?>" class="w-full bg-slate-950 border border-slate-800 rounded-lg px-2.5 py-1 text-xs text-white placeholder-slate-600 focus:outline-none">
|
||||
</div>
|
||||
|
||||
<label class="flex items-center space-x-2 text-xs text-slate-300 pt-1">
|
||||
<input type="checkbox" name="is_demo_mode" value="1" <?= empty($configs['JIRA']) || !empty($configs['JIRA']['is_demo_mode']) ? 'checked' : '' ?> class="rounded bg-slate-900 border-slate-700 text-emerald-500">
|
||||
<span>Gebruik interactieve Sandbox data</span>
|
||||
</label>
|
||||
|
||||
<button type="submit" class="w-full py-2 rounded-xl bg-slate-800 hover:bg-slate-700 text-white text-xs font-semibold transition">
|
||||
Jira Opslaan
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gesynchroniseerde Jira Issues & 1-Click Import naar Dagplanning -->
|
||||
<div class="bg-slate-900/80 border border-slate-800 rounded-2xl p-6 shadow-xl space-y-4">
|
||||
<div class="flex items-center justify-between pb-3 border-b border-slate-800">
|
||||
<div class="flex items-center space-x-2">
|
||||
<i data-lucide="check-square" class="w-5 h-5 text-sky-400"></i>
|
||||
<h3 class="text-sm font-bold text-white uppercase tracking-wider">
|
||||
Jira Issues Toegewezen aan U
|
||||
</h3>
|
||||
</div>
|
||||
<span class="text-xs text-slate-400 font-mono"><?= count($jiraIssues) ?> issues</span>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<?php foreach ($jiraIssues as $issue): ?>
|
||||
<div class="bg-slate-950/60 border border-slate-800 hover:border-slate-700 rounded-xl p-4 flex flex-col justify-between transition">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="font-mono text-xs font-bold text-sky-400 bg-sky-500/10 border border-sky-500/20 px-2 py-0.5 rounded">
|
||||
<?= htmlspecialchars($issue['key']) ?>
|
||||
</span>
|
||||
<span class="text-[10px] font-semibold px-2 py-0.5 rounded bg-slate-800 text-slate-300">
|
||||
<?= htmlspecialchars($issue['status']) ?>
|
||||
</span>
|
||||
</div>
|
||||
<h4 class="text-xs font-bold text-white leading-snug">
|
||||
<?= htmlspecialchars($issue['summary']) ?>
|
||||
</h4>
|
||||
<span class="text-[10px] text-slate-500 mt-1 block">Epic: <?= htmlspecialchars($issue['epic']) ?></span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 pt-3 border-t border-slate-800/80 flex items-center justify-between">
|
||||
<span class="text-[10px] font-bold text-amber-400"><?= htmlspecialchars($issue['priority']) ?> Priority</span>
|
||||
<button onclick="importJiraToTasks('<?= htmlspecialchars(addslashes($issue['summary'])) ?>', '<?= htmlspecialchars($issue['key']) ?>')" class="flex items-center space-x-1 text-[11px] font-semibold text-emerald-400 hover:text-emerald-300 bg-emerald-500/10 hover:bg-emerald-500/20 border border-emerald-500/20 px-2.5 py-1 rounded-lg transition">
|
||||
<i data-lucide="plus" class="w-3 h-3"></i>
|
||||
<span>Plan als Dagtaak</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function importJiraToTasks(title, jiraKey) {
|
||||
const res = await fetch('/api/planner.php?action=add_task', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
title: `[${jiraKey}] ${title}`,
|
||||
priority: 'P1',
|
||||
date: '<?= date('Y-m-d') ?>'
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
alert(`Jira issue ${jiraKey} is toegevoegd aan uw dagplanning!`);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
Reference in New Issue
Block a user