Compare commits
2 Commits
bc6fdd249e
...
d870e643dc
| Author | SHA1 | Date | |
|---|---|---|---|
| d870e643dc | |||
| d15303ff6c |
+139
-25
@@ -1756,9 +1756,9 @@ if ($isAjaxRequest) {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Modal: Jira Ticket Inplannen (met tijdsuggestie) -->
|
||||
<!-- Modal: Jira Ticket Inplannen (met datum, tijdsuggestie & aanpasbare titel) -->
|
||||
<div id="jiraPlanModal" class="fixed inset-0 z-50 bg-slate-950/70 backdrop-blur-sm hidden items-center justify-center p-4">
|
||||
<div class="fociz-card p-6 w-full max-w-md shadow-2xl space-y-4">
|
||||
<div class="fociz-card p-6 w-full max-w-lg max-h-[90vh] overflow-y-auto shadow-2xl space-y-4">
|
||||
<div class="flex items-center justify-between pb-3 border-b border-slate-100 dark:border-slate-800/80">
|
||||
<div class="flex items-center space-x-2.5">
|
||||
<div class="w-8 h-8 rounded-xl bg-sky-50 dark:bg-sky-500/10 border border-sky-200 dark:border-sky-500/20 text-sky-600 dark:text-sky-400 flex items-center justify-center">
|
||||
@@ -1769,29 +1769,78 @@ if ($isAjaxRequest) {
|
||||
<p class="text-[10px] text-slate-500 dark:text-slate-400" id="jiraPlanModalKey">—</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="closeJiraPlanModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
|
||||
<button type="button" onclick="closeJiraPlanModal()" class="p-1.5 text-slate-400 hover:text-slate-600 dark:hover:text-slate-200 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer">
|
||||
<i data-lucide="x" class="w-4 h-4"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Ticket samenvatting -->
|
||||
<div class="bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-200 dark:border-slate-800 p-3">
|
||||
<p class="text-xs font-semibold text-slate-800 dark:text-slate-200 leading-snug" id="jiraPlanModalSummary">—</p>
|
||||
<div class="flex items-center space-x-2 mt-1.5">
|
||||
<span class="text-[10px] text-slate-500" id="jiraPlanModalStatus">—</span>
|
||||
<span class="text-slate-300 dark:text-slate-600">•</span>
|
||||
<span class="text-[10px] text-slate-500" id="jiraPlanModalPriority">—</span>
|
||||
<span id="jiraPlanModalSpBadge" class="hidden px-1.5 py-0.5 rounded bg-violet-50 dark:bg-violet-500/10 border border-violet-200 dark:border-violet-500/20 text-violet-700 dark:text-violet-400 font-mono text-[9px] font-bold"></span>
|
||||
<!-- Ticket samenvatting & Uitklapbare beschrijving -->
|
||||
<div class="bg-slate-50 dark:bg-slate-900/50 rounded-xl border border-slate-200 dark:border-slate-800 p-3.5 space-y-2.5">
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-slate-800 dark:text-slate-200 leading-snug" id="jiraPlanModalSummary">—</p>
|
||||
<div class="flex items-center space-x-2 mt-1.5">
|
||||
<span class="text-[10px] text-slate-500" id="jiraPlanModalStatus">—</span>
|
||||
<span class="text-slate-300 dark:text-slate-600">•</span>
|
||||
<span class="text-[10px] text-slate-500" id="jiraPlanModalPriority">—</span>
|
||||
<span id="jiraPlanModalSpBadge" class="hidden px-1.5 py-0.5 rounded bg-violet-50 dark:bg-violet-500/10 border border-violet-200 dark:border-violet-500/20 text-violet-700 dark:text-violet-400 font-mono text-[9px] font-bold"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Uitklapknop voor inhoud ticket (10 regels verticaal scrollbaar) -->
|
||||
<div class="pt-2 border-t border-slate-200/70 dark:border-slate-800/70">
|
||||
<button type="button" onclick="toggleJiraPlanDescription()" class="w-full flex items-center justify-between text-[11px] font-semibold text-indigo-600 dark:text-indigo-400 hover:text-indigo-700 dark:hover:text-indigo-300 transition cursor-pointer group">
|
||||
<span class="flex items-center space-x-1.5">
|
||||
<i data-lucide="file-text" class="w-3.5 h-3.5"></i>
|
||||
<span id="jiraPlanDescToggleLabel">Inhoud van het item bekijken</span>
|
||||
</span>
|
||||
<i data-lucide="chevron-down" id="jiraPlanDescChevron" class="w-3.5 h-3.5 transition-transform duration-200 group-hover:translate-y-0.5"></i>
|
||||
</button>
|
||||
<div id="jiraPlanDescWrapper" class="hidden mt-2.5">
|
||||
<div id="jiraPlanModalDescription" class="max-h-48 overflow-y-auto p-3 bg-white dark:bg-[#0c0f17] rounded-xl border border-slate-200 dark:border-slate-800 text-xs text-slate-700 dark:text-slate-300 whitespace-pre-wrap font-sans leading-relaxed"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tijdsuggestie -->
|
||||
<div class="space-y-3">
|
||||
<!-- Formulier velden -->
|
||||
<div class="space-y-3.5">
|
||||
<!-- Titel voor de agenda / dagtaak -->
|
||||
<div>
|
||||
<label class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">Starttijd (suggestie)</label>
|
||||
<input type="time" id="jiraPlanStartTime" class="w-full bg-white dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||
<p class="text-[10px] text-slate-400 mt-1">Laat leeg voor handmatig inplannen op de tijdlijn</p>
|
||||
<label for="jiraPlanCustomTitle" class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">
|
||||
Hoe het in de agenda komt (Titel)
|
||||
</label>
|
||||
<input type="text" id="jiraPlanCustomTitle" class="w-full bg-white dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500 placeholder-slate-400" placeholder="Oppakken Jira item ...">
|
||||
</div>
|
||||
|
||||
<!-- Datum & Starttijd -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label for="jiraPlanDate" class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">
|
||||
Datum
|
||||
</label>
|
||||
<input type="date" id="jiraPlanDate" class="w-full bg-white dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="jiraPlanStartTime" class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">
|
||||
Starttijd
|
||||
</label>
|
||||
<div class="relative flex items-center">
|
||||
<input type="time" id="jiraPlanStartTime" class="w-full bg-white dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 rounded-xl pl-3 pr-8 py-2 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||
<button type="button" onclick="clearJiraPlanStartTime()" title="Starttijd wissen" class="absolute right-2 p-1 text-slate-400 hover:text-rose-500 dark:hover:text-rose-400 rounded transition cursor-pointer">
|
||||
<i data-lucide="x" class="w-3.5 h-3.5"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p class="text-[10px] text-slate-400 mt-1 flex items-center justify-between">
|
||||
<span>Laat leeg voor handmatig inplannen</span>
|
||||
<button type="button" onclick="clearJiraPlanStartTime()" class="text-indigo-600 dark:text-indigo-400 hover:underline cursor-pointer flex items-center space-x-0.5" title="Starttijd wissen">
|
||||
<i data-lucide="x" class="w-2.5 h-2.5"></i>
|
||||
<span>Wissen</span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Duur -->
|
||||
<div>
|
||||
<label class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">Duur</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
@@ -1802,8 +1851,10 @@ if ($isAjaxRequest) {
|
||||
</div>
|
||||
<input type="hidden" id="jiraPlanDuration" value="15">
|
||||
</div>
|
||||
|
||||
<!-- Prioriteit -->
|
||||
<div>
|
||||
<label class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">Prioriteit</label>
|
||||
<label for="jiraPlanPriority" class="block text-[11px] font-bold text-slate-700 dark:text-slate-300 mb-1.5">Prioriteit</label>
|
||||
<select id="jiraPlanPriority" class="w-full bg-white dark:bg-[#0c0f17] border border-slate-200 dark:border-slate-800 rounded-xl px-3 py-2 text-sm text-slate-900 dark:text-white focus:outline-none focus:ring-1 focus:ring-indigo-500">
|
||||
<option value="P1">P1 — Urgent</option>
|
||||
<option value="P2">P2 — Hoog</option>
|
||||
@@ -1812,7 +1863,7 @@ if ($isAjaxRequest) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-3 pt-1">
|
||||
<div class="flex space-x-3 pt-2 border-t border-slate-100 dark:border-slate-800/80">
|
||||
<button type="button" onclick="closeJiraPlanModal()" class="flex-1 px-4 py-2.5 rounded-xl bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-300 font-semibold text-sm transition cursor-pointer">
|
||||
Annuleren
|
||||
</button>
|
||||
@@ -2970,6 +3021,9 @@ const plannerTicketStore = new Map();
|
||||
plannerJiraAll.forEach(iss => {
|
||||
if (iss && iss.key) plannerTicketStore.set(iss.key, iss);
|
||||
});
|
||||
plannerJiraAssigned.forEach(iss => {
|
||||
if (iss && iss.key && !plannerTicketStore.has(iss.key)) plannerTicketStore.set(iss.key, iss);
|
||||
});
|
||||
|
||||
let activePlannerJiraQueue = ''; // '': Alle, 'my': Mijn, 'DX': DX Queue, 'SD': SD Queue
|
||||
|
||||
@@ -3191,9 +3245,35 @@ function openJiraPlanFromDetail() {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Jira Plan Modal (met tijdsuggestie) ---
|
||||
// --- Jira Plan Modal (met datum, tijdsuggestie & aanpasbare titel) ---
|
||||
let _jiraPlanCurrentIssue = null;
|
||||
|
||||
function clearJiraPlanStartTime() {
|
||||
const input = document.getElementById('jiraPlanStartTime');
|
||||
if (input) {
|
||||
input.value = '';
|
||||
input.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleJiraPlanDescription() {
|
||||
const wrapper = document.getElementById('jiraPlanDescWrapper');
|
||||
const chevron = document.getElementById('jiraPlanDescChevron');
|
||||
const label = document.getElementById('jiraPlanDescToggleLabel');
|
||||
if (!wrapper) return;
|
||||
const isHidden = wrapper.classList.contains('hidden');
|
||||
if (isHidden) {
|
||||
wrapper.classList.remove('hidden');
|
||||
if (chevron) chevron.classList.add('rotate-180');
|
||||
if (label) label.textContent = 'Inhoud inklappen';
|
||||
} else {
|
||||
wrapper.classList.add('hidden');
|
||||
if (chevron) chevron.classList.remove('rotate-180');
|
||||
if (label) label.textContent = 'Inhoud van het item bekijken';
|
||||
}
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
|
||||
function openJiraPlanModal(issueKey) {
|
||||
const issue = plannerTicketStore.get(issueKey);
|
||||
if (!issue) return;
|
||||
@@ -3214,6 +3294,32 @@ function openJiraPlanModal(issueKey) {
|
||||
spBadge.classList.add('hidden');
|
||||
}
|
||||
|
||||
// Vul beschrijving (10 regels scrollbaar venstertje) en reset naar ingeklapt
|
||||
const descEl = document.getElementById('jiraPlanModalDescription');
|
||||
if (descEl) {
|
||||
const descText = (issue.description && issue.description.trim()) ? issue.description.trim() : 'Geen beschrijving beschikbaar voor dit ticket.';
|
||||
descEl.textContent = descText;
|
||||
}
|
||||
const descWrapper = document.getElementById('jiraPlanDescWrapper');
|
||||
const descChevron = document.getElementById('jiraPlanDescChevron');
|
||||
const descLabel = document.getElementById('jiraPlanDescToggleLabel');
|
||||
if (descWrapper) descWrapper.classList.add('hidden');
|
||||
if (descChevron) descChevron.classList.remove('rotate-180');
|
||||
if (descLabel) descLabel.textContent = 'Inhoud van het item bekijken';
|
||||
|
||||
// Titel hoe het in de agenda komt: standaard "Oppakken Jira item <issue.key>"
|
||||
const titleInput = document.getElementById('jiraPlanCustomTitle');
|
||||
if (titleInput) {
|
||||
titleInput.value = `Oppakken Jira item ${issue.key}`;
|
||||
}
|
||||
|
||||
// Datum: standaard de actieve planner datum of vandaag
|
||||
const dateInput = document.getElementById('jiraPlanDate');
|
||||
const targetDate = (typeof activePlannerDate !== 'undefined' && activePlannerDate) ? activePlannerDate : new Date().toISOString().slice(0, 10);
|
||||
if (dateInput) {
|
||||
dateInput.value = targetDate;
|
||||
}
|
||||
|
||||
// Standaard duur: 15 min (of op basis van SP: 1 SP = 30 min)
|
||||
let defaultDuration = 15;
|
||||
if (issue.story_points && issue.story_points > 0) {
|
||||
@@ -3233,9 +3339,8 @@ function openJiraPlanModal(issueKey) {
|
||||
|
||||
// Slimme starttijd: stel het volgende vrije kwartier voor
|
||||
const now = new Date();
|
||||
const suggestTime = activePlannerDate === now.toISOString().slice(0,10)
|
||||
? suggestNextFreeSlot()
|
||||
: '09:00';
|
||||
const todayStr = now.toISOString().slice(0, 10);
|
||||
const suggestTime = targetDate === todayStr ? suggestNextFreeSlot() : '09:00';
|
||||
document.getElementById('jiraPlanStartTime').value = suggestTime;
|
||||
|
||||
const modal = document.getElementById('jiraPlanModal');
|
||||
@@ -3281,6 +3386,13 @@ async function submitJiraPlanModal() {
|
||||
if (!_jiraPlanCurrentIssue) return;
|
||||
const issue = _jiraPlanCurrentIssue;
|
||||
|
||||
const titleInput = document.getElementById('jiraPlanCustomTitle');
|
||||
const customTitle = titleInput ? titleInput.value.trim() : '';
|
||||
const finalTitle = customTitle || `Oppakken Jira item ${issue.key}`;
|
||||
|
||||
const dateInput = document.getElementById('jiraPlanDate');
|
||||
const planDate = (dateInput && dateInput.value) ? dateInput.value : ((typeof activePlannerDate !== 'undefined' && activePlannerDate) ? activePlannerDate : new Date().toISOString().slice(0, 10));
|
||||
|
||||
const duration = parseInt(document.getElementById('jiraPlanDuration').value, 10) || 15;
|
||||
const startTime = document.getElementById('jiraPlanStartTime').value.trim();
|
||||
const priority = document.getElementById('jiraPlanPriority').value;
|
||||
@@ -3292,13 +3404,13 @@ async function submitJiraPlanModal() {
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
title: `[${issue.key}] ${issue.summary || issue.key}`,
|
||||
title: finalTitle,
|
||||
priority: priority,
|
||||
source: 'JIRA',
|
||||
external_id: issue.key,
|
||||
external_url: issue.url || '',
|
||||
duration_minutes: duration,
|
||||
date: activePlannerDate
|
||||
date: planDate
|
||||
};
|
||||
if (startTime) {
|
||||
payload.time_block_start = startTime;
|
||||
@@ -3318,7 +3430,9 @@ async function submitJiraPlanModal() {
|
||||
if (data.success) {
|
||||
closeJiraPlanModal();
|
||||
showWidgetToast(`<strong>${escapeHtml(issue.key)}</strong> ingepland als dagtaak`, 'success');
|
||||
switchPlannerDate(activePlannerDate, null, false);
|
||||
if (typeof switchPlannerDate === 'function') {
|
||||
switchPlannerDate(planDate, null, false);
|
||||
}
|
||||
} else {
|
||||
alert(data.error || 'Kon ticket niet inplannen');
|
||||
btn.innerHTML = origHtml;
|
||||
|
||||
Reference in New Issue
Block a user