Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>TeamPerf | Performance Dashboard</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<script> | |
tailwind.config = { | |
theme: { | |
extend: { | |
colors: { | |
primary: '#4F46E5', | |
secondary: '#10B981', | |
dark: '#1F2937', | |
light: '#F9FAFB' | |
} | |
} | |
} | |
} | |
</script> | |
<style> | |
.progress-ring__circle { | |
transition: stroke-dashoffset 0.5s; | |
transform: rotate(-90deg); | |
transform-origin: 50% 50%; | |
} | |
.chart-container { | |
position: relative; | |
height: 250px; | |
} | |
.fade-in { | |
animation: fadeIn 0.5s ease-in; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; } | |
to { opacity: 1; } | |
} | |
.modal { | |
transition: opacity 0.3s ease; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 font-sans"> | |
<div class="min-h-screen flex flex-col"> | |
<!-- Header --> | |
<header class="bg-white shadow-sm"> | |
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex justify-between items-center"> | |
<div class="flex items-center space-x-2"> | |
<div class="w-8 h-8 rounded-md bg-primary flex items-center justify-center"> | |
<i class="fas fa-chart-line text-white"></i> | |
</div> | |
<h1 class="text-xl font-bold text-dark">TeamPerf</h1> | |
</div> | |
<div class="flex items-center space-x-4"> | |
<div class="relative"> | |
<button id="notifications-btn" class="p-2 rounded-full hover:bg-gray-100"> | |
<i class="fas fa-bell text-gray-500"></i> | |
<span id="notification-count" class="absolute top-0 right-0 w-5 h-5 bg-red-500 rounded-full text-white text-xs flex items-center justify-center">3</span> | |
</button> | |
<div id="notifications-dropdown" class="hidden absolute right-0 mt-2 w-64 bg-white rounded-md shadow-lg z-10"> | |
<div class="p-4 border-b"> | |
<h3 class="font-medium">Notifications</h3> | |
</div> | |
<div id="notification-list" class="max-h-60 overflow-y-auto"> | |
<a href="#" class="block px-4 py-3 hover:bg-gray-50 border-b notification-item"> | |
<p class="text-sm">John completed his quarterly goals</p> | |
<p class="text-xs text-gray-500">2 mins ago</p> | |
</a> | |
<a href="#" class="block px-4 py-3 hover:bg-gray-50 border-b notification-item"> | |
<p class="text-sm">Sarah requested feedback</p> | |
<p class="text-xs text-gray-500">1 hour ago</p> | |
</a> | |
<a href="#" class="block px-4 py-3 hover:bg-gray-50 notification-item"> | |
<p class="text-sm">New 360° review available</p> | |
<p class="text-xs text-gray-500">3 hours ago</p> | |
</a> | |
</div> | |
</div> | |
</div> | |
<div class="flex items-center space-x-2"> | |
<img src="https://randomuser.me/api/portraits/women/44.jpg" alt="Profile" class="w-8 h-8 rounded-full"> | |
<span class="text-sm font-medium">Jane D.</span> | |
</div> | |
</div> | |
</div> | |
</header> | |
<!-- Main Content --> | |
<main class="flex-1"> | |
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6"> | |
<!-- Dashboard Header --> | |
<div class="flex justify-between items-center mb-6"> | |
<div> | |
<h2 class="text-2xl font-bold text-dark">Performance Dashboard</h2> | |
<p class="text-gray-500">Track and manage your team's performance</p> | |
</div> | |
<div class="flex space-x-3"> | |
<button id="new-goal-btn" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary-600 flex items-center"> | |
<i class="fas fa-plus mr-2"></i> New Goal | |
</button> | |
<button id="filter-btn" class="px-4 py-2 bg-white border border-gray-300 rounded-md hover:bg-gray-50 flex items-center"> | |
<i class="fas fa-filter mr-2"></i> Filter | |
</button> | |
</div> | |
</div> | |
<!-- Stats Cards --> | |
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6"> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div class="flex justify-between"> | |
<div> | |
<p class="text-gray-500">Team Performance</p> | |
<h3 id="team-performance" class="text-2xl font-bold">82%</h3> | |
</div> | |
<div class="w-16 h-16"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path id="team-performance-ring" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#4F46E5" | |
stroke-width="3" | |
stroke-dasharray="82, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div class="mt-2 flex items-center text-sm text-gray-500"> | |
<span class="text-green-500 mr-1"><i class="fas fa-arrow-up"></i> 5%</span> | |
<span>vs last quarter</span> | |
</div> | |
</div> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div class="flex justify-between"> | |
<div> | |
<p class="text-gray-500">Goal Completion</p> | |
<h3 id="goal-completion" class="text-2xl font-bold">68%</h3> | |
</div> | |
<div class="w-16 h-16"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path id="goal-completion-ring" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="68, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div class="mt-2 flex items-center text-sm text-gray-500"> | |
<span class="text-green-500 mr-1"><i class="fas fa-arrow-up"></i> 12%</span> | |
<span>vs last quarter</span> | |
</div> | |
</div> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div> | |
<p class="text-gray-500">Pending Reviews</p> | |
<h3 id="pending-reviews" class="text-2xl font-bold">14</h3> | |
</div> | |
<div class="mt-4"> | |
<div class="flex justify-between text-sm mb-1"> | |
<span>Overdue</span> | |
<span id="overdue-reviews">5</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div id="overdue-bar" class="bg-yellow-500 h-2 rounded-full" style="width: 35%"></div> | |
</div> | |
</div> | |
</div> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div> | |
<p class="text-gray-500">Employee Engagement</p> | |
<h3 id="engagement-score" class="text-2xl font-bold">7.8</h3> | |
</div> | |
<div class="mt-4"> | |
<div class="flex justify-between text-sm mb-1"> | |
<span>eNPS Score</span> | |
<span id="enps-score">+42</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div id="engagement-bar" class="bg-purple-500 h-2 rounded-full" style="width: 78%"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Main Content Area --> | |
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
<!-- Left Column --> | |
<div class="lg:col-span-2 space-y-6"> | |
<!-- Performance Trends Chart --> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="font-bold text-lg">Performance Trends</h3> | |
<select id="time-period-select" class="border border-gray-300 rounded-md px-3 py-1 text-sm"> | |
<option value="3">Last 3 Months</option> | |
<option value="6">Last 6 Months</option> | |
<option value="12">Last Year</option> | |
</select> | |
</div> | |
<div class="chart-container"> | |
<canvas id="performanceChart"></canvas> | |
</div> | |
</div> | |
<!-- Team Goals --> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="font-bold text-lg">Team Goals</h3> | |
<button id="view-all-goals" class="text-primary text-sm font-medium">View All</button> | |
</div> | |
<div id="goals-list" class="space-y-4"> | |
<div class="border-b pb-4"> | |
<div class="flex justify-between mb-2"> | |
<h4 class="font-medium">Increase Customer Satisfaction</h4> | |
<span class="text-sm font-medium">75%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div class="bg-primary h-2 rounded-full" style="width: 75%"></div> | |
</div> | |
<div class="flex justify-between mt-2 text-sm text-gray-500"> | |
<span>Due: Jun 30, 2023</span> | |
<span>5/8 milestones</span> | |
</div> | |
</div> | |
<div class="border-b pb-4"> | |
<div class="flex justify-between mb-2"> | |
<h4 class="font-medium">Improve Product Quality</h4> | |
<span class="text-sm font-medium">62%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div class="bg-primary h-2 rounded-full" style="width: 62%"></div> | |
</div> | |
<div class="flex justify-between mt-2 text-sm text-gray-500"> | |
<span>Due: Aug 15, 2023</span> | |
<span>3/6 milestones</span> | |
</div> | |
</div> | |
<div> | |
<div class="flex justify-between mb-2"> | |
<h4 class="font-medium">Expand Market Reach</h4> | |
<span class="text-sm font-medium">45%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div class="bg-primary h-2 rounded-full" style="width: 45%"></div> | |
</div> | |
<div class="flex justify-between mt-2 text-sm text-gray-500"> | |
<span>Due: Dec 31, 2023</span> | |
<span>2/5 milestones</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Right Column --> | |
<div class="space-y-6"> | |
<!-- Quick Actions --> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<h3 class="font-bold text-lg mb-4">Quick Actions</h3> | |
<div class="grid grid-cols-2 gap-3"> | |
<button id="set-goal-btn" class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50"> | |
<div class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center mb-2"> | |
<i class="fas fa-bullseye text-blue-600"></i> | |
</div> | |
<span class="text-sm">Set Goal</span> | |
</button> | |
<button id="give-feedback-btn" class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50"> | |
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center mb-2"> | |
<i class="fas fa-comment-alt text-green-600"></i> | |
</div> | |
<span class="text-sm">Give Feedback</span> | |
</button> | |
<button id="run-report-btn" class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50"> | |
<div class="w-10 h-10 bg-purple-100 rounded-full flex items-center justify-center mb-2"> | |
<i class="fas fa-chart-bar text-purple-600"></i> | |
</div> | |
<span class="text-sm">Run Report</span> | |
</button> | |
<button id="team-review-btn" class="flex flex-col items-center justify-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50"> | |
<div class="w-10 h-10 bg-yellow-100 rounded-full flex items-center justify-center mb-2"> | |
<i class="fas fa-users text-yellow-600"></i> | |
</div> | |
<span class="text-sm">Team Review</span> | |
</button> | |
</div> | |
</div> | |
<!-- Team Members --> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="font-bold text-lg">Team Members</h3> | |
<button id="view-all-members" class="text-primary text-sm font-medium">View All</button> | |
</div> | |
<div id="team-members-list" class="space-y-4"> | |
<div class="flex items-center"> | |
<img src="https://randomuser.me/api/portraits/men/32.jpg" alt="Team member" class="w-10 h-10 rounded-full mr-3"> | |
<div class="flex-1"> | |
<h4 class="font-medium">John Smith</h4> | |
<p class="text-sm text-gray-500">Product Manager</p> | |
</div> | |
<div class="w-8 h-8"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path class="performance-ring" data-value="85" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="85, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div class="flex items-center"> | |
<img src="https://randomuser.me/api/portraits/women/65.jpg" alt="Team member" class="w-10 h-10 rounded-full mr-3"> | |
<div class="flex-1"> | |
<h4 class="font-medium">Sarah Johnson</h4> | |
<p class="text-sm text-gray-500">UX Designer</p> | |
</div> | |
<div class="w-8 h-8"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path class="performance-ring" data-value="78" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="78, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div class="flex items-center"> | |
<img src="https://randomuser.me/api/portraits/men/75.jpg" alt="Team member" class="w-10 h-10 rounded-full mr-3"> | |
<div class="flex-1"> | |
<h4 class="font-medium">Michael Chen</h4> | |
<p class="text-sm text-gray-500">Frontend Developer</p> | |
</div> | |
<div class="w-8 h-8"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path class="performance-ring" data-value="92" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="92, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div class="flex items-center"> | |
<img src="https://randomuser.me/api/portraits/women/33.jpg" alt="Team member" class="w-10 h-10 rounded-full mr-3"> | |
<div class="flex-1"> | |
<h4 class="font-medium">Emily Wilson</h4> | |
<p class="text-sm text-gray-500">Marketing Specialist</p> | |
</div> | |
<div class="w-8 h-8"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path class="performance-ring" data-value="65" d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="65, 100" | |
/> | |
</svg> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Recent Feedback --> | |
<div class="bg-white rounded-lg shadow p-6"> | |
<h3 class="font-bold text-lg mb-4">Recent Feedback</h3> | |
<div id="feedback-list" class="space-y-4"> | |
<div class="flex"> | |
<img src="https://randomuser.me/api/portraits/men/22.jpg" alt="Feedback giver" class="w-8 h-8 rounded-full mr-3"> | |
<div> | |
<div class="bg-gray-50 p-3 rounded-lg"> | |
<p class="text-sm">"Great job on the Q2 presentation! Your preparation really showed."</p> | |
</div> | |
<p class="text-xs text-gray-500 mt-1">David K. • 2 days ago</p> | |
</div> | |
</div> | |
<div class="flex"> | |
<img src="https://randomuser.me/api/portraits/women/45.jpg" alt="Feedback giver" class="w-8 h-8 rounded-full mr-3"> | |
<div> | |
<div class="bg-gray-50 p-3 rounded-lg"> | |
<p class="text-sm">"Let's work on improving response times to customer inquiries."</p> | |
</div> | |
<p class="text-xs text-gray-500 mt-1">Lisa M. • 1 week ago</p> | |
</div> | |
</div> | |
</div> | |
<button id="view-all-feedback" class="mt-4 text-primary text-sm font-medium w-full text-center">View All Feedback</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</main> | |
</div> | |
<!-- Modals --> | |
<div id="new-goal-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden modal"> | |
<div class="bg-white rounded-lg shadow-xl w-full max-w-md"> | |
<div class="p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-lg font-bold">Create New Goal</h3> | |
<button id="close-goal-modal" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<form id="goal-form"> | |
<div class="mb-4"> | |
<label for="goal-title" class="block text-sm font-medium text-gray-700 mb-1">Goal Title</label> | |
<input type="text" id="goal-title" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"> | |
</div> | |
<div class="mb-4"> | |
<label for="goal-description" class="block text-sm font-medium text-gray-700 mb-1">Description</label> | |
<textarea id="goal-description" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"></textarea> | |
</div> | |
<div class="grid grid-cols-2 gap-4 mb-4"> | |
<div> | |
<label for="goal-due-date" class="block text-sm font-medium text-gray-700 mb-1">Due Date</label> | |
<input type="date" id="goal-due-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"> | |
</div> | |
<div> | |
<label for="goal-milestones" class="block text-sm font-medium text-gray-700 mb-1">Milestones</label> | |
<input type="number" id="goal-milestones" min="1" value="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"> | |
</div> | |
</div> | |
<div class="flex justify-end space-x-3"> | |
<button type="button" id="cancel-goal" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300">Cancel</button> | |
<button type="submit" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary-600">Create Goal</button> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
<div id="feedback-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden modal"> | |
<div class="bg-white rounded-lg shadow-xl w-full max-w-md"> | |
<div class="p-6"> | |
<div class="flex justify-between items-center mb-4"> | |
<h3 class="text-lg font-bold">Give Feedback</h3> | |
<button id="close-feedback-modal" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
<form id="feedback-form"> | |
<div class="mb-4"> | |
<label for="feedback-recipient" class="block text-sm font-medium text-gray-700 mb-1">Recipient</label> | |
<select id="feedback-recipient" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"> | |
<option value="">Select team member</option> | |
<option value="John Smith">John Smith</option> | |
<option value="Sarah Johnson">Sarah Johnson</option> | |
<option value="Michael Chen">Michael Chen</option> | |
<option value="Emily Wilson">Emily Wilson</option> | |
</select> | |
</div> | |
<div class="mb-4"> | |
<label for="feedback-type" class="block text-sm font-medium text-gray-700 mb-1">Feedback Type</label> | |
<select id="feedback-type" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"> | |
<option value="positive">Positive</option> | |
<option value="constructive">Constructive</option> | |
<option value="development">Development</option> | |
</select> | |
</div> | |
<div class="mb-4"> | |
<label for="feedback-message" class="block text-sm font-medium text-gray-700 mb-1">Message</label> | |
<textarea id="feedback-message" rows="4" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary"></textarea> | |
</div> | |
<div class="flex justify-end space-x-3"> | |
<button type="button" id="cancel-feedback" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300">Cancel</button> | |
<button type="submit" class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary-600">Submit Feedback</button> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
<div id="view-all-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden modal"> | |
<div class="bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[80vh] flex flex-col"> | |
<div class="p-6 border-b"> | |
<div class="flex justify-between items-center"> | |
<h3 id="view-all-title" class="text-lg font-bold">View All</h3> | |
<button id="close-view-all-modal" class="text-gray-500 hover:text-gray-700"> | |
<i class="fas fa-times"></i> | |
</button> | |
</div> | |
</div> | |
<div id="view-all-content" class="p-6 overflow-y-auto flex-1"> | |
<!-- Content will be dynamically inserted here --> | |
</div> | |
</div> | |
</div> | |
<!-- Chart.js --> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<script> | |
// Dashboard Data | |
const dashboardData = { | |
teamPerformance: 82, | |
goalCompletion: 68, | |
pendingReviews: 14, | |
overdueReviews: 5, | |
engagementScore: 7.8, | |
enpsScore: 42, | |
performanceTrends: { | |
'3': { | |
labels: ['Apr', 'May', 'Jun'], | |
team: [80, 79, 82], | |
goals: [65, 67, 68] | |
}, | |
'6': { | |
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], | |
team: [72, 75, 78, 80, 79, 82], | |
goals: [58, 60, 62, 65, 67, 68] | |
}, | |
'12': { | |
labels: ['Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], | |
team: [65, 68, 70, 72, 70, 72, 72, 75, 78, 80, 79, 82], | |
goals: [50, 52, 55, 56, 55, 56, 58, 60, 62, 65, 67, 68] | |
} | |
}, | |
teamGoals: [ | |
{ | |
title: "Increase Customer Satisfaction", | |
progress: 75, | |
dueDate: "Jun 30, 2023", | |
milestones: "5/8" | |
}, | |
{ | |
title: "Improve Product Quality", | |
progress: 62, | |
dueDate: "Aug 15, 2023", | |
milestones: "3/6" | |
}, | |
{ | |
title: "Expand Market Reach", | |
progress: 45, | |
dueDate: "Dec 31, 2023", | |
milestones: "2/5" | |
}, | |
{ | |
title: "Reduce Operational Costs", | |
progress: 30, | |
dueDate: "Sep 30, 2023", | |
milestones: "1/4" | |
}, | |
{ | |
title: "Improve Employee Retention", | |
progress: 55, | |
dueDate: "Nov 15, 2023", | |
milestones: "4/7" | |
} | |
], | |
teamMembers: [ | |
{ | |
name: "John Smith", | |
role: "Product Manager", | |
performance: 85, | |
photo: "https://randomuser.me/api/portraits/men/32.jpg" | |
}, | |
{ | |
name: "Sarah Johnson", | |
role: "UX Designer", | |
performance: 78, | |
photo: "https://randomuser.me/api/portraits/women/65.jpg" | |
}, | |
{ | |
name: "Michael Chen", | |
role: "Frontend Developer", | |
performance: 92, | |
photo: "https://randomuser.me/api/portraits/men/75.jpg" | |
}, | |
{ | |
name: "Emily Wilson", | |
role: "Marketing Specialist", | |
performance: 65, | |
photo: "https://randomuser.me/api/portraits/women/33.jpg" | |
}, | |
{ | |
name: "David Kim", | |
role: "Backend Developer", | |
performance: 88, | |
photo: "https://randomuser.me/api/portraits/men/22.jpg" | |
}, | |
{ | |
name: "Lisa Martinez", | |
role: "QA Engineer", | |
performance: 72, | |
photo: "https://randomuser.me/api/portraits/women/45.jpg" | |
} | |
], | |
feedback: [ | |
{ | |
giver: "David K.", | |
message: "Great job on the Q2 presentation! Your preparation really showed.", | |
date: "2 days ago", | |
photo: "https://randomuser.me/api/portraits/men/22.jpg" | |
}, | |
{ | |
giver: "Lisa M.", | |
message: "Let's work on improving response times to customer inquiries.", | |
date: "1 week ago", | |
photo: "https://randomuser.me/api/portraits/women/45.jpg" | |
}, | |
{ | |
giver: "Robert T.", | |
message: "Your attention to detail in the last sprint was excellent.", | |
date: "2 weeks ago", | |
photo: "https://randomuser.me/api/portraits/men/41.jpg" | |
}, | |
{ | |
giver: "Anna S.", | |
message: "The new onboarding process you designed is very effective.", | |
date: "3 weeks ago", | |
photo: "https://randomuser.me/api/portraits/women/63.jpg" | |
} | |
], | |
notifications: [ | |
{ | |
message: "John completed his quarterly goals", | |
time: "2 mins ago" | |
}, | |
{ | |
message: "Sarah requested feedback", | |
time: "1 hour ago" | |
}, | |
{ | |
message: "New 360° review available", | |
time: "3 hours ago" | |
} | |
] | |
}; | |
// Initialize dashboard | |
document.addEventListener('DOMContentLoaded', function() { | |
// Initialize charts and data | |
initPerformanceChart(); | |
updateDashboardData(); | |
initEventListeners(); | |
// Add fade-in animation to all cards | |
const cards = document.querySelectorAll('.bg-white'); | |
cards.forEach((card, index) => { | |
card.classList.add('fade-in'); | |
card.style.animationDelay = `${index * 0.1}s`; | |
}); | |
}); | |
// Initialize performance chart | |
let performanceChart; | |
function initPerformanceChart() { | |
const ctx = document.getElementById('performanceChart').getContext('2d'); | |
const selectedPeriod = document.getElementById('time-period-select').value; | |
const data = dashboardData.performanceTrends[selectedPeriod]; | |
performanceChart = new Chart(ctx, { | |
type: 'line', | |
data: { | |
labels: data.labels, | |
datasets: [ | |
{ | |
label: 'Team Performance', | |
data: data.team, | |
borderColor: '#4F46E5', | |
backgroundColor: 'rgba(79, 70, 229, 0.1)', | |
borderWidth: 2, | |
tension: 0.3, | |
fill: true | |
}, | |
{ | |
label: 'Goal Completion', | |
data: data.goals, | |
borderColor: '#10B981', | |
backgroundColor: 'rgba(16, 185, 129, 0.1)', | |
borderWidth: 2, | |
tension: 0.3, | |
fill: true | |
} | |
] | |
}, | |
options: { | |
responsive: true, | |
maintainAspectRatio: false, | |
plugins: { | |
legend: { | |
position: 'top', | |
}, | |
tooltip: { | |
mode: 'index', | |
intersect: false, | |
} | |
}, | |
scales: { | |
y: { | |
beginAtZero: false, | |
min: 50, | |
max: 100, | |
ticks: { | |
stepSize: 10 | |
} | |
} | |
} | |
} | |
}); | |
} | |
// Update dashboard data | |
function updateDashboardData() { | |
// Update metrics | |
document.getElementById('team-performance').textContent = `${dashboardData.teamPerformance}%`; | |
document.getElementById('goal-completion').textContent = `${dashboardData.goalCompletion}%`; | |
document.getElementById('pending-reviews').textContent = dashboardData.pendingReviews; | |
document.getElementById('overdue-reviews').textContent = dashboardData.overdueReviews; | |
document.getElementById('engagement-score').textContent = dashboardData.engagementScore; | |
document.getElementById('enps-score').textContent = `+${dashboardData.enpsScore}`; | |
// Update progress rings | |
document.getElementById('team-performance-ring').setAttribute('stroke-dasharray', `${dashboardData.teamPerformance}, 100`); | |
document.getElementById('goal-completion-ring').setAttribute('stroke-dasharray', `${dashboardData.goalCompletion}, 100`); | |
// Update progress bars | |
document.getElementById('overdue-bar').style.width = `${(dashboardData.overdueReviews / dashboardData.pendingReviews) * 100}%`; | |
document.getElementById('engagement-bar').style.width = `${(dashboardData.engagementScore / 10) * 100}%`; | |
// Update team member performance rings | |
document.querySelectorAll('.performance-ring').forEach(ring => { | |
const value = ring.getAttribute('data-value'); | |
ring.setAttribute('stroke-dasharray', `${value}, 100`); | |
}); | |
} | |
// Initialize event listeners | |
function initEventListeners() { | |
// Notifications dropdown | |
document.getElementById('notifications-btn').addEventListener('click', function(e) { | |
e.stopPropagation(); | |
const dropdown = document.getElementById('notifications-dropdown'); | |
dropdown.classList.toggle('hidden'); | |
}); | |
// Close dropdown when clicking outside | |
document.addEventListener('click', function() { | |
document.getElementById('notifications-dropdown').classList.add('hidden'); | |
}); | |
// Time period selector | |
document.getElementById('time-period-select').addEventListener('change', function() { | |
performanceChart.destroy(); | |
initPerformanceChart(); | |
}); | |
// New goal modal | |
document.getElementById('new-goal-btn').addEventListener('click', function() { | |
document.getElementById('new-goal-modal').classList.remove('hidden'); | |
}); | |
document.getElementById('close-goal-modal').addEventListener('click', function() { | |
document.getElementById('new-goal-modal').classList.add('hidden'); | |
}); | |
document.getElementById('cancel-goal').addEventListener('click', function() { | |
document.getElementById('new-goal-modal').classList.add('hidden'); | |
}); | |
document.getElementById('goal-form').addEventListener('submit', function(e) { | |
e.preventDefault(); | |
const title = document.getElementById('goal-title').value; | |
const description = document.getElementById('goal-description').value; | |
const dueDate = document.getElementById('goal-due-date').value; | |
const milestones = document.getElementById('goal-milestones').value; | |
// Format date | |
const formattedDate = new Date(dueDate).toLocaleDateString('en-US', { | |
month: 'short', | |
day: 'numeric', | |
year: 'numeric' | |
}); | |
// Add new goal | |
const newGoal = { | |
title: title, | |
progress: 0, | |
dueDate: formattedDate, | |
milestones: `0/${milestones}` | |
}; | |
dashboardData.teamGoals.unshift(newGoal); | |
updateGoalsList(); | |
// Update goal completion metric | |
const totalGoals = dashboardData.teamGoals.length; | |
const completedGoals = dashboardData.teamGoals.filter(g => g.progress === 100).length; | |
dashboardData.goalCompletion = Math.round((completedGoals / totalGoals) * 100); | |
updateDashboardData(); | |
// Reset form and close modal | |
document.getElementById('goal-form').reset(); | |
document.getElementById('new-goal-modal').classList.add('hidden'); | |
// Show success message | |
alert('New goal created successfully!'); | |
}); | |
// Feedback modal | |
document.getElementById('give-feedback-btn').addEventListener('click', function() { | |
document.getElementById('feedback-modal').classList.remove('hidden'); | |
}); | |
document.getElementById('close-feedback-modal').addEventListener('click', function() { | |
document.getElementById('feedback-modal').classList.add('hidden'); | |
}); | |
document.getElementById('cancel-feedback').addEventListener('click', function() { | |
document.getElementById('feedback-modal').classList.add('hidden'); | |
}); | |
document.getElementById('feedback-form').addEventListener('submit', function(e) { | |
e.preventDefault(); | |
const recipient = document.getElementById('feedback-recipient').value; | |
const type = document.getElementById('feedback-type').value; | |
const message = document.getElementById('feedback-message').value; | |
// Add new feedback | |
const newFeedback = { | |
giver: "You", | |
message: message, | |
date: "Just now", | |
photo: "https://randomuser.me/api/portraits/women/44.jpg", | |
type: type, | |
recipient: recipient | |
}; | |
dashboardData.feedback.unshift(newFeedback); | |
updateFeedbackList(); | |
// Reset form and close modal | |
document.getElementById('feedback-form').reset(); | |
document.getElementById('feedback-modal').classList.add('hidden'); | |
// Show success message | |
alert('Feedback submitted successfully!'); | |
}); | |
// View all modals | |
document.getElementById('view-all-goals').addEventListener('click', function() { | |
showViewAllModal('Team Goals', 'goals'); | |
}); | |
document.getElementById('view-all-members').addEventListener('click', function() { | |
showViewAllModal('Team Members', 'members'); | |
}); | |
document.getElementById('view-all-feedback').addEventListener('click', function() { | |
showViewAllModal('All Feedback', 'feedback'); | |
}); | |
document.getElementById('close-view-all-modal').addEventListener('click', function() { | |
document.getElementById('view-all-modal').classList.add('hidden'); | |
}); | |
// Quick action buttons | |
document.getElementById('set-goal-btn').addEventListener('click', function() { | |
document.getElementById('new-goal-modal').classList.remove('hidden'); | |
}); | |
document.getElementById('run-report-btn').addEventListener('click', function() { | |
alert('Performance report is being generated. You will receive a notification when it\'s ready.'); | |
}); | |
document.getElementById('team-review-btn').addEventListener('click', function() { | |
alert('Team review session has been scheduled for next Monday at 10 AM.'); | |
}); | |
// Filter button | |
document.getElementById('filter-btn').addEventListener('click', function() { | |
alert('Filter functionality will be implemented in the next version.'); | |
}); | |
// Notification items | |
document.querySelectorAll('.notification-item').forEach(item => { | |
item.addEventListener('click', function(e) { | |
e.preventDefault(); | |
const index = Array.from(document.querySelectorAll('.notification-item')).indexOf(item); | |
dashboardData.notifications.splice(index, 1); | |
updateNotificationList(); | |
// Close dropdown | |
document.getElementById('notifications-dropdown').classList.add('hidden'); | |
}); | |
}); | |
} | |
// Update goals list | |
function updateGoalsList() { | |
const goalsList = document.getElementById('goals-list'); | |
goalsList.innerHTML = ''; | |
// Show only first 3 goals in the main view | |
const goalsToShow = dashboardData.teamGoals.slice(0, 3); | |
goalsToShow.forEach(goal => { | |
const goalElement = document.createElement('div'); | |
goalElement.className = 'border-b pb-4'; | |
goalElement.innerHTML = ` | |
<div class="flex justify-between mb-2"> | |
<h4 class="font-medium">${goal.title}</h4> | |
<span class="text-sm font-medium">${goal.progress}%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div class="bg-primary h-2 rounded-full" style="width: ${goal.progress}%"></div> | |
</div> | |
<div class="flex justify-between mt-2 text-sm text-gray-500"> | |
<span>Due: ${goal.dueDate}</span> | |
<span>${goal.milestones} milestones</span> | |
</div> | |
`; | |
goalsList.appendChild(goalElement); | |
}); | |
} | |
// Update feedback list | |
function updateFeedbackList() { | |
const feedbackList = document.getElementById('feedback-list'); | |
feedbackList.innerHTML = ''; | |
// Show only first 2 feedback items in the main view | |
const feedbackToShow = dashboardData.feedback.slice(0, 2); | |
feedbackToShow.forEach(feedback => { | |
const feedbackElement = document.createElement('div'); | |
feedbackElement.className = 'flex'; | |
feedbackElement.innerHTML = ` | |
<img src="${feedback.photo}" alt="Feedback giver" class="w-8 h-8 rounded-full mr-3"> | |
<div> | |
<div class="bg-gray-50 p-3 rounded-lg"> | |
<p class="text-sm">"${feedback.message}"</p> | |
</div> | |
<p class="text-xs text-gray-500 mt-1">${feedback.giver} • ${feedback.date}</p> | |
</div> | |
`; | |
feedbackList.appendChild(feedbackElement); | |
}); | |
} | |
// Update notification list | |
function updateNotificationList() { | |
const notificationList = document.getElementById('notification-list'); | |
notificationList.innerHTML = ''; | |
dashboardData.notifications.forEach(notification => { | |
const notificationElement = document.createElement('a'); | |
notificationElement.href = '#'; | |
notificationElement.className = 'block px-4 py-3 hover:bg-gray-50 border-b notification-item'; | |
notificationElement.innerHTML = ` | |
<p class="text-sm">${notification.message}</p> | |
<p class="text-xs text-gray-500">${notification.time}</p> | |
`; | |
notificationList.appendChild(notificationElement); | |
}); | |
// Update notification count | |
document.getElementById('notification-count').textContent = dashboardData.notifications.length; | |
// Add event listeners to new notification items | |
document.querySelectorAll('.notification-item').forEach(item => { | |
item.addEventListener('click', function(e) { | |
e.preventDefault(); | |
const index = Array.from(document.querySelectorAll('.notification-item')).indexOf(item); | |
dashboardData.notifications.splice(index, 1); | |
updateNotificationList(); | |
// Close dropdown | |
document.getElementById('notifications-dropdown').classList.add('hidden'); | |
}); | |
}); | |
} | |
// Show view all modal | |
function showViewAllModal(title, type) { | |
document.getElementById('view-all-title').textContent = title; | |
const content = document.getElementById('view-all-content'); | |
content.innerHTML = ''; | |
if (type === 'goals') { | |
dashboardData.teamGoals.forEach(goal => { | |
const goalElement = document.createElement('div'); | |
goalElement.className = 'border-b pb-4 mb-4'; | |
goalElement.innerHTML = ` | |
<div class="flex justify-between mb-2"> | |
<h4 class="font-medium">${goal.title}</h4> | |
<span class="text-sm font-medium">${goal.progress}%</span> | |
</div> | |
<div class="w-full bg-gray-200 rounded-full h-2"> | |
<div class="bg-primary h-2 rounded-full" style="width: ${goal.progress}%"></div> | |
</div> | |
<div class="flex justify-between mt-2 text-sm text-gray-500"> | |
<span>Due: ${goal.dueDate}</span> | |
<span>${goal.milestones} milestones</span> | |
</div> | |
`; | |
content.appendChild(goalElement); | |
}); | |
} else if (type === 'members') { | |
dashboardData.teamMembers.forEach(member => { | |
const memberElement = document.createElement('div'); | |
memberElement.className = 'flex items-center mb-4'; | |
memberElement.innerHTML = ` | |
<img src="${member.photo}" alt="Team member" class="w-10 h-10 rounded-full mr-3"> | |
<div class="flex-1"> | |
<h4 class="font-medium">${member.name}</h4> | |
<p class="text-sm text-gray-500">${member.role}</p> | |
</div> | |
<div class="w-8 h-8"> | |
<svg class="w-full h-full" viewBox="0 0 36 36"> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#E5E7EB" | |
stroke-width="3" | |
stroke-dasharray="100, 100" | |
/> | |
<path d="M18 2.0845 | |
a 15.9155 15.9155 0 0 1 0 31.831 | |
a 15.9155 15.9155 0 0 1 0 -31.831" | |
fill="none" | |
stroke="#10B981" | |
stroke-width="3" | |
stroke-dasharray="${member.performance}, 100" | |
/> | |
</svg> | |
</div> | |
`; | |
content.appendChild(memberElement); | |
}); | |
} else if (type === 'feedback') { | |
dashboardData.feedback.forEach(feedback => { | |
const feedbackElement = document.createElement('div'); | |
feedbackElement.className = 'border-b pb-4 mb-4'; | |
feedbackElement.innerHTML = ` | |
<div class="flex"> | |
<img src="${feedback.photo}" alt="Feedback giver" class="w-8 h-8 rounded-full mr-3"> | |
<div class="flex-1"> | |
<div class="flex justify-between items-center mb-1"> | |
<h4 class="font-medium">${feedback.giver}</h4> | |
<span class="text-xs text-gray-500">${feedback.date}</span> | |
</div> | |
<div class="bg-gray-50 p-3 rounded-lg"> | |
<p class="text-sm">"${feedback.message}"</p> | |
</div> | |
${feedback.recipient ? `<p class="text-xs text-gray-500 mt-1">To: ${feedback.recipient}</p>` : ''} | |
</div> | |
</div> | |
`; | |
content.appendChild(feedbackElement); | |
}); | |
} | |
document.getElementById('view-all-modal').classList.remove('hidden'); | |
} | |
// Simulate data updates (for demo purposes) | |
setInterval(function() { | |
// Randomly update some metrics | |
dashboardData.teamPerformance = Math.min(100, dashboardData.teamPerformance + (Math.random() > 0.5 ? 1 : -1)); | |
dashboardData.goalCompletion = Math.min(100, dashboardData.goalCompletion + (Math.random() > 0.5 ? 1 : -1)); | |
dashboardData.engagementScore = (Math.random() * 0.2 + 7.6).toFixed(1); | |
// Update dashboard | |
updateDashboardData(); | |
// Occasionally add a notification | |
if (Math.random() > 0.9 && dashboardData.notifications.length < 5) { | |
const messages = [ | |
"New performance review available", | |
"Team meeting in 15 minutes", | |
"Quarterly report is ready", | |
"Goal progress update", | |
"New feedback received" | |
]; | |
const times = [ | |
"Just now", | |
"1 min ago", | |
"5 mins ago" | |
]; | |
dashboardData.notifications.push({ | |
message: messages[Math.floor(Math.random() * messages.length)], | |
time: times[Math.floor(Math.random() * times.length)] | |
}); | |
updateNotificationList(); | |
} | |
}, 5000); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=JayStormX8/team-goals" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |