December 16th, 2025 V.8
This commit is contained in:
parent
08b009ac18
commit
17c88f822f
BIN
assets/pasted-20251217-025226-df69b749.png
Normal file
BIN
assets/pasted-20251217-025226-df69b749.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
449
hr_cases.php
449
hr_cases.php
@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) {
|
|||||||
}
|
}
|
||||||
require_once 'db/config.php';
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
// Mock data, mirroring the structure from the image and previous context
|
||||||
$cases = [
|
$cases = [
|
||||||
[
|
[
|
||||||
'id' => 'HR-2024-1847',
|
'id' => 'HR-2024-1847',
|
||||||
@ -14,9 +15,30 @@ $cases = [
|
|||||||
'severity' => 'high',
|
'severity' => 'high',
|
||||||
'department' => 'Engineering',
|
'department' => 'Engineering',
|
||||||
'assignedTo' => 'Jennifer Smith',
|
'assignedTo' => 'Jennifer Smith',
|
||||||
|
'assignedToRole' => 'Senior HR Manager',
|
||||||
|
'createdDate' => 'Dec 10, 2024',
|
||||||
'lastUpdate' => '2 hours ago',
|
'lastUpdate' => '2 hours ago',
|
||||||
'comments' => 8
|
'commentsCount' => 8,
|
||||||
|
'partiesInvolved' => 3,
|
||||||
|
'tags' => ['Conflict', 'Management', 'Urgent'],
|
||||||
|
'checklist' => [
|
||||||
|
['item' => 'Initial complaint documented', 'completed' => true],
|
||||||
|
['item' => 'Meeting with complainant scheduled', 'completed' => true],
|
||||||
|
['item' => 'Meeting with manager', 'completed' => false],
|
||||||
|
['item' => 'Resolution plan drafted', 'completed' => false],
|
||||||
|
],
|
||||||
|
'timeline' => [
|
||||||
|
['status' => 'Opened', 'details' => 'Case opened by HR department', 'date' => 'Dec 15, 2024 10:30 AM', 'completed' => true],
|
||||||
|
['status' => 'Investigation', 'details' => 'Initial interviews conducted', 'date' => 'Dec 18, 2024 2:45 PM', 'completed' => true],
|
||||||
|
['status' => 'Mediation', 'details' => 'Mediation session scheduled', 'date' => 'Dec 22, 2024 3:00 PM', 'completed' => false],
|
||||||
|
['status' => 'Resolution', 'details' => 'Awaiting final sign-off', 'date' => null, 'completed' => false],
|
||||||
|
],
|
||||||
|
'comments' => [
|
||||||
|
['author' => 'Jennifer Smith', 'role' => 'Senior HR Manager', 'time' => '2 hours ago', 'comment' => 'Just completed the meeting with David. He acknowledged the concerns and is willing to work on improving team communication. I\'ve scheduled a follow-up session for next week to review progress.'],
|
||||||
|
['author' => 'Michael Torres', 'role' => 'Team Lead', 'time' => '1 day ago', 'comment' => 'Thanks for the quick response on this. The team really appreciates that this is being taken seriously. I think we\'re seeing some improvement already in daily standups.'],
|
||||||
|
]
|
||||||
],
|
],
|
||||||
|
// Add other cases here...
|
||||||
[
|
[
|
||||||
'id' => 'HR-2024-1852',
|
'id' => 'HR-2024-1852',
|
||||||
'title' => 'Benefits Inquiry - Health Insurance',
|
'title' => 'Benefits Inquiry - Health Insurance',
|
||||||
@ -24,62 +46,36 @@ $cases = [
|
|||||||
'severity' => 'low',
|
'severity' => 'low',
|
||||||
'department' => 'Sales',
|
'department' => 'Sales',
|
||||||
'assignedTo' => 'Michael Torres',
|
'assignedTo' => 'Michael Torres',
|
||||||
|
'assignedToRole' => 'Senior HR Manager',
|
||||||
|
'createdDate' => 'Dec 12, 2024',
|
||||||
'lastUpdate' => '4 hours ago',
|
'lastUpdate' => '4 hours ago',
|
||||||
'comments' => 3
|
'commentsCount' => 3,
|
||||||
|
'partiesInvolved' => 1,
|
||||||
|
'tags' => ['Benefits', 'Inquiry'],
|
||||||
|
'checklist' => [],
|
||||||
|
'timeline' => [],
|
||||||
|
'comments' => []
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'id' => 'HR-2024-1855',
|
|
||||||
'title' => 'Remote Work Policy Question',
|
|
||||||
'status' => 'open',
|
|
||||||
'severity' => 'medium',
|
|
||||||
'department' => 'Product',
|
|
||||||
'assignedTo' => 'Sarah Anderson',
|
|
||||||
'lastUpdate' => '1 day ago',
|
|
||||||
'comments' => 5
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => 'HR-2024-1860',
|
|
||||||
'title' => 'Performance Review Discussion',
|
|
||||||
'status' => 'in-review',
|
|
||||||
'severity' => 'medium',
|
|
||||||
'department' => 'Marketing',
|
|
||||||
'assignedTo' => 'Jennifer Smith',
|
|
||||||
'lastUpdate' => '1 day ago',
|
|
||||||
'comments' => 12
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => 'HR-2024-1863',
|
|
||||||
'title' => 'Workplace Accommodation Request',
|
|
||||||
'status' => 'open',
|
|
||||||
'severity' => 'high',
|
|
||||||
'department' => 'Engineering',
|
|
||||||
'assignedTo' => 'Michael Torres',
|
|
||||||
'lastUpdate' => '2 days ago',
|
|
||||||
'comments' => 6
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$cases_json = json_encode($cases);
|
||||||
|
|
||||||
|
|
||||||
function get_severity_badge($severity) {
|
function get_severity_badge($severity) {
|
||||||
switch (strtolower($severity)) {
|
switch (strtolower($severity)) {
|
||||||
case 'high':
|
case 'high': return 'bg-red-100 text-red-800';
|
||||||
return 'bg-red-100 text-red-800';
|
case 'medium': return 'bg-yellow-100 text-yellow-800';
|
||||||
case 'medium':
|
case 'low': return 'bg-green-100 text-green-800';
|
||||||
return 'bg-yellow-100 text-yellow-800';
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
case 'low':
|
|
||||||
return 'bg-green-100 text-green-800';
|
|
||||||
default:
|
|
||||||
return 'bg-gray-100 text-gray-800';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_status_badge($status) {
|
function get_status_badge($status) {
|
||||||
switch (strtolower($status)) {
|
switch (strtolower($status)) {
|
||||||
case 'in-review':
|
case 'in-review': return 'bg-blue-100 text-blue-800';
|
||||||
return 'bg-blue-100 text-blue-800';
|
case 'open': return 'bg-gray-200 text-gray-800';
|
||||||
case 'open':
|
case 'closed': return 'bg-green-200 text-green-800';
|
||||||
return 'bg-gray-200 text-gray-800';
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
default:
|
|
||||||
return 'bg-gray-100 text-gray-800';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@ -90,130 +86,309 @@ function get_status_badge($status) {
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>HR Cases - FinMox</title>
|
<title>HR Cases - FinMox</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/lucide/4.2.0/lucide.min.css" rel="stylesheet">
|
||||||
|
<script src="https://unpkg.com/lucide@latest"></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100">
|
<body class="bg-gray-50">
|
||||||
<div class="flex h-screen bg-gray-200">
|
<div class="flex h-screen bg-white">
|
||||||
<?php include '_sidebar.php'; ?>
|
<?php include '_sidebar.php'; ?>
|
||||||
|
|
||||||
<div class="flex-1 flex flex-col overflow-hidden">
|
<div class="flex-1 flex flex-col overflow-hidden">
|
||||||
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-100">
|
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-50">
|
||||||
<div class="container mx-auto px-6 py-8">
|
<div class="container mx-auto px-6 py-8">
|
||||||
<div class="flex flex-col md:flex-row gap-6">
|
<div class="flex flex-col md:flex-row gap-8">
|
||||||
|
|
||||||
<!-- Left Column: Case Details -->
|
<!-- Left Column: Case Details -->
|
||||||
<div id="case-details-container" class="w-full md:w-1/2 lg:w-3/5">
|
<div id="case-details-column" class="w-full md:w-3/5 lg:w-3/5 order-2 md:order-1">
|
||||||
<div class="bg-white rounded-2xl shadow-sm p-6">
|
<div class="space-y-6">
|
||||||
<div class="flex justify-between items-start mb-4">
|
|
||||||
<div>
|
<!-- Case Header -->
|
||||||
<h2 id="case-details-title" class="text-2xl font-bold text-gray-800">Case Details</h2>
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
<p id="case-details-id" class="text-sm text-gray-500"></p>
|
<div class="flex justify-between items-center mb-4">
|
||||||
</div>
|
<h2 id="case-title" class="text-2xl font-bold text-gray-900">Manager Conflict Resolution</h2>
|
||||||
</div>
|
<div class="flex items-center gap-2">
|
||||||
<div class="flex flex-col md:flex-row h-full bg-[#fafafa] overflow-hidden">
|
<span id="case-severity-badge" class="text-sm font-semibold px-3 py-1 rounded-lg <?php echo get_severity_badge('high'); ?>">High Severity</span>
|
||||||
<div class="hidden md:block w-80 flex-shrink-0 overflow-y-auto p-6 border-r border-gray-200">
|
<select id="case-status-dropdown" class="border border-gray-300 rounded-lg text-sm font-medium focus:ring-blue-500 focus:border-blue-500">
|
||||||
<div class="placeholder bg-gray-200 animate-pulse rounded-lg p-6 h-full">
|
<option>Open</option>
|
||||||
<h3 class="font-bold text-lg text-gray-700 mb-4">Case Sidebar</h3>
|
<option selected>In Review</option>
|
||||||
|
<option>Closed</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 overflow-y-auto">
|
<p id="case-id-date" class="text-sm text-gray-500">Case #HR-2024-1847 • Created Dec 10, 2024</p>
|
||||||
<div class="max-w-5xl mx-auto px-4 md:px-6 py-4 md:py-8">
|
</div>
|
||||||
<div class="placeholder bg-gray-200 animate-pulse rounded-lg p-6 h-48 mb-6">
|
|
||||||
<h3 class="font-bold text-lg text-gray-700 mb-4">Case Header</h3>
|
<!-- Case Timeline -->
|
||||||
</div>
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
|
<h3 class="text-xl font-bold text-gray-900 mb-6">Case Timeline</h3>
|
||||||
<div class="placeholder bg-gray-200 animate-pulse rounded-lg p-6 h-96">
|
<div id="case-timeline-content" class="space-y-8 relative">
|
||||||
<h3 class="font-bold text-lg text-gray-700 mb-4">Timeline Section</h3>
|
<!-- Timeline items will be injected here -->
|
||||||
</div>
|
|
||||||
<div class="placeholder bg-gray-200 animate-pulse rounded-lg p-6 h-96">
|
|
||||||
<h3 class="font-bold text-lg text-gray-700 mb-4">Comments Section</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Comments Section -->
|
||||||
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
|
<h3 class="text-xl font-bold text-gray-900 mb-6">Comments & Discussion</h3>
|
||||||
|
<div id="case-comments-content" class="space-y-6">
|
||||||
|
<!-- Comments will be injected here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right Column: Cases List -->
|
<!-- Right Column: Contextual Sidebar & Case List -->
|
||||||
<div class="w-full md:w-1/2 lg:w-2/5">
|
<div class="w-full md:w-2/5 lg:w-2/5 order-1 md:order-2 space-y-6">
|
||||||
<div class="bg-white rounded-2xl shadow-sm border-gray-200 p-6">
|
|
||||||
<div class="flex items-center justify-between mb-4">
|
<!-- Contextual Details -->
|
||||||
<h3 class="flex items-center gap-2 font-bold text-xl text-gray-800">
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6 text-[#3A66FF]"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
<h3 class="text-lg font-bold text-gray-900 mb-6">Case Details</h3>
|
||||||
HR Cases This Week
|
<div class="space-y-5">
|
||||||
</h3>
|
<div>
|
||||||
<span class="bg-[#3A66FF]/10 text-[#3A66FF] hover:bg-[#3A66FF]/20 font-semibold text-sm px-2 py-1 rounded-md">
|
<p class="text-sm text-gray-500 mb-1">Assigned HR Rep</p>
|
||||||
<?php echo count($cases); ?> active
|
<div class="flex items-center gap-3">
|
||||||
</span>
|
<img id="case-assignee-img" src="https://i.pravatar.cc/40?u=jennifer" class="w-10 h-10 rounded-full" alt="Jennifer Smith">
|
||||||
|
<div>
|
||||||
|
<p id="case-assignee-name" class="font-semibold text-gray-800">Jennifer Smith</p>
|
||||||
|
<p id="case-assignee-role" class="text-sm text-gray-500">Senior HR Manager</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-500 mb-1">Department</p>
|
||||||
|
<p id="case-department" class="font-medium text-gray-800">Engineering</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-500 mb-1">Parties Involved</p>
|
||||||
|
<p id="case-parties" class="font-medium text-gray-800">3 employees</p>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div>
|
||||||
|
<p class="text-sm text-gray-500 mb-3">Tags</p>
|
||||||
|
<div id="case-tags" class="flex flex-wrap gap-2">
|
||||||
|
<span class="bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1 rounded-md">Conflict</span>
|
||||||
|
<span class="bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1 rounded-md">Management</span>
|
||||||
|
<span class="bg-red-100 text-red-800 text-sm font-medium px-3 py-1 rounded-md">Urgent</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Resolution Checklist -->
|
||||||
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
|
<div class="flex justify-between items-center mb-3">
|
||||||
|
<h3 class="text-lg font-bold text-gray-900">Resolution Checklist</h3>
|
||||||
|
<span id="checklist-progress-text" class="text-sm font-semibold text-gray-600">2/4</span>
|
||||||
|
</div>
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-2 mb-4">
|
||||||
|
<div id="checklist-progress-bar" class="bg-blue-600 h-2 rounded-full" style="width: 50%"></div>
|
||||||
|
</div>
|
||||||
|
<div id="checklist-items" class="space-y-3">
|
||||||
|
<!-- Checklist items will be injected here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Case List -->
|
||||||
|
<div class="bg-white border border-gray-200 rounded-2xl p-6">
|
||||||
|
<h3 class="text-lg font-bold text-gray-900 mb-4">All Cases</h3>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<?php foreach ($cases as $case): ?>
|
<?php foreach ($cases as $case):
|
||||||
<a href="#" class="case-link block p-4 bg-gray-50 rounded-xl border border-gray-200 hover:border-[#3A66FF]/30 transition-colors cursor-pointer" data-case-id="<?php echo htmlspecialchars($case['id']); ?>">
|
// Corrected escaping for the data-case-id attribute
|
||||||
<div class="flex items-start justify-between mb-3">
|
?>
|
||||||
<div class="flex-1">
|
<a href="#" class="case-link block p-4 bg-gray-50 rounded-xl border border-gray-200 hover:border-blue-500 transition-colors cursor-pointer" data-case-id="<?php echo htmlspecialchars($case['id']); ?>">
|
||||||
<div class="flex items-center gap-2 mb-1">
|
<div class="flex items-start justify-between">
|
||||||
<p class="font-bold text-gray-900 hover:text-[#3A66FF] transition-colors"><?php echo htmlspecialchars($case['title']); ?></p>
|
<p class="font-bold text-gray-800 group-hover:text-blue-600"><?php echo htmlspecialchars($case['title']); ?></p>
|
||||||
</div>
|
<span class="text-xs font-semibold px-2 py-1 rounded-full <?php echo get_severity_badge($case['severity']); ?>"><?php echo htmlspecialchars(ucfirst($case['severity'])); ?></span>
|
||||||
<p class="text-xs text-gray-500"><?php echo htmlspecialchars($case['id']); ?></p>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2">
|
|
||||||
<span class="text-xs font-semibold px-2 py-1 rounded-full <?php echo get_severity_badge($case['severity']); ?>"><?php echo htmlspecialchars(ucfirst($case['severity'])); ?></span>
|
|
||||||
<span class="text-xs font-semibold px-2 py-1 rounded-md <?php echo get_status_badge($case['status']); ?>"><?php echo htmlspecialchars(str_replace('-', ' ', ucfirst($case['status']))); ?></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center justify-between text-sm text-gray-600">
|
|
||||||
<p>Assigned to: <span class="font-semibold text-gray-800"><?php echo htmlspecialchars($case['assignedTo']); ?></span></p>
|
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<div class="flex items-center gap-1 text-gray-500">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
|
||||||
<span><?php echo htmlspecialchars($case['lastUpdate']); ?></span>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-1 text-gray-500">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-4 h-4"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
|
||||||
<span><?php echo htmlspecialchars($case['comments']); ?></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-1"><?php echo htmlspecialchars($case['id']); ?></p>
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const caseLinks = document.querySelectorAll('.case-link');
|
const casesData = <?php echo $cases_json; ?>;
|
||||||
const detailsContainer = document.getElementById('case-details-container');
|
const casesMap = new Map(casesData.map(c => [c.id, c]));
|
||||||
const detailsId = document.getElementById('case-details-id');
|
|
||||||
|
|
||||||
const casesData = <?php echo json_encode($cases); ?>;
|
const caseTitle = document.getElementById('case-title');
|
||||||
const casesMap = new Map(casesData.map(c => [c.id, c]));
|
const caseIdDate = document.getElementById('case-id-date');
|
||||||
|
const caseSeverityBadge = document.getElementById('case-severity-badge');
|
||||||
|
const caseStatusDropdown = document.getElementById('case-status-dropdown');
|
||||||
|
|
||||||
|
const caseAssigneeImg = document.getElementById('case-assignee-img');
|
||||||
|
const caseAssigneeName = document.getElementById('case-assignee-name');
|
||||||
|
const caseAssigneeRole = document.getElementById('case-assignee-role');
|
||||||
|
const caseDepartment = document.getElementById('case-department');
|
||||||
|
const caseParties = document.getElementById('case-parties');
|
||||||
|
const caseTags = document.getElementById('case-tags');
|
||||||
|
|
||||||
// Show first case by default
|
const checklistProgressText = document.getElementById('checklist-progress-text');
|
||||||
const firstCaseId = casesData[0].id;
|
const checklistProgressBar = document.getElementById('checklist-progress-bar');
|
||||||
const firstCaseData = casesMap.get(firstCaseId);
|
const checklistItems = document.getElementById('checklist-items');
|
||||||
document.getElementById('case-details-title').textContent = firstCaseData.title;
|
|
||||||
detailsId.textContent = firstCaseData.id;
|
const timelineContent = document.getElementById('case-timeline-content');
|
||||||
|
const commentsContent = document.getElementById('case-comments-content');
|
||||||
|
|
||||||
|
function getSeverityBadgeClass(severity) {
|
||||||
|
switch (severity.toLowerCase()) {
|
||||||
|
case 'high': return 'bg-red-100 text-red-800';
|
||||||
|
case 'medium': return 'bg-yellow-100 text-yellow-800';
|
||||||
|
case 'low': return 'bg-green-100 text-green-800';
|
||||||
|
default: return 'bg-gray-100 text-gray-800';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
caseLinks.forEach(link => {
|
function renderChecklist(checklist) {
|
||||||
link.addEventListener('click', function (e) {
|
checklistItems.innerHTML = '';
|
||||||
e.preventDefault();
|
if (!checklist || checklist.length === 0) {
|
||||||
const caseId = this.dataset.caseId;
|
checklistItems.innerHTML = '<p class="text-sm text-gray-500">No checklist items.</p>';
|
||||||
const caseData = casesMap.get(caseId);
|
checklistProgressBar.style.width = '0%';
|
||||||
|
checklistProgressText.textContent = '0/0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let completedCount = 0;
|
||||||
|
checklist.forEach(item => {
|
||||||
|
if (item.completed) completedCount++;
|
||||||
|
const itemEl = document.createElement('div');
|
||||||
|
itemEl.className = 'flex items-center';
|
||||||
|
itemEl.innerHTML = `
|
||||||
|
<div class="${item.completed ? 'bg-blue-600' : 'border border-gray-400'} rounded-full w-5 h-5 flex items-center justify-center mr-3"><svg class="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg></div>
|
||||||
|
<span class="${item.completed ? 'text-gray-500 line-through' : 'text-gray-800'} text-sm">${item.item}</span>
|
||||||
|
`;
|
||||||
|
checklistItems.appendChild(itemEl);
|
||||||
|
});
|
||||||
|
|
||||||
if (caseData) {
|
const progress = (completedCount / checklist.length) * 100;
|
||||||
document.getElementById('case-details-title').textContent = caseData.title;
|
checklistProgressBar.style.width = `${progress}%`;
|
||||||
detailsId.textContent = caseData.id;
|
checklistProgressText.textContent = `${completedCount}/${checklist.length}`;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
function renderTimeline(timeline) {
|
||||||
|
timelineContent.innerHTML = '';
|
||||||
|
if (!timeline || timeline.length === 0) {
|
||||||
|
timelineContent.innerHTML = '<p class="text-sm text-gray-500">No timeline events.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertical line
|
||||||
|
const line = document.createElement('div');
|
||||||
|
line.className = 'absolute left-4 top-2 bottom-2 w-0.5 bg-gray-200';
|
||||||
|
timelineContent.appendChild(line);
|
||||||
|
|
||||||
|
timeline.forEach(item => {
|
||||||
|
const itemEl = document.createElement('div');
|
||||||
|
itemEl.className = 'relative pl-12';
|
||||||
|
itemEl.innerHTML = `
|
||||||
|
<div class="${item.completed ? 'bg-blue-600' : 'border-2 border-gray-400'} absolute left-4 top-1.5 -translate-x-1/2 w-5 h-5 rounded-full z-10 bg-white flex items-center justify-center" >
|
||||||
|
${item.completed ? '<svg class="w-3 h-3 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>' : ''}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<p class="font-bold text-gray-800">${item.status}</p>
|
||||||
|
<p class="text-sm text-gray-500">${item.date || ''}</p>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mt-1">${item.details}</p>
|
||||||
|
`;
|
||||||
|
timelineContent.appendChild(itemEl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderComments(comments) {
|
||||||
|
commentsContent.innerHTML = '';
|
||||||
|
if (!comments || comments.length === 0) {
|
||||||
|
commentsContent.innerHTML = '<p class="text-sm text-gray-500">No comments yet.</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
comments.forEach(comment => {
|
||||||
|
const itemEl = document.createElement('div');
|
||||||
|
itemEl.className = 'flex items-start gap-4';
|
||||||
|
itemEl.innerHTML = `
|
||||||
|
<img src="https://i.pravatar.cc/40?u=${comment.author.replace(/\s/g, '')}" class="w-10 h-10 rounded-full" alt="${comment.author}">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-gray-800">${comment.author}</p>
|
||||||
|
<p class="text-xs text-gray-500">${comment.role}</p>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-400">${comment.time}</p>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-700 mt-2 bg-gray-50 p-3 rounded-lg">${comment.comment}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
commentsContent.appendChild(itemEl);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCaseDetails(caseId) {
|
||||||
|
const caseData = casesMap.get(caseId);
|
||||||
|
if (!caseData) return;
|
||||||
|
|
||||||
|
// Header
|
||||||
|
caseTitle.textContent = caseData.title;
|
||||||
|
caseIdDate.textContent = `Case #${caseData.id} • Created ${caseData.createdDate}`;
|
||||||
|
caseSeverityBadge.textContent = caseData.severity.charAt(0).toUpperCase() + caseData.severity.slice(1);
|
||||||
|
caseSeverityBadge.className = `text-sm font-semibold px-3 py-1 rounded-lg ${getSeverityBadgeClass(caseData.severity)}`;
|
||||||
|
caseStatusDropdown.value = caseData.status.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
||||||
|
|
||||||
|
// Details card
|
||||||
|
caseAssigneeImg.src = `https://i.pravatar.cc/40?u=${caseData.assignedTo.replace(/\s/g, '')}`;
|
||||||
|
caseAssigneeName.textContent = caseData.assignedTo;
|
||||||
|
caseAssigneeRole.textContent = caseData.assignedToRole;
|
||||||
|
caseDepartment.textContent = caseData.department;
|
||||||
|
caseParties.textContent = `${caseData.partiesInvolved} employees`;
|
||||||
|
caseTags.innerHTML = '';
|
||||||
|
caseData.tags.forEach(tag => {
|
||||||
|
const tagEl = document.createElement('span');
|
||||||
|
tagEl.className = 'bg-blue-100 text-blue-800 text-sm font-medium px-3 py-1 rounded-md';
|
||||||
|
tagEl.textContent = tag;
|
||||||
|
if(tag.toLowerCase() === 'urgent') {
|
||||||
|
tagEl.className = 'bg-red-100 text-red-800 text-sm font-medium px-3 py-1 rounded-md';
|
||||||
|
}
|
||||||
|
caseTags.appendChild(tagEl);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Checklist
|
||||||
|
renderChecklist(caseData.checklist);
|
||||||
|
|
||||||
|
// Timeline
|
||||||
|
renderTimeline(caseData.timeline);
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
renderComments(caseData.comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup links
|
||||||
|
const caseLinks = document.querySelectorAll('.case-link');
|
||||||
|
caseLinks.forEach(link => {
|
||||||
|
link.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Update active state
|
||||||
|
caseLinks.forEach(l => l.classList.remove('bg-blue-100', 'border-blue-500'));
|
||||||
|
this.classList.add('bg-blue-100', 'border-blue-500');
|
||||||
|
|
||||||
|
const caseId = this.dataset.caseId;
|
||||||
|
updateCaseDetails(caseId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Show first case by default
|
||||||
|
if (casesData.length > 0) {
|
||||||
|
const firstCaseId = casesData[0].id;
|
||||||
|
updateCaseDetails(firstCaseId);
|
||||||
|
const firstLink = document.querySelector('.case-link');
|
||||||
|
if(firstLink) {
|
||||||
|
firstLink.classList.add('bg-blue-100', 'border-blue-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user