mirror of
https://github.com/thecyberlearn/victor-ai.git
synced 2026-08-18 08:53:04 +00:00
Victor AI - Local code complete
This commit is contained in:
commit
28467c4ce2
813
assets/css/styles.css
Normal file
813
assets/css/styles.css
Normal file
@ -0,0 +1,813 @@
|
|||||||
|
/* Common Styles for AI Services Hub */
|
||||||
|
|
||||||
|
/* Import fonts */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap');
|
||||||
|
|
||||||
|
/* Reset and base styles */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout utilities */
|
||||||
|
.container {
|
||||||
|
max-width: 7xl;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.container {
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.container {
|
||||||
|
padding: 0 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Component styles */
|
||||||
|
.glass-effect {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover {
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-hover:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card {
|
||||||
|
background: white;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-card:hover {
|
||||||
|
transform: translateY(-8px);
|
||||||
|
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar */
|
||||||
|
.custom-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-track {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loading skeleton */
|
||||||
|
.loading-skeleton {
|
||||||
|
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: loading 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading {
|
||||||
|
0% { background-position: 200% 0; }
|
||||||
|
100% { background-position: -200% 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideUp {
|
||||||
|
from { opacity: 0; transform: translateY(20px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeLine {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translateY(0px); }
|
||||||
|
50% { transform: translateY(-10px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-glow {
|
||||||
|
0%, 100% { box-shadow: 0 0 20px rgba(102, 126, 234, 0.4); }
|
||||||
|
50% { box-shadow: 0 0 30px rgba(102, 126, 234, 0.8); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
|
||||||
|
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(16, 185, 129, 0); }
|
||||||
|
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-pulse-soft {
|
||||||
|
animation: pulse-soft 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-soft {
|
||||||
|
0%, 100% { opacity: 1; }
|
||||||
|
50% { opacity: 0.7; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-in {
|
||||||
|
animation: fadeIn 0.4s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-slide-up {
|
||||||
|
animation: slideUp 0.4s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade {
|
||||||
|
animation: fadeLine 0.6s ease-in;
|
||||||
|
}
|
||||||
|
|
||||||
|
.float-animation {
|
||||||
|
animation: float 3s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse-glow {
|
||||||
|
animation: pulse-glow 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status indicator */
|
||||||
|
.status-indicator {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-indicator::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -2px;
|
||||||
|
right: -2px;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: #10b981;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid white;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CONSOLIDATED MOBILE STYLES - REPLACE ALL EXISTING MOBILE CSS */
|
||||||
|
|
||||||
|
/* Mobile responsive utilities */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.mobile-stack {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Section */
|
||||||
|
.text-center.mb-8 h1 {
|
||||||
|
font-size: 2rem !important;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enhanced Search Command Center */
|
||||||
|
.bg-white.rounded-2xl.p-6.mb-8 {
|
||||||
|
padding: 1rem !important;
|
||||||
|
margin-bottom: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trade AI Command Header */
|
||||||
|
.flex.items-center.gap-3.mb-4 h2 {
|
||||||
|
font-size: 1.125rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search Input */
|
||||||
|
#query {
|
||||||
|
font-size: 16px !important;
|
||||||
|
padding: 0.875rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search Button */
|
||||||
|
.bg-blue-600.hover\:bg-blue-700 {
|
||||||
|
padding: 0.875rem 1.5rem !important;
|
||||||
|
min-width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search button inline with text input - only lens icon */
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 {
|
||||||
|
flex-direction: row !important;
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
align-items: stretch !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 .flex-1 {
|
||||||
|
flex: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 button {
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 50px !important;
|
||||||
|
padding: 0.875rem 1rem !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide search button text on mobile, show only icon */
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 button span {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 button i {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick searches in single row with horizontal scroll */
|
||||||
|
.flex.flex-wrap.gap-2 {
|
||||||
|
flex-direction: row !important;
|
||||||
|
flex-wrap: nowrap !important;
|
||||||
|
overflow-x: auto !important;
|
||||||
|
overflow-y: hidden !important;
|
||||||
|
align-items: center !important;
|
||||||
|
padding: 0.5rem 0 !important;
|
||||||
|
margin-bottom: 0.75rem !important;
|
||||||
|
-webkit-overflow-scrolling: touch !important;
|
||||||
|
scrollbar-width: none !important;
|
||||||
|
-ms-overflow-style: none !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
position: relative !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide scrollbar on mobile */
|
||||||
|
.flex.flex-wrap.gap-2::-webkit-scrollbar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick searches label */
|
||||||
|
.flex.flex-wrap.gap-2 span.text-sm.text-gray-500 {
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
margin-right: 0.5rem !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
color: #6b7280 !important;
|
||||||
|
align-self: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Quick search buttons mobile */
|
||||||
|
.flex.flex-wrap.gap-2 button {
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
font-size: 0.75rem !important;
|
||||||
|
padding: 0.5rem 0.75rem !important;
|
||||||
|
min-width: fit-content !important;
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advanced Filters Section */
|
||||||
|
.border-t.border-gray-200.pt-4 {
|
||||||
|
padding-top: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advanced Filters Grid */
|
||||||
|
.grid.grid-cols-1.md\:grid-cols-3.gap-4 {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form Labels */
|
||||||
|
.block.text-sm.font-medium.text-gray-700.mb-2 {
|
||||||
|
margin-bottom: 0.5rem !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Form Inputs and Selects */
|
||||||
|
.w-full.px-3.py-2 {
|
||||||
|
padding: 0.75rem !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advanced Search Buttons - Mobile Override */
|
||||||
|
.flex.flex-wrap.gap-3 {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: 1fr 1fr !important;
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide Reset button on mobile */
|
||||||
|
.flex.flex-wrap.gap-3 button:nth-child(3) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style remaining buttons */
|
||||||
|
.flex.flex-wrap.gap-3 button:nth-child(1),
|
||||||
|
.flex.flex-wrap.gap-3 button:nth-child(2) {
|
||||||
|
width: 100% !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
padding: 0.75rem 0.5rem !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content Grid - Stack on mobile */
|
||||||
|
.grid.grid-cols-1.lg\:grid-cols-3.gap-6 {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
gap: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Results Section */
|
||||||
|
.lg\:col-span-2 {
|
||||||
|
grid-column: span 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search Results Container */
|
||||||
|
#resultsSection .bg-white.rounded-2xl {
|
||||||
|
padding: 1rem !important;
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search Results Header */
|
||||||
|
#resultsSection .flex.items-center.justify-between {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
gap: 1rem !important;
|
||||||
|
margin-bottom: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resultsSection .flex.items-center.justify-between h3 {
|
||||||
|
font-size: 1.25rem !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Results Count and Controls */
|
||||||
|
#resultsSection .flex.items-center.gap-2 {
|
||||||
|
width: 100% !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
flex-wrap: wrap !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resultsCount {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
color: #059669 !important;
|
||||||
|
background: #ecfdf5 !important;
|
||||||
|
padding: 0.25rem 0.5rem !important;
|
||||||
|
border-radius: 0.375rem !important;
|
||||||
|
border: 1px solid #a7f3d0 !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
order: 1 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort Dropdown */
|
||||||
|
#sortBy {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
padding: 0.5rem !important;
|
||||||
|
order: 2 !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
min-width: 120px !important;
|
||||||
|
background: white !important;
|
||||||
|
border: 1px solid #d1d5db !important;
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sortBy:focus {
|
||||||
|
border-color: #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Export Button */
|
||||||
|
.bg-gray-100.hover\:bg-gray-200 {
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
padding: 0.5rem 0.75rem !important;
|
||||||
|
order: 3 !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
background: #f3f4f6 !important;
|
||||||
|
border: 1px solid #d1d5db !important;
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
transition: all 0.15s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== SEARCH RESULTS MOBILE STYLING ===== */
|
||||||
|
|
||||||
|
/* Main search results container */
|
||||||
|
#results {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
gap: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual result cards - SIMPLE DESKTOP-LIKE LAYOUT */
|
||||||
|
#results > div {
|
||||||
|
border: 1px solid #e5e7eb !important;
|
||||||
|
border-radius: 0.5rem !important;
|
||||||
|
padding: 1rem !important;
|
||||||
|
margin-bottom: 0.75rem !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06) !important;
|
||||||
|
transition: all 0.2s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Company header with flag and name - KEEP DESKTOP LAYOUT */
|
||||||
|
#results .flex.items-center.gap-3 {
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
margin-bottom: 0.75rem !important;
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flag element */
|
||||||
|
#results .w-8.h-6 {
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
width: 2rem !important;
|
||||||
|
height: 1.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Company name */
|
||||||
|
#results .text-base.font-bold,
|
||||||
|
#results .text-lg.font-bold {
|
||||||
|
flex: 1 !important;
|
||||||
|
font-size: 1rem !important;
|
||||||
|
line-height: 1.3 !important;
|
||||||
|
word-break: break-word !important;
|
||||||
|
color: #1f2937 !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contact information section - KEEP DESKTOP STRUCTURE */
|
||||||
|
#results .space-y-2 {
|
||||||
|
margin-top: 0.75rem !important;
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual contact items - CLEAN ROWS LIKE DESKTOP */
|
||||||
|
#results .flex.items-center.gap-2,
|
||||||
|
#results .flex.items-start.gap-2 {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
align-items: center !important;
|
||||||
|
padding: 0.25rem 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons - ensure they display properly */
|
||||||
|
#results .fas,
|
||||||
|
#results .fa {
|
||||||
|
width: 1rem !important;
|
||||||
|
text-align: center !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
margin-right: 0.5rem !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icon colors - same as desktop */
|
||||||
|
#results .fa-phone { color: #059669 !important; }
|
||||||
|
#results .fa-envelope { color: #2563eb !important; }
|
||||||
|
#results .fa-globe { color: #7c3aed !important; }
|
||||||
|
#results .fa-map-marker-alt { color: #dc2626 !important; }
|
||||||
|
|
||||||
|
/* Contact text */
|
||||||
|
#results .flex.items-center.gap-2 span,
|
||||||
|
#results .flex.items-center.gap-2 a,
|
||||||
|
#results .flex.items-start.gap-2 span {
|
||||||
|
word-break: break-word !important;
|
||||||
|
line-height: 1.3 !important;
|
||||||
|
font-size: 0.875rem !important;
|
||||||
|
flex: 1 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text colors - same as desktop */
|
||||||
|
#results .text-green-600 { color: #059669 !important; }
|
||||||
|
#results .text-blue-600 { color: #2563eb !important; }
|
||||||
|
#results .text-purple-600 { color: #7c3aed !important; }
|
||||||
|
#results .text-gray-600 { color: #4b5563 !important; }
|
||||||
|
#results .text-blue-700 { color: #1d4ed8 !important; }
|
||||||
|
|
||||||
|
/* Product tags - same as desktop structure */
|
||||||
|
#results .flex.flex-wrap.gap-1 {
|
||||||
|
margin-top: 0.75rem !important;
|
||||||
|
gap: 0.375rem !important;
|
||||||
|
padding-top: 0.75rem !important;
|
||||||
|
border-top: 1px solid #f3f4f6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Product tag styling - same as desktop */
|
||||||
|
#results .bg-blue-50,
|
||||||
|
#results .bg-blue-100 {
|
||||||
|
font-size: 0.75rem !important;
|
||||||
|
padding: 0.25rem 0.5rem !important;
|
||||||
|
background: linear-gradient(135deg, #dbeafe, #bfdbfe) !important;
|
||||||
|
color: #1e40af !important;
|
||||||
|
border: 1px solid #93c5fd !important;
|
||||||
|
border-radius: 9999px !important;
|
||||||
|
display: inline-block !important;
|
||||||
|
margin: 0.25rem 0.25rem 0.25rem 0 !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover effects - same as desktop */
|
||||||
|
#results > div:hover {
|
||||||
|
transform: translateY(-2px) !important;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove hover effects on contact items */
|
||||||
|
#results .flex.items-center.gap-2:hover,
|
||||||
|
#results .flex.items-start.gap-2:hover {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links - ensure they're touch-friendly */
|
||||||
|
#results a {
|
||||||
|
min-height: 32px !important;
|
||||||
|
display: inline-flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#results a:hover {
|
||||||
|
opacity: 0.8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRUD Wrench Button */
|
||||||
|
.fixed.bottom-6.right-6 {
|
||||||
|
bottom: 1rem !important;
|
||||||
|
right: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-14.h-14 {
|
||||||
|
width: 3rem !important;
|
||||||
|
height: 3rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRUD Modal Mobile Adjustments */
|
||||||
|
.max-w-4xl {
|
||||||
|
max-width: calc(100vw - 2rem) !important;
|
||||||
|
margin: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-h-\[90vh\] {
|
||||||
|
max-height: calc(100vh - 2rem) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRUD Modal Content */
|
||||||
|
.p-6 {
|
||||||
|
padding: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRUD Form Grids */
|
||||||
|
.grid.grid-cols-1.md\:grid-cols-2.gap-4 {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
gap: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toast Notifications */
|
||||||
|
.fixed.top-4.right-4 {
|
||||||
|
top: 1rem !important;
|
||||||
|
right: 1rem !important;
|
||||||
|
left: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-w-sm {
|
||||||
|
max-width: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very small screens */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
#results > div {
|
||||||
|
padding: 0.875rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#results .text-base.font-bold,
|
||||||
|
#results .text-lg.font-bold {
|
||||||
|
font-size: 0.9375rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#results .flex.items-center.gap-2 span,
|
||||||
|
#results .flex.items-center.gap-2 a {
|
||||||
|
font-size: 0.8125rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet and larger screens */
|
||||||
|
@media (min-width: 769px) and (max-width: 1024px) {
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1025px) {
|
||||||
|
.service-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IMMEDIATE MOBILE FIXES - Add to end of styles.css */
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
/* Fix search button staying inline with input */
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 {
|
||||||
|
flex-direction: row !important;
|
||||||
|
align-items: stretch !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 .flex-1 {
|
||||||
|
flex: 1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 button {
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 50px !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
padding: 0.875rem 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide button text on mobile, show only icon */
|
||||||
|
.flex.flex-col.sm\:flex-row.gap-3.mb-4 button span {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix advanced search buttons */
|
||||||
|
.flex.flex-wrap.gap-3 {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: 1fr 1fr !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide reset button on mobile for cleaner look */
|
||||||
|
.flex.flex-wrap.gap-3 button:nth-child(3) {
|
||||||
|
grid-column: span 2 !important;
|
||||||
|
font-size: 0.8rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix modal sizing */
|
||||||
|
.max-w-4xl, .max-w-2xl {
|
||||||
|
max-width: calc(100vw - 1rem) !important;
|
||||||
|
margin: 0.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Improve touch targets */
|
||||||
|
button, .cursor-pointer {
|
||||||
|
min-height: 44px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Very small screens (phones in portrait) */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.px-4 {
|
||||||
|
padding-left: 0.75rem !important;
|
||||||
|
padding-right: 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-3xl, .text-4xl {
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
line-height: 1.3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack stats in 2x2 grid instead of 4x1 */
|
||||||
|
.grid.grid-cols-2.lg\:grid-cols-4 {
|
||||||
|
grid-template-columns: repeat(2, 1fr) !important;
|
||||||
|
gap: 0.5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Searchable Country Dropdown Styles - Add to end of styles.css */
|
||||||
|
|
||||||
|
/* Input with search icon */
|
||||||
|
.relative input[id$="_input"] {
|
||||||
|
padding-right: 2.5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search icon positioning */
|
||||||
|
.relative .absolute.right-3 {
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown menu */
|
||||||
|
.relative .absolute.z-20 {
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||||
|
background: white;
|
||||||
|
max-height: 12rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown options */
|
||||||
|
.relative .absolute.z-20 > div {
|
||||||
|
padding: 0.75rem;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
border-bottom: 1px solid #f3f4f6;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20 > div:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20 > div:hover {
|
||||||
|
background-color: #eff6ff;
|
||||||
|
color: #1d4ed8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Highlighted option (keyboard navigation) */
|
||||||
|
.relative .absolute.z-20 > div.bg-blue-100 {
|
||||||
|
background-color: #dbeafe !important;
|
||||||
|
color: #1e40af !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom scrollbar for dropdown */
|
||||||
|
.relative .absolute.z-20::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20::-webkit-scrollbar-track {
|
||||||
|
background: #f1f5f9;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20::-webkit-scrollbar-thumb {
|
||||||
|
background: #cbd5e1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile improvements */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.relative input[id$="_input"] {
|
||||||
|
font-size: 16px !important; /* Prevents zoom on iOS */
|
||||||
|
padding: 0.875rem 2.5rem 0.875rem 0.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20 > div {
|
||||||
|
padding: 1rem 0.75rem;
|
||||||
|
min-height: 44px; /* Better touch targets */
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relative .absolute.z-20 {
|
||||||
|
max-height: 10rem; /* Smaller on mobile */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focus styles for accessibility */
|
||||||
|
.relative input[id$="_input"]:focus {
|
||||||
|
outline: none !important;
|
||||||
|
border-color: #3b82f6 !important;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Animation for icon change */
|
||||||
|
.relative .absolute.right-3 i {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
198
assets/js/calendar-agent.js
Normal file
198
assets/js/calendar-agent.js
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/**
|
||||||
|
* Calendar Agent Specific Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CalendarAgent {
|
||||||
|
constructor() {
|
||||||
|
this.totalActions = 0;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
Utils.time.updateLastUpdated('lastSync');
|
||||||
|
this.initializeEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeEventListeners() {
|
||||||
|
Utils.events.onEnterKey('calendarCommand', () => this.executeCalendarCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
setCalendarCommand(command) {
|
||||||
|
Utils.form.setInputValue('calendarCommand', command);
|
||||||
|
this.executeCalendarCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeCalendarCommand() {
|
||||||
|
const command = Utils.form.getInputValue('calendarCommand');
|
||||||
|
if (!command) {
|
||||||
|
Utils.toast.warning('Please enter a command');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils.button.setLoading('calendarAiBtn', 'Processing...', 'fa-spinner fa-spin');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Simulate AI processing
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
|
|
||||||
|
const response = this.generateCalendarAIResponse(command);
|
||||||
|
Utils.modal.showAI(response);
|
||||||
|
|
||||||
|
this.updateCalendarStats();
|
||||||
|
Utils.time.updateLastUpdated('lastSync');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
Utils.toast.error('Error processing command: ' + error.message);
|
||||||
|
} finally {
|
||||||
|
Utils.button.restore('calendarAiBtn', 'Execute', 'fa-robot');
|
||||||
|
Utils.form.clearInput('calendarCommand');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateCalendarAIResponse(command) {
|
||||||
|
const lowerCommand = command.toLowerCase();
|
||||||
|
|
||||||
|
if (lowerCommand.includes('schedule') && lowerCommand.includes('meeting')) {
|
||||||
|
return `
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">📅 Schedule Meeting</h4>
|
||||||
|
<div class="bg-green-50 border border-green-200 p-4 rounded-lg">
|
||||||
|
<h5 class="font-medium text-green-800 mb-2">✅ Optimal Time Found</h5>
|
||||||
|
<p class="text-sm text-green-700 mb-3">Best time for all attendees: <strong>Tomorrow 3:30 PM - 4:30 PM</strong></p>
|
||||||
|
<div class="space-y-2 text-sm text-green-700">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fas fa-users text-green-600"></i>
|
||||||
|
<span>5 attendees available</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fas fa-map-marker-alt text-green-600"></i>
|
||||||
|
<span>Conference Room B reserved</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fas fa-video text-green-600"></i>
|
||||||
|
<span>Zoom link generated</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-blue-50 border border-blue-200 p-4 rounded-lg">
|
||||||
|
<h5 class="font-medium text-blue-800 mb-2">📋 Meeting Details</h5>
|
||||||
|
<div class="space-y-2 text-sm text-blue-700">
|
||||||
|
<p><strong>Title:</strong> Team Strategy Discussion</p>
|
||||||
|
<p><strong>Duration:</strong> 1 hour</p>
|
||||||
|
<p><strong>Attendees:</strong> Sarah, John, Mike, Lisa, David</p>
|
||||||
|
<p><strong>Agenda:</strong> Q1 planning and resource allocation</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="flex-1 bg-green-600 text-white py-2 px-4 rounded-lg hover:bg-green-700 transition-colors">Confirm & Send Invites</button>
|
||||||
|
<button class="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">Modify Details</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">🤖 Calendar AI Response</h4>
|
||||||
|
<div class="bg-green-50 border border-green-200 p-4 rounded-lg">
|
||||||
|
<p class="text-green-700">Processing your request: "<em>${command}</em>"</p>
|
||||||
|
<p class="text-sm text-green-600 mt-2">I can help you with:</p>
|
||||||
|
<ul class="mt-3 space-y-1 text-sm text-green-700">
|
||||||
|
<li>• Smart meeting scheduling and optimization</li>
|
||||||
|
<li>• Finding optimal free time slots</li>
|
||||||
|
<li>• Conflict detection and resolution</li>
|
||||||
|
<li>• Focus time blocking and protection</li>
|
||||||
|
<li>• Calendar analysis and insights</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCalendarStats() {
|
||||||
|
Utils.stats.increment('aiScheduled');
|
||||||
|
this.totalActions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick action functions
|
||||||
|
scheduleMeeting() {
|
||||||
|
Utils.modal.showAI(`
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">📅 Schedule New Meeting</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Meeting Title:</label>
|
||||||
|
<input type="text" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" placeholder="Team Strategy Discussion">
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Date:</label>
|
||||||
|
<input type="date" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Duration:</label>
|
||||||
|
<select class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500">
|
||||||
|
<option value="30">30 minutes</option>
|
||||||
|
<option value="60" selected>1 hour</option>
|
||||||
|
<option value="90">1.5 hours</option>
|
||||||
|
<option value="120">2 hours</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Attendees:</label>
|
||||||
|
<input type="text" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" placeholder="sarah@company.com, john@company.com">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Meeting Type:</label>
|
||||||
|
<div class="grid grid-cols-2 gap-3">
|
||||||
|
<label class="flex items-center p-3 border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50">
|
||||||
|
<input type="radio" name="meetingType" value="inPerson" class="mr-2">
|
||||||
|
<span class="text-sm">In-Person</span>
|
||||||
|
</label>
|
||||||
|
<label class="flex items-center p-3 border border-gray-300 rounded-lg cursor-pointer hover:bg-gray-50">
|
||||||
|
<input type="radio" name="meetingType" value="virtual" class="mr-2" checked>
|
||||||
|
<span class="text-sm">Virtual</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full bg-green-600 text-white py-3 px-4 rounded-lg hover:bg-green-700 transition-colors font-medium">
|
||||||
|
🤖 Find Optimal Time & Schedule
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
findFreeTime() {
|
||||||
|
this.updateCalendarStats();
|
||||||
|
Utils.toast.info('🔍 Found 3 optimal time slots this week for your requirements');
|
||||||
|
}
|
||||||
|
|
||||||
|
blockFocusTime() {
|
||||||
|
this.updateCalendarStats();
|
||||||
|
Utils.toast.success('🧠 Protected 2-hour focus block scheduled for tomorrow 10-12 AM');
|
||||||
|
}
|
||||||
|
|
||||||
|
optimizeSchedule() {
|
||||||
|
if (confirm('Let AI optimize your schedule for maximum productivity?')) {
|
||||||
|
this.updateCalendarStats();
|
||||||
|
Utils.toast.success('✨ Schedule optimized! Moved 3 meetings to create better focus blocks and reduced meeting fragmentation by 40%.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Calendar Agent when DOM is loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
window.calendarAgent = new CalendarAgent();
|
||||||
|
|
||||||
|
// Make functions globally available for onclick handlers
|
||||||
|
window.executeCalendarCommand = () => calendarAgent.executeCalendarCommand();
|
||||||
|
window.setCalendarCommand = (cmd) => calendarAgent.setCalendarCommand(cmd);
|
||||||
|
window.scheduleMeeting = () => calendarAgent.scheduleMeeting();
|
||||||
|
window.findFreeTime = () => calendarAgent.findFreeTime();
|
||||||
|
window.blockFocusTime = () => calendarAgent.blockFocusTime();
|
||||||
|
window.optimizeSchedule = () => calendarAgent.optimizeSchedule();
|
||||||
|
window.closeAIModal = () => Utils.modal.hideAI();
|
||||||
|
window.goHome = () => Utils.navigation.goHome();
|
||||||
|
});
|
||||||
546
assets/js/email-agent.js
Normal file
546
assets/js/email-agent.js
Normal file
@ -0,0 +1,546 @@
|
|||||||
|
/**
|
||||||
|
* Email Agent - Webhook Integration
|
||||||
|
* Connects to your n8n email analysis workflow
|
||||||
|
*/
|
||||||
|
|
||||||
|
class EmailAgent {
|
||||||
|
constructor() {
|
||||||
|
this.apiEndpoint = 'https://thecyberlearn.app.n8n.cloud/webhook/email-agent';
|
||||||
|
this.currentEmails = [];
|
||||||
|
this.currentFilter = 'all';
|
||||||
|
this.totalActions = 0;
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.updateLastSync();
|
||||||
|
this.initializeEventListeners();
|
||||||
|
this.loadEmails(); // Auto-load emails on page load
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeEventListeners() {
|
||||||
|
// Search on Enter key
|
||||||
|
const searchInput = document.getElementById('searchQuery');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.searchEmails();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLastSync() {
|
||||||
|
const element = document.getElementById('lastSync');
|
||||||
|
if (element) {
|
||||||
|
element.textContent = new Date().toLocaleTimeString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function to load emails from webhook
|
||||||
|
async loadEmails(action = 'get_inbox', params = {}) {
|
||||||
|
const loadingState = document.getElementById('loadingState');
|
||||||
|
const emailList = document.getElementById('emailList');
|
||||||
|
const emptyState = document.getElementById('emptyState');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Show loading state
|
||||||
|
this.showLoading(true);
|
||||||
|
|
||||||
|
// Build API URL
|
||||||
|
const url = new URL(this.apiEndpoint);
|
||||||
|
url.searchParams.append('action', action);
|
||||||
|
|
||||||
|
// Add additional parameters
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
if (params[key]) {
|
||||||
|
url.searchParams.append(key, params[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Loading emails from:', url.toString());
|
||||||
|
|
||||||
|
const response = await fetch(url.toString());
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Email data received:', data);
|
||||||
|
|
||||||
|
if (data.success && data.emails) {
|
||||||
|
this.currentEmails = data.emails;
|
||||||
|
this.displayEmails(data.emails);
|
||||||
|
this.updateStats(data);
|
||||||
|
this.addToRecentActivity(`Loaded ${data.emails.length} emails`, 'load');
|
||||||
|
|
||||||
|
// Hide empty state, show email list
|
||||||
|
if (emptyState) emptyState.classList.add('hidden');
|
||||||
|
if (emailList) emailList.classList.remove('hidden');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.showEmptyState();
|
||||||
|
console.log('No emails found or API error');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading emails:', error);
|
||||||
|
this.showError('Failed to load emails: ' + error.message);
|
||||||
|
} finally {
|
||||||
|
this.showLoading(false);
|
||||||
|
this.updateLastSync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display emails in the UI
|
||||||
|
displayEmails(emails) {
|
||||||
|
const emailList = document.getElementById('emailList');
|
||||||
|
if (!emailList) return;
|
||||||
|
|
||||||
|
if (emails.length === 0) {
|
||||||
|
this.showEmptyState();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailHTML = emails.map((email, index) => {
|
||||||
|
return this.generateEmailCard(email, index);
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
emailList.innerHTML = emailHTML;
|
||||||
|
emailList.classList.remove('hidden');
|
||||||
|
|
||||||
|
// Add click handlers
|
||||||
|
this.attachEmailClickHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate individual email card HTML
|
||||||
|
generateEmailCard(email, index) {
|
||||||
|
const priorityClass = `priority-${email.priority.toLowerCase()}`;
|
||||||
|
const unreadClass = email.unread ? 'email-unread' : 'email-read';
|
||||||
|
const typeIcon = this.getTypeIcon(email.type);
|
||||||
|
const typeColor = this.getTypeColor(email.type);
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="email-card ${unreadClass} ${priorityClass} p-4 rounded-lg border border-gray-200 cursor-pointer fade-in"
|
||||||
|
onclick="emailAgent.viewEmailDetails('${email.id}')"
|
||||||
|
data-email-id="${email.id}">
|
||||||
|
|
||||||
|
<div class="flex items-start justify-between mb-3">
|
||||||
|
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||||
|
<!-- Type Icon -->
|
||||||
|
<div class="w-8 h-8 bg-${typeColor}-100 rounded-lg flex items-center justify-center flex-shrink-0">
|
||||||
|
<i class="${typeIcon} text-${typeColor}-600"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sender & Subject -->
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<div class="flex items-center gap-2 mb-1">
|
||||||
|
<span class="font-semibold text-gray-800 truncate">${email.sender}</span>
|
||||||
|
${email.priority === 'High' ? '<span class="px-2 py-1 bg-red-100 text-red-700 text-xs rounded-full">High Priority</span>' : ''}
|
||||||
|
${email.priority === 'Medium' ? '<span class="px-2 py-1 bg-orange-100 text-orange-700 text-xs rounded-full">Medium</span>' : ''}
|
||||||
|
${email.unread ? '<span class="w-2 h-2 bg-blue-500 rounded-full"></span>' : ''}
|
||||||
|
</div>
|
||||||
|
<h4 class="font-medium text-gray-800 mb-1 line-clamp-1">${email.subject}</h4>
|
||||||
|
<p class="text-sm text-gray-600 line-clamp-2">${email.summary}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Time & Actions -->
|
||||||
|
<div class="text-right ml-4 flex-shrink-0">
|
||||||
|
<div class="text-sm text-gray-500 mb-1">${email.timestamp}</div>
|
||||||
|
<div class="flex items-center gap-1 justify-end">
|
||||||
|
${email.attachments > 0 ? `<i class="fas fa-paperclip text-gray-400 text-xs"></i><span class="text-xs text-gray-500">${email.attachments}</span>` : ''}
|
||||||
|
<span class="text-xs px-2 py-1 bg-${typeColor}-50 text-${typeColor}-700 rounded">${email.type.toUpperCase()}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="flex gap-2 pt-2 border-t border-gray-100">
|
||||||
|
<button onclick="event.stopPropagation(); emailAgent.viewEmailDetails('${email.id}')"
|
||||||
|
class="flex-1 text-xs bg-blue-600 text-white py-2 px-3 rounded-lg hover:bg-blue-700 transition-colors">
|
||||||
|
View Details
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); emailAgent.markAsRead('${email.id}')"
|
||||||
|
class="text-xs px-3 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
|
||||||
|
${email.unread ? 'Mark Read' : 'Mark Unread'}
|
||||||
|
</button>
|
||||||
|
<button onclick="event.stopPropagation(); emailAgent.shareEmail('${email.id}')"
|
||||||
|
class="text-xs px-3 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">
|
||||||
|
<i class="fas fa-share"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get type icon for email type
|
||||||
|
getTypeIcon(type) {
|
||||||
|
const icons = {
|
||||||
|
'email': 'fas fa-envelope',
|
||||||
|
'pdf': 'fas fa-file-pdf',
|
||||||
|
'image': 'fas fa-image'
|
||||||
|
};
|
||||||
|
return icons[type] || 'fas fa-file';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get type color for email type
|
||||||
|
getTypeColor(type) {
|
||||||
|
const colors = {
|
||||||
|
'email': 'blue',
|
||||||
|
'pdf': 'red',
|
||||||
|
'image': 'green'
|
||||||
|
};
|
||||||
|
return colors[type] || 'gray';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search emails
|
||||||
|
async searchEmails() {
|
||||||
|
const searchQuery = document.getElementById('searchQuery');
|
||||||
|
const query = searchQuery ? searchQuery.value.trim() : '';
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
this.loadEmails(); // Load all if no search query
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.loadEmails('search', { query: query });
|
||||||
|
this.addToRecentActivity(`Searched for "${query}"`, 'search');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter emails by type
|
||||||
|
async filterEmails(type) {
|
||||||
|
this.currentFilter = type;
|
||||||
|
|
||||||
|
// Update filter button styles
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||||
|
btn.classList.remove('active', 'bg-blue-100', 'text-blue-700');
|
||||||
|
btn.classList.add('bg-gray-100', 'text-gray-700');
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeBtn = document.querySelector(`[data-filter="${type}"]`);
|
||||||
|
if (activeBtn) {
|
||||||
|
activeBtn.classList.remove('bg-gray-100', 'text-gray-700');
|
||||||
|
activeBtn.classList.add('active', 'bg-blue-100', 'text-blue-700');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'all') {
|
||||||
|
await this.loadEmails('get_inbox');
|
||||||
|
} else {
|
||||||
|
await this.loadEmails('filter', { type: type });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addToRecentActivity(`Filtered by ${type}`, 'filter');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh emails
|
||||||
|
async refreshEmails() {
|
||||||
|
await this.loadEmails(this.currentFilter === 'all' ? 'get_inbox' : 'filter',
|
||||||
|
this.currentFilter === 'all' ? {} : { type: this.currentFilter });
|
||||||
|
this.addToRecentActivity('Refreshed emails', 'refresh');
|
||||||
|
}
|
||||||
|
|
||||||
|
// View email details in modal
|
||||||
|
viewEmailDetails(emailId) {
|
||||||
|
const email = this.currentEmails.find(e => e.id === emailId);
|
||||||
|
if (!email) return;
|
||||||
|
|
||||||
|
const modal = document.getElementById('emailModal');
|
||||||
|
const content = document.getElementById('emailContent');
|
||||||
|
|
||||||
|
if (!modal || !content) return;
|
||||||
|
|
||||||
|
const detailHTML = `
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Email Header -->
|
||||||
|
<div class="border-b border-gray-200 pb-4">
|
||||||
|
<div class="flex items-center gap-3 mb-3">
|
||||||
|
<div class="w-12 h-12 bg-${this.getTypeColor(email.type)}-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="${this.getTypeIcon(email.type)} text-${this.getTypeColor(email.type)}-600 text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h2 class="text-xl font-bold text-gray-800">${email.subject}</h2>
|
||||||
|
<p class="text-gray-600">From: ${email.sender} (${email.senderEmail})</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<span class="px-3 py-1 bg-${email.priorityColor}-100 text-${email.priorityColor}-700 rounded-full text-sm">
|
||||||
|
${email.priority} Priority
|
||||||
|
</span>
|
||||||
|
<p class="text-sm text-gray-500 mt-1">${email.timestamp}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Content -->
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-2">AI Summary</h3>
|
||||||
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||||
|
<p class="text-blue-800">${email.summary}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${email.fullSummary && email.fullSummary !== email.summary ? `
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 mb-2">Full Analysis</h3>
|
||||||
|
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
|
||||||
|
<p class="text-gray-700 whitespace-pre-wrap">${email.fullSummary}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<!-- Email Meta Info -->
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<h4 class="font-medium text-gray-700 mb-2">AI Analysis</h4>
|
||||||
|
<p class="text-sm text-gray-600">Priority: ${email.priority}</p>
|
||||||
|
<p class="text-sm text-gray-600">Attachments: ${email.attachments}</p>
|
||||||
|
<p class="text-sm text-gray-600">Auto-processed: Yes</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
content.innerHTML = detailHTML;
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
|
||||||
|
this.addToRecentActivity(`Viewed "${email.subject}"`, 'view');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close email modal
|
||||||
|
closeEmailModal() {
|
||||||
|
const modal = document.getElementById('emailModal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark email as read/unread (simulated)
|
||||||
|
markAsRead(emailId) {
|
||||||
|
const email = this.currentEmails.find(e => e.id === emailId);
|
||||||
|
if (email) {
|
||||||
|
email.unread = !email.unread;
|
||||||
|
this.displayEmails(this.currentEmails); // Refresh display
|
||||||
|
this.addToRecentActivity(`Marked "${email.subject}" as ${email.unread ? 'unread' : 'read'}`, 'mark');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Share email (copy to clipboard)
|
||||||
|
shareEmail(emailId) {
|
||||||
|
const email = this.currentEmails.find(e => e.id === emailId);
|
||||||
|
if (email) {
|
||||||
|
const shareText = `${email.subject}\nFrom: ${email.sender}\nSummary: ${email.summary}`;
|
||||||
|
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
navigator.clipboard.writeText(shareText).then(() => {
|
||||||
|
this.showToast('Email details copied to clipboard!', 'success');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback for older browsers
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = shareText;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
this.showToast('Email details copied to clipboard!', 'success');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addToRecentActivity(`Shared "${email.subject}"`, 'share');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export emails to CSV
|
||||||
|
exportEmails() {
|
||||||
|
if (this.currentEmails.length === 0) {
|
||||||
|
this.showToast('No emails to export', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = ['Date', 'Sender', 'Subject', 'Type', 'Priority', 'Summary'];
|
||||||
|
const csvContent = [
|
||||||
|
headers.join(','),
|
||||||
|
...this.currentEmails.map(email => [
|
||||||
|
`"${email.date}"`,
|
||||||
|
`"${email.sender}"`,
|
||||||
|
`"${email.subject}"`,
|
||||||
|
`"${email.type}"`,
|
||||||
|
`"${email.priority}"`,
|
||||||
|
`"${email.summary.replace(/"/g, '""')}"`
|
||||||
|
].join(','))
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const blob = new Blob([csvContent], { type: 'text/csv' });
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `email_summaries_${new Date().toISOString().split('T')[0]}.csv`;
|
||||||
|
a.click();
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
|
||||||
|
this.showToast('Email data exported successfully!', 'success');
|
||||||
|
this.addToRecentActivity(`Exported ${this.currentEmails.length} emails`, 'export');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update statistics
|
||||||
|
updateStats(data) {
|
||||||
|
const stats = data.stats || {};
|
||||||
|
|
||||||
|
// Update stat counters
|
||||||
|
this.updateElement('totalCount', stats.total || this.currentEmails.length);
|
||||||
|
this.updateElement('priorityCount', stats.high_priority || 0);
|
||||||
|
this.updateElement('processedCount', stats.total || this.currentEmails.length);
|
||||||
|
this.updateElement('aiActionsCount', stats.total || this.currentEmails.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to update element text
|
||||||
|
updateElement(id, value) {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add activity to recent activity panel
|
||||||
|
addToRecentActivity(message, type = 'info') {
|
||||||
|
const recentActivity = document.getElementById('recentActivity');
|
||||||
|
if (!recentActivity) return;
|
||||||
|
|
||||||
|
const iconMap = {
|
||||||
|
'load': 'fa-download',
|
||||||
|
'search': 'fa-search',
|
||||||
|
'filter': 'fa-filter',
|
||||||
|
'refresh': 'fa-sync-alt',
|
||||||
|
'view': 'fa-eye',
|
||||||
|
'mark': 'fa-check',
|
||||||
|
'share': 'fa-share',
|
||||||
|
'export': 'fa-file-export'
|
||||||
|
};
|
||||||
|
|
||||||
|
const colorMap = {
|
||||||
|
'load': 'blue',
|
||||||
|
'search': 'green',
|
||||||
|
'filter': 'purple',
|
||||||
|
'refresh': 'orange',
|
||||||
|
'view': 'indigo',
|
||||||
|
'mark': 'green',
|
||||||
|
'share': 'blue',
|
||||||
|
'export': 'red'
|
||||||
|
};
|
||||||
|
|
||||||
|
const icon = iconMap[type] || 'fa-info-circle';
|
||||||
|
const color = colorMap[type] || 'blue';
|
||||||
|
const time = new Date().toLocaleTimeString();
|
||||||
|
|
||||||
|
// Clear default message if exists
|
||||||
|
if (recentActivity.children.length === 1 && recentActivity.textContent.includes('Load emails')) {
|
||||||
|
recentActivity.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const activityItem = document.createElement('div');
|
||||||
|
activityItem.className = 'flex items-start gap-3 p-2 bg-gray-50 rounded-lg fade-in';
|
||||||
|
activityItem.innerHTML = `
|
||||||
|
<div class="w-6 h-6 bg-${color}-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas ${icon} text-${color}-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800 truncate">${message}</p>
|
||||||
|
<p class="text-xs text-gray-500">${time}</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
recentActivity.insertBefore(activityItem, recentActivity.firstChild);
|
||||||
|
|
||||||
|
// Keep only last 5 activities
|
||||||
|
while (recentActivity.children.length > 5) {
|
||||||
|
recentActivity.removeChild(recentActivity.lastChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.totalActions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show/hide loading state
|
||||||
|
showLoading(show) {
|
||||||
|
const loadingState = document.getElementById('loadingState');
|
||||||
|
const emailList = document.getElementById('emailList');
|
||||||
|
|
||||||
|
if (loadingState) {
|
||||||
|
if (show) {
|
||||||
|
loadingState.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
loadingState.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emailList && show) {
|
||||||
|
emailList.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show empty state
|
||||||
|
showEmptyState() {
|
||||||
|
const emailList = document.getElementById('emailList');
|
||||||
|
const emptyState = document.getElementById('emptyState');
|
||||||
|
|
||||||
|
if (emailList) emailList.classList.add('hidden');
|
||||||
|
if (emptyState) emptyState.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show error message
|
||||||
|
showError(message) {
|
||||||
|
this.showToast(message, 'error');
|
||||||
|
this.showEmptyState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toast notification system
|
||||||
|
showToast(message, type = 'info') {
|
||||||
|
const colors = {
|
||||||
|
success: 'bg-green-100 border-green-300 text-green-800',
|
||||||
|
error: 'bg-red-100 border-red-300 text-red-800',
|
||||||
|
warning: 'bg-yellow-100 border-yellow-300 text-yellow-800',
|
||||||
|
info: 'bg-blue-100 border-blue-300 text-blue-800'
|
||||||
|
};
|
||||||
|
|
||||||
|
const icons = {
|
||||||
|
success: 'fa-check-circle',
|
||||||
|
error: 'fa-times-circle',
|
||||||
|
warning: 'fa-exclamation-triangle',
|
||||||
|
info: 'fa-info-circle'
|
||||||
|
};
|
||||||
|
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.className = `fixed bottom-4 right-4 z-50 ${colors[type]} border rounded-lg shadow-lg p-4 max-w-sm`;
|
||||||
|
toast.innerHTML = `
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<i class="fas ${icons[type]} text-lg"></i>
|
||||||
|
<span class="font-medium">${message}</span>
|
||||||
|
<button onclick="this.parentElement.parentElement.remove()" class="ml-auto text-lg hover:opacity-70">×</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
setTimeout(() => toast.remove(), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach click handlers to email cards
|
||||||
|
attachEmailClickHandlers() {
|
||||||
|
// Click handlers are already in the HTML via onclick attributes
|
||||||
|
// This method can be used for additional event handling if needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Email Agent when DOM is loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
window.emailAgent = new EmailAgent();
|
||||||
|
|
||||||
|
// Make functions globally available for onclick handlers
|
||||||
|
window.loadEmails = () => emailAgent.loadEmails();
|
||||||
|
window.searchEmails = () => emailAgent.searchEmails();
|
||||||
|
window.filterEmails = (type) => emailAgent.filterEmails(type);
|
||||||
|
window.refreshEmails = () => emailAgent.refreshEmails();
|
||||||
|
window.exportEmails = () => emailAgent.exportEmails();
|
||||||
|
window.closeEmailModal = () => emailAgent.closeEmailModal();
|
||||||
|
|
||||||
|
});
|
||||||
177
assets/js/index.js
Normal file
177
assets/js/index.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/**
|
||||||
|
* Main Index Page Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AIServicesHub {
|
||||||
|
constructor() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.addAnimations();
|
||||||
|
this.initializeEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeEventListeners() {
|
||||||
|
// Service card click handlers are handled via onclick attributes
|
||||||
|
// But we can add keyboard navigation here if needed
|
||||||
|
this.addKeyboardNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
|
addAnimations() {
|
||||||
|
// Add staggered animation to service cards
|
||||||
|
const cards = document.querySelectorAll('.service-card');
|
||||||
|
cards.forEach((card, index) => {
|
||||||
|
card.style.animationDelay = `${index * 0.1}s`;
|
||||||
|
card.classList.add('opacity-0');
|
||||||
|
setTimeout(() => {
|
||||||
|
card.style.animation = 'fadeInUp 0.6s ease-out forwards';
|
||||||
|
card.classList.remove('opacity-0');
|
||||||
|
}, index * 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addKeyboardNavigation() {
|
||||||
|
// Add keyboard navigation for service cards
|
||||||
|
const serviceCards = document.querySelectorAll('.service-card');
|
||||||
|
serviceCards.forEach((card, index) => {
|
||||||
|
card.setAttribute('tabindex', '0');
|
||||||
|
card.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
card.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToService(service) {
|
||||||
|
// Map service names to actual HTML files
|
||||||
|
const serviceUrls = {
|
||||||
|
'trade-intelligence': 'trade-intelligence.html',
|
||||||
|
'email-agent': 'email-agent.html',
|
||||||
|
'calendar-agent': 'calendar-agent.html',
|
||||||
|
'task-agent': 'task-agent.html'
|
||||||
|
};
|
||||||
|
|
||||||
|
const url = serviceUrls[service];
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
// Check if file exists by trying to navigate
|
||||||
|
try {
|
||||||
|
window.location.href = url;
|
||||||
|
} catch (error) {
|
||||||
|
// Fallback to showing information if file doesn't exist
|
||||||
|
this.showServiceInfo(service);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.showServiceInfo(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showServiceInfo(service) {
|
||||||
|
const services = {
|
||||||
|
'trade-intelligence': {
|
||||||
|
name: 'Trade Intelligence',
|
||||||
|
description: 'Find exporters, importers, and trade data from around the world',
|
||||||
|
features: ['50K+ Companies', '150+ Countries', 'Real-time Search', 'Export Data'],
|
||||||
|
icon: 'fas fa-ship',
|
||||||
|
color: 'blue'
|
||||||
|
},
|
||||||
|
'email-agent': {
|
||||||
|
name: 'Email Agent',
|
||||||
|
description: 'Smart email management and summarization with AI',
|
||||||
|
features: ['Email Summarization', 'Priority Detection', 'Auto-categorization', 'Smart Replies'],
|
||||||
|
icon: 'fas fa-envelope',
|
||||||
|
color: 'purple'
|
||||||
|
},
|
||||||
|
'calendar-agent': {
|
||||||
|
name: 'Calendar Agent',
|
||||||
|
description: 'Intelligent scheduling and meeting management',
|
||||||
|
features: ['Smart Scheduling', 'Conflict Detection', 'Meeting Optimization', 'Time Blocking'],
|
||||||
|
icon: 'fas fa-calendar',
|
||||||
|
color: 'green'
|
||||||
|
},
|
||||||
|
'task-agent': {
|
||||||
|
name: 'Task Agent',
|
||||||
|
description: 'Smart task management and prioritization',
|
||||||
|
features: ['AI Prioritization', 'Progress Tracking', 'Deadline Management', 'Workload Balancing'],
|
||||||
|
icon: 'fas fa-tasks',
|
||||||
|
color: 'orange'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const serviceData = services[service];
|
||||||
|
if (serviceData) {
|
||||||
|
Utils.modal.show('demoModal', `
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-16 h-16 bg-${serviceData.color}-100 rounded-xl flex items-center justify-center mx-auto mb-4">
|
||||||
|
<i class="${serviceData.icon} text-${serviceData.color}-600 text-2xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-bold text-gray-800 mb-2">${serviceData.name}</h3>
|
||||||
|
<p class="text-gray-600 mb-6">${serviceData.description}</p>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-3 mb-6">
|
||||||
|
${serviceData.features.map(feature => `
|
||||||
|
<div class="bg-${serviceData.color}-50 p-3 rounded-lg">
|
||||||
|
<p class="text-sm text-${serviceData.color}-700 font-medium">${feature}</p>
|
||||||
|
</div>
|
||||||
|
`).join('')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<p class="text-sm text-gray-600">
|
||||||
|
<strong>Coming Soon!</strong><br>
|
||||||
|
This agent is currently in development.
|
||||||
|
<br>Check back soon for the full experience.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showDemo() {
|
||||||
|
Utils.modal.show('demoModal');
|
||||||
|
}
|
||||||
|
|
||||||
|
showDocumentation() {
|
||||||
|
Utils.modal.show('docModal');
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDemoModal() {
|
||||||
|
Utils.modal.hide('demoModal');
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDocModal() {
|
||||||
|
Utils.modal.hide('docModal');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CSS for fade in animation
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(30px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
|
// Initialize when DOM is loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
window.aiServicesHub = new AIServicesHub();
|
||||||
|
|
||||||
|
// Make functions globally available for onclick handlers
|
||||||
|
window.navigateToService = (service) => aiServicesHub.navigateToService(service);
|
||||||
|
window.showDemo = () => aiServicesHub.showDemo();
|
||||||
|
window.showDocumentation = () => aiServicesHub.showDocumentation();
|
||||||
|
window.closeDemoModal = () => aiServicesHub.closeDemoModal();
|
||||||
|
window.closeDocModal = () => aiServicesHub.closeDocModal();
|
||||||
|
});
|
||||||
45
assets/js/navigation.js
Normal file
45
assets/js/navigation.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Minimal Navigation Component
|
||||||
|
* Only creates breadcrumbs for your existing HTML
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
createBreadcrumbs();
|
||||||
|
});
|
||||||
|
|
||||||
|
function createBreadcrumbs() {
|
||||||
|
const breadcrumbContainer = document.querySelector('.breadcrumbs');
|
||||||
|
if (!breadcrumbContainer) return;
|
||||||
|
|
||||||
|
// Detect current page
|
||||||
|
const path = window.location.pathname;
|
||||||
|
const filename = path.split('/').pop() || 'index.html';
|
||||||
|
const currentPage = filename.replace('.html', '');
|
||||||
|
|
||||||
|
const pages = {
|
||||||
|
'index': { name: 'Home', icon: 'fas fa-home' },
|
||||||
|
'trade-intelligence': { name: 'Trade Intelligence', icon: 'fas fa-ship' },
|
||||||
|
'email-agent': { name: 'Email Agent', icon: 'fas fa-envelope' },
|
||||||
|
'calendar-agent': { name: 'Calendar Agent', icon: 'fas fa-calendar' },
|
||||||
|
'task-agent': { name: 'Task Agent', icon: 'fas fa-tasks' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentPageInfo = pages[currentPage];
|
||||||
|
if (!currentPageInfo) return;
|
||||||
|
|
||||||
|
breadcrumbContainer.innerHTML = `
|
||||||
|
<div class="flex items-center space-x-2 text-sm">
|
||||||
|
<a href="index.html" class="text-indigo-600 hover:text-indigo-800 flex items-center gap-1 transition-colors">
|
||||||
|
<i class="fas fa-home"></i>
|
||||||
|
<span>Home</span>
|
||||||
|
</a>
|
||||||
|
${currentPage !== 'index' ? `
|
||||||
|
<i class="fas fa-chevron-right text-gray-400"></i>
|
||||||
|
<span class="text-gray-600 flex items-center gap-1">
|
||||||
|
<i class="${currentPageInfo.icon}"></i>
|
||||||
|
<span>${currentPageInfo.name}</span>
|
||||||
|
</span>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
887
assets/js/task-agent.js
Normal file
887
assets/js/task-agent.js
Normal file
@ -0,0 +1,887 @@
|
|||||||
|
/**
|
||||||
|
* Task Agent Specific Functions - Fixed Version
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TaskAgent {
|
||||||
|
constructor() {
|
||||||
|
this.totalActions = 0;
|
||||||
|
this.tasks = [];
|
||||||
|
this.stats = {
|
||||||
|
total: 0,
|
||||||
|
overdue: 0,
|
||||||
|
dueToday: 0,
|
||||||
|
completed: 0,
|
||||||
|
inProgress: 0,
|
||||||
|
toDo: 0
|
||||||
|
};
|
||||||
|
// Set default API URL - you can override this
|
||||||
|
this.apiUrl = 'https://thecyberlearn.app.n8n.cloud/webhook/tasks';
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// Wait for DOM to be ready
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', () => this.initializeAfterDOM());
|
||||||
|
} else {
|
||||||
|
this.initializeAfterDOM();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeAfterDOM() {
|
||||||
|
this.updateLastUpdated('lastUpdate');
|
||||||
|
this.initializeEventListeners();
|
||||||
|
|
||||||
|
// Load sample tasks if API URL is not configured
|
||||||
|
if (this.apiUrl.includes('your-n8n-instance.com')) {
|
||||||
|
console.log('Using sample data - configure apiUrl for real data');
|
||||||
|
this.loadSampleTasks();
|
||||||
|
} else {
|
||||||
|
this.loadTasks(); // Load tasks from API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLastUpdated(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = new Date().toLocaleTimeString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeEventListeners() {
|
||||||
|
const taskCommandInput = document.getElementById('taskCommand');
|
||||||
|
if (taskCommandInput) {
|
||||||
|
taskCommandInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.executeTaskCommand();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchInput = document.getElementById('taskSearchInput');
|
||||||
|
if (searchInput) {
|
||||||
|
searchInput.addEventListener('keypress', (e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.handleSearch();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTaskCommand(command) {
|
||||||
|
const element = document.getElementById('taskCommand');
|
||||||
|
if (element) {
|
||||||
|
element.value = command;
|
||||||
|
this.executeTaskCommand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeTaskCommand() {
|
||||||
|
const element = document.getElementById('taskCommand');
|
||||||
|
const command = element ? element.value : '';
|
||||||
|
|
||||||
|
if (!command) {
|
||||||
|
this.showToast('Please enter a command', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setButtonLoading('taskAiBtn', 'Processing...', 'fa-spinner fa-spin');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Simulate AI processing
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
|
|
||||||
|
const response = this.generateTaskAIResponse(command);
|
||||||
|
this.showAIModal(response);
|
||||||
|
|
||||||
|
this.updateTaskStats();
|
||||||
|
this.updateLastUpdated('lastUpdate');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.showToast('Error processing command: ' + error.message, 'error');
|
||||||
|
} finally {
|
||||||
|
this.restoreButton('taskAiBtn', 'Execute', 'fa-robot');
|
||||||
|
this.clearInput('taskCommand');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generateTaskAIResponse(command) {
|
||||||
|
const lowerCommand = command.toLowerCase();
|
||||||
|
|
||||||
|
if (lowerCommand.includes('overdue') || lowerCommand.includes('urgent')) {
|
||||||
|
return `
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">⚠️ Overdue Tasks Analysis</h4>
|
||||||
|
<div class="bg-red-50 border border-red-200 p-4 rounded-lg">
|
||||||
|
<h5 class="font-medium text-red-800 mb-2">🚨 Immediate Action Required</h5>
|
||||||
|
<p class="text-sm text-red-700 mb-3">Found <strong>${this.stats.overdue}</strong> overdue tasks that need immediate attention</p>
|
||||||
|
<div class="space-y-2 text-sm text-red-700">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fas fa-exclamation-triangle text-red-600"></i>
|
||||||
|
<span>Website Security Audit - 2 days overdue</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<i class="fas fa-clock text-red-600"></i>
|
||||||
|
<span>Client Presentation - Due today</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-orange-50 border border-orange-200 p-4 rounded-lg">
|
||||||
|
<h5 class="font-medium text-orange-800 mb-2">💡 AI Recommendations</h5>
|
||||||
|
<div class="space-y-2 text-sm text-orange-700">
|
||||||
|
<p>• Prioritize security audit first - highest business risk</p>
|
||||||
|
<p>• Delegate or reschedule lower priority tasks</p>
|
||||||
|
<p>• Block 2-hour focus time for urgent items</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">🤖 Task AI Response</h4>
|
||||||
|
<div class="bg-orange-50 border border-orange-200 p-4 rounded-lg">
|
||||||
|
<p class="text-orange-700">Processing your request: "<em>${command}</em>"</p>
|
||||||
|
<p class="text-sm text-orange-600 mt-2">I can help you with:</p>
|
||||||
|
<ul class="mt-3 space-y-1 text-sm text-orange-700">
|
||||||
|
<li>• Smart task prioritization and scheduling</li>
|
||||||
|
<li>• Deadline tracking and alerts</li>
|
||||||
|
<li>• Progress analysis and reporting</li>
|
||||||
|
<li>• Workload balancing and optimization</li>
|
||||||
|
<li>• Task automation and workflows</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real API integration functions
|
||||||
|
async loadTasks(filters = {}) {
|
||||||
|
try {
|
||||||
|
this.showLoading(true);
|
||||||
|
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
action: 'get_tasks',
|
||||||
|
...filters
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Loading tasks from:', this.apiUrl);
|
||||||
|
|
||||||
|
const response = await fetch(`${this.apiUrl}?${params}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
this.tasks = data.tasks || [];
|
||||||
|
this.stats = data.stats || this.stats;
|
||||||
|
this.updateUI();
|
||||||
|
this.renderTasks();
|
||||||
|
console.log('✅ Tasks loaded successfully:', this.tasks.length);
|
||||||
|
} else {
|
||||||
|
throw new Error(data.message || 'Failed to load tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error loading tasks:', error);
|
||||||
|
this.showError('Failed to load tasks: ' + error.message);
|
||||||
|
} finally {
|
||||||
|
this.showLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load sample tasks for demonstration
|
||||||
|
loadSampleTasks() {
|
||||||
|
console.log('Loading sample tasks...');
|
||||||
|
|
||||||
|
this.tasks = [
|
||||||
|
{
|
||||||
|
id: 'task_1',
|
||||||
|
name: 'Website Security Audit',
|
||||||
|
description: 'Complete security assessment and vulnerability report',
|
||||||
|
dueDate: '02-01-2025',
|
||||||
|
dueDateFormatted: '2 days overdue',
|
||||||
|
timeEstimate: '3 hrs',
|
||||||
|
status: 'To Do',
|
||||||
|
priority: 'High',
|
||||||
|
priorityColor: 'red',
|
||||||
|
progress: 0,
|
||||||
|
type: 'Security',
|
||||||
|
isOverdue: true,
|
||||||
|
isDueToday: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'task_2',
|
||||||
|
name: 'Write Blog Article',
|
||||||
|
description: 'Article on "Top 5 AI Tools for Creators"',
|
||||||
|
dueDate: '06-01-2025',
|
||||||
|
dueDateFormatted: 'Due tomorrow',
|
||||||
|
timeEstimate: '2 hrs',
|
||||||
|
status: 'In Progress',
|
||||||
|
priority: 'Medium',
|
||||||
|
priorityColor: 'orange',
|
||||||
|
progress: 65,
|
||||||
|
type: 'Writing',
|
||||||
|
isOverdue: false,
|
||||||
|
isDueToday: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'task_3',
|
||||||
|
name: 'Design Landing Page',
|
||||||
|
description: 'Create a responsive landing page using Tailwind',
|
||||||
|
dueDate: '05-01-2025',
|
||||||
|
dueDateFormatted: 'Due today',
|
||||||
|
timeEstimate: '3 hrs',
|
||||||
|
status: 'To Do',
|
||||||
|
priority: 'Medium',
|
||||||
|
priorityColor: 'orange',
|
||||||
|
progress: 0,
|
||||||
|
type: 'Design',
|
||||||
|
isOverdue: false,
|
||||||
|
isDueToday: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'task_4',
|
||||||
|
name: 'Deploy Production Update',
|
||||||
|
description: 'Release v2.1.3 to production servers',
|
||||||
|
dueDate: '03-01-2025',
|
||||||
|
dueDateFormatted: 'Completed yesterday',
|
||||||
|
timeEstimate: '1 hr',
|
||||||
|
status: 'Done',
|
||||||
|
priority: 'High',
|
||||||
|
priorityColor: 'red',
|
||||||
|
progress: 100,
|
||||||
|
type: 'Development',
|
||||||
|
isOverdue: false,
|
||||||
|
isDueToday: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
this.stats = {
|
||||||
|
total: this.tasks.length,
|
||||||
|
overdue: this.tasks.filter(t => t.isOverdue).length,
|
||||||
|
dueToday: this.tasks.filter(t => t.isDueToday).length,
|
||||||
|
completed: this.tasks.filter(t => t.status === 'Done').length,
|
||||||
|
inProgress: this.tasks.filter(t => t.status === 'In Progress').length,
|
||||||
|
toDo: this.tasks.filter(t => t.status === 'To Do').length
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateUI();
|
||||||
|
this.renderTasks();
|
||||||
|
this.showLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchTasks(query) {
|
||||||
|
if (!query.trim()) {
|
||||||
|
this.loadTasks();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter current tasks for demo
|
||||||
|
const filtered = this.tasks.filter(task =>
|
||||||
|
task.name.toLowerCase().includes(query.toLowerCase()) ||
|
||||||
|
task.description.toLowerCase().includes(query.toLowerCase())
|
||||||
|
);
|
||||||
|
|
||||||
|
this.renderFilteredTasks(filtered);
|
||||||
|
this.showToast(`Found ${filtered.length} tasks matching "${query}"`, 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
async filterTasks(status) {
|
||||||
|
console.log('Filtering by status:', status);
|
||||||
|
|
||||||
|
if (status === 'all') {
|
||||||
|
this.renderTasks();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusMap = {
|
||||||
|
'todo': 'To Do',
|
||||||
|
'inprogress': 'In Progress',
|
||||||
|
'done': 'Done'
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetStatus = statusMap[status] || status;
|
||||||
|
const filtered = this.tasks.filter(task => task.status === targetStatus);
|
||||||
|
this.renderFilteredTasks(filtered);
|
||||||
|
this.showToast(`Showing ${filtered.length} ${targetStatus} tasks`, 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTasks() {
|
||||||
|
this.renderFilteredTasks(this.tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFilteredTasks(tasks) {
|
||||||
|
const todoColumn = document.querySelector('#todoColumn .kanban-column');
|
||||||
|
const inProgressColumn = document.querySelector('#inProgressColumn .kanban-column');
|
||||||
|
const doneColumn = document.querySelector('#doneColumn .kanban-column');
|
||||||
|
|
||||||
|
if (!todoColumn || !inProgressColumn || !doneColumn) {
|
||||||
|
console.error('Kanban columns not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear existing tasks
|
||||||
|
todoColumn.innerHTML = '';
|
||||||
|
inProgressColumn.innerHTML = '';
|
||||||
|
doneColumn.innerHTML = '';
|
||||||
|
|
||||||
|
// Group tasks by status
|
||||||
|
const tasksByStatus = {
|
||||||
|
'To Do': [],
|
||||||
|
'In Progress': [],
|
||||||
|
'Done': []
|
||||||
|
};
|
||||||
|
|
||||||
|
tasks.forEach(task => {
|
||||||
|
if (tasksByStatus[task.status]) {
|
||||||
|
tasksByStatus[task.status].push(task);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render tasks in each column
|
||||||
|
Object.keys(tasksByStatus).forEach(status => {
|
||||||
|
const column = status === 'To Do' ? todoColumn :
|
||||||
|
status === 'In Progress' ? inProgressColumn : doneColumn;
|
||||||
|
|
||||||
|
tasksByStatus[status].forEach(task => {
|
||||||
|
column.appendChild(this.createTaskCard(task));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update column counts
|
||||||
|
this.updateColumnCounts(tasksByStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
createTaskCard(task) {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
|
||||||
|
let cardClass = 'task-card bg-gray-50 p-4 rounded-lg border border-gray-200 cursor-pointer hover:shadow-md transition-all';
|
||||||
|
if (task.isOverdue) {
|
||||||
|
cardClass = 'task-card task-overdue bg-red-50 p-4 rounded-lg border border-red-200 cursor-pointer hover:shadow-md transition-all';
|
||||||
|
} else if (task.isDueToday) {
|
||||||
|
cardClass = 'task-card task-due-today bg-orange-50 p-4 rounded-lg border border-orange-200 cursor-pointer hover:shadow-md transition-all';
|
||||||
|
} else if (task.status === 'Done') {
|
||||||
|
cardClass = 'task-card task-completed bg-green-50 p-4 rounded-lg border border-green-200 cursor-pointer hover:shadow-md transition-all';
|
||||||
|
}
|
||||||
|
|
||||||
|
card.className = cardClass;
|
||||||
|
card.setAttribute('data-task-id', task.id);
|
||||||
|
|
||||||
|
const priorityBadgeColor = task.priority === 'High' ? 'red' :
|
||||||
|
task.priority === 'Medium' ? 'orange' : 'green';
|
||||||
|
|
||||||
|
let progressBar = '';
|
||||||
|
if (task.status === 'In Progress') {
|
||||||
|
progressBar = `
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-2 mb-2">
|
||||||
|
<div class="bg-orange-500 h-2 rounded-full transition-all duration-300" style="width: ${task.progress}%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between text-xs text-gray-500">
|
||||||
|
<span>${task.progress}% complete</span>
|
||||||
|
<span>${task.dueDateFormatted}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
progressBar = `
|
||||||
|
<div class="flex items-center justify-between text-xs text-gray-500">
|
||||||
|
<span><i class="fas fa-clock mr-1"></i>${task.dueDateFormatted}</span>
|
||||||
|
${task.type ? `<span><i class="fas fa-tag mr-1"></i>${task.type}</span>` : ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
card.innerHTML = `
|
||||||
|
<div class="flex items-start justify-between mb-2">
|
||||||
|
<h4 class="font-medium text-gray-800 text-sm ${task.status === 'Done' ? 'line-through' : ''}">${task.name}</h4>
|
||||||
|
<span class="px-2 py-1 bg-${priorityBadgeColor}-100 text-${priorityBadgeColor}-700 text-xs rounded-full">${task.priority}</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-xs text-gray-600 mb-3">${task.description}</p>
|
||||||
|
${progressBar}
|
||||||
|
${task.timeEstimate !== 'Not specified' ? `
|
||||||
|
<div class="text-xs text-gray-500 mt-2">
|
||||||
|
<i class="fas fa-hourglass-half mr-1"></i>Estimated: ${task.timeEstimate}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${task.status === 'Done' ? `
|
||||||
|
<div class="flex items-center justify-between text-xs text-gray-500 mt-2">
|
||||||
|
<span><i class="fas fa-check mr-1"></i>Completed</span>
|
||||||
|
<span>Yesterday</span>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add click handler for task details
|
||||||
|
card.addEventListener('click', () => this.showTaskDetails(task));
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateColumnCounts(tasksByStatus) {
|
||||||
|
const todoCountEl = document.querySelector('#todoColumn .text-gray-500');
|
||||||
|
const inProgressCountEl = document.querySelector('#inProgressColumn .text-gray-500');
|
||||||
|
const doneCountEl = document.querySelector('#doneColumn .text-gray-500');
|
||||||
|
|
||||||
|
if (todoCountEl) todoCountEl.textContent = tasksByStatus['To Do'].length;
|
||||||
|
if (inProgressCountEl) inProgressCountEl.textContent = tasksByStatus['In Progress'].length;
|
||||||
|
if (doneCountEl) doneCountEl.textContent = tasksByStatus['Done'].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUI() {
|
||||||
|
// Update stats dashboard
|
||||||
|
this.updateElement('overdueCount', this.stats.overdue);
|
||||||
|
this.updateElement('dueTodayCount', this.stats.dueToday);
|
||||||
|
this.updateElement('totalTasks', this.stats.total);
|
||||||
|
this.updateElement('completedToday', this.stats.completed);
|
||||||
|
|
||||||
|
this.updateLastUpdated('lastUpdate');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateElement(id, value) {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showTaskDetails(task) {
|
||||||
|
const modalContent = `
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h4 class="text-xl font-bold text-gray-800">${task.name}</h4>
|
||||||
|
<span class="px-3 py-1 bg-${task.priorityColor}-100 text-${task.priorityColor}-700 text-sm rounded-full">${task.priority} Priority</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<h5 class="font-medium text-gray-700 mb-2">Description</h5>
|
||||||
|
<p class="text-gray-600">${task.description}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="bg-blue-50 rounded-lg p-3">
|
||||||
|
<h5 class="font-medium text-blue-700 mb-1">Status</h5>
|
||||||
|
<p class="text-blue-600">${task.status}</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 rounded-lg p-3">
|
||||||
|
<h5 class="font-medium text-green-700 mb-1">Due Date</h5>
|
||||||
|
<p class="text-green-600">${task.dueDateFormatted}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${task.status === 'In Progress' ? `
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3">
|
||||||
|
<h5 class="font-medium text-orange-700 mb-1">Progress</h5>
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-3 mb-2">
|
||||||
|
<div class="bg-orange-500 h-3 rounded-full" style="width: ${task.progress}%"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-orange-600">${task.progress}% Complete</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="bg-purple-50 rounded-lg p-3">
|
||||||
|
<h5 class="font-medium text-purple-700 mb-1">Type</h5>
|
||||||
|
<p class="text-purple-600">${task.type}</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-indigo-50 rounded-lg p-3">
|
||||||
|
<h5 class="font-medium text-indigo-700 mb-1">Time Estimate</h5>
|
||||||
|
<p class="text-indigo-600">${task.timeEstimate}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-3 pt-4">
|
||||||
|
<button onclick="taskAgent.updateTaskStatus('${task.id}', 'In Progress')" class="flex-1 bg-orange-600 text-white py-2 px-4 rounded-lg hover:bg-orange-700 transition-colors">
|
||||||
|
Mark In Progress
|
||||||
|
</button>
|
||||||
|
<button onclick="taskAgent.updateTaskStatus('${task.id}', 'Done')" class="flex-1 bg-green-600 text-white py-2 px-4 rounded-lg hover:bg-green-700 transition-colors">
|
||||||
|
Mark Complete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
this.showAIModal(modalContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading(show) {
|
||||||
|
const loadingElement = document.getElementById('loadingState');
|
||||||
|
const kanbanColumns = document.querySelectorAll('.kanban-column');
|
||||||
|
|
||||||
|
if (loadingElement) {
|
||||||
|
loadingElement.classList.toggle('hidden', !show);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
kanbanColumns.forEach(column => {
|
||||||
|
column.innerHTML = '<div class="text-center text-gray-500 py-8"><i class="fas fa-spinner fa-spin"></i> Loading...</div>';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showError(message) {
|
||||||
|
const todoColumn = document.querySelector('#todoColumn .kanban-column');
|
||||||
|
if (todoColumn) {
|
||||||
|
todoColumn.innerHTML = `
|
||||||
|
<div class="text-center py-8">
|
||||||
|
<div class="w-12 h-12 bg-red-100 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||||
|
<i class="fas fa-exclamation-triangle text-red-500"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-sm font-semibold text-red-600 mb-2">Error Loading Tasks</h3>
|
||||||
|
<p class="text-xs text-gray-500 mb-3">${message}</p>
|
||||||
|
<button onclick="taskAgent.loadSampleTasks()" class="text-xs bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded transition-colors">
|
||||||
|
Load Sample Data
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTaskStats() {
|
||||||
|
this.totalActions++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
setButtonLoading(elementId, text, iconClass) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.innerHTML = `<i class="${iconClass}"></i> ${text}`;
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreButton(elementId, text, iconClass) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.innerHTML = `<i class="${iconClass}"></i> <span>${text}</span>`;
|
||||||
|
element.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInput(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showAIModal(content) {
|
||||||
|
const modal = document.getElementById('aiModal');
|
||||||
|
const responseDiv = document.getElementById('aiResponse');
|
||||||
|
if (modal && responseDiv) {
|
||||||
|
responseDiv.innerHTML = content;
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hideAIModal() {
|
||||||
|
const modal = document.getElementById('aiModal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(message, type = 'info') {
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.className = `fixed top-4 right-4 z-50 max-w-sm w-full transform transition-all duration-300`;
|
||||||
|
|
||||||
|
const bgColor = {
|
||||||
|
success: 'bg-green-500',
|
||||||
|
error: 'bg-red-500',
|
||||||
|
warning: 'bg-yellow-500',
|
||||||
|
info: 'bg-blue-500'
|
||||||
|
}[type] || 'bg-gray-500';
|
||||||
|
|
||||||
|
const icon = {
|
||||||
|
success: 'fas fa-check-circle',
|
||||||
|
error: 'fas fa-exclamation-circle',
|
||||||
|
warning: 'fas fa-exclamation-triangle',
|
||||||
|
info: 'fas fa-info-circle'
|
||||||
|
}[type] || 'fas fa-info-circle';
|
||||||
|
|
||||||
|
toast.innerHTML = `
|
||||||
|
<div class="${bgColor} text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3">
|
||||||
|
<i class="${icon}"></i>
|
||||||
|
<span class="text-sm font-medium">${message}</span>
|
||||||
|
<button onclick="this.parentElement.parentElement.remove()" class="ml-auto text-white hover:text-gray-200">
|
||||||
|
<i class="fas fa-times text-xs"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
|
||||||
|
// Animate in
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.transform = 'translateX(0)';
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Auto remove after 4 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
toast.style.transform = 'translateX(100%)';
|
||||||
|
setTimeout(() => {
|
||||||
|
if (toast.parentElement) {
|
||||||
|
toast.remove();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}, 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick action functions
|
||||||
|
createTask() {
|
||||||
|
this.showAIModal(`
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">✅ Create New Task</h4>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Task Name:</label>
|
||||||
|
<input type="text" id="newTaskName" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500" placeholder="Enter task name">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Description:</label>
|
||||||
|
<textarea id="newTaskDescription" rows="3" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500" placeholder="Describe the task..."></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Due Date:</label>
|
||||||
|
<input type="date" id="newTaskDue" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Priority:</label>
|
||||||
|
<select id="newTaskPriority" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500">
|
||||||
|
<option value="Low">Low Priority</option>
|
||||||
|
<option value="Medium" selected>Medium Priority</option>
|
||||||
|
<option value="High">High Priority</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Time Estimate:</label>
|
||||||
|
<select id="newTaskTime" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-orange-500 focus:border-orange-500">
|
||||||
|
<option value="30 mins">30 minutes</option>
|
||||||
|
<option value="1 hr" selected>1 hour</option>
|
||||||
|
<option value="2 hrs">2 hours</option>
|
||||||
|
<option value="4 hrs">4 hours</option>
|
||||||
|
<option value="1 day">1 day</option>
|
||||||
|
<option value="2-3 days">2-3 days</option>
|
||||||
|
<option value="1 week">1 week</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button onclick="taskAgent.submitNewTask()" class="w-full bg-orange-600 text-white py-3 px-4 rounded-lg hover:bg-orange-700 transition-colors font-medium">
|
||||||
|
🚀 Create Task
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitNewTask() {
|
||||||
|
const name = document.getElementById('newTaskName')?.value || '';
|
||||||
|
const description = document.getElementById('newTaskDescription')?.value || '';
|
||||||
|
const dueDate = document.getElementById('newTaskDue')?.value || '';
|
||||||
|
const priority = document.getElementById('newTaskPriority')?.value || 'Medium';
|
||||||
|
const timeEstimate = document.getElementById('newTaskTime')?.value || '1 hr';
|
||||||
|
|
||||||
|
if (!name.trim()) {
|
||||||
|
this.showToast('Please enter a task name', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// In a real implementation, you would send this to your n8n workflow
|
||||||
|
// For now, we'll simulate success and add to local data
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
|
// Add new task to local data for demo
|
||||||
|
const newTask = {
|
||||||
|
id: 'task_' + Date.now(),
|
||||||
|
name: name,
|
||||||
|
description: description || 'No description provided',
|
||||||
|
dueDate: dueDate,
|
||||||
|
dueDateFormatted: dueDate ? 'Due ' + new Date(dueDate).toLocaleDateString() : 'No due date',
|
||||||
|
timeEstimate: timeEstimate,
|
||||||
|
status: 'To Do',
|
||||||
|
priority: priority,
|
||||||
|
priorityColor: priority === 'High' ? 'red' : priority === 'Medium' ? 'orange' : 'green',
|
||||||
|
progress: 0,
|
||||||
|
type: 'General',
|
||||||
|
isOverdue: false,
|
||||||
|
isDueToday: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.tasks.unshift(newTask);
|
||||||
|
this.stats.total++;
|
||||||
|
this.stats.toDo++;
|
||||||
|
|
||||||
|
this.hideAIModal();
|
||||||
|
this.showToast(`Task "${name}" created successfully!`, 'success');
|
||||||
|
this.updateUI();
|
||||||
|
this.renderTasks();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.showToast('Failed to create task: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTaskStatus(taskId, newStatus) {
|
||||||
|
try {
|
||||||
|
const task = this.tasks.find(t => t.id === taskId);
|
||||||
|
if (task) {
|
||||||
|
const oldStatus = task.status;
|
||||||
|
task.status = newStatus;
|
||||||
|
|
||||||
|
if (newStatus === 'Done') {
|
||||||
|
task.progress = 100;
|
||||||
|
} else if (newStatus === 'In Progress' && task.progress === 0) {
|
||||||
|
task.progress = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update stats
|
||||||
|
if (oldStatus === 'To Do') this.stats.toDo--;
|
||||||
|
else if (oldStatus === 'In Progress') this.stats.inProgress--;
|
||||||
|
else if (oldStatus === 'Done') this.stats.completed--;
|
||||||
|
|
||||||
|
if (newStatus === 'To Do') this.stats.toDo++;
|
||||||
|
else if (newStatus === 'In Progress') this.stats.inProgress++;
|
||||||
|
else if (newStatus === 'Done') this.stats.completed++;
|
||||||
|
|
||||||
|
this.hideAIModal();
|
||||||
|
this.showToast(`Task status updated to ${newStatus}`, 'success');
|
||||||
|
this.updateUI();
|
||||||
|
this.renderTasks();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.showToast('Failed to update task: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prioritizeTasks() {
|
||||||
|
this.updateTaskStats();
|
||||||
|
this.showToast('🎯 Tasks automatically prioritized by AI algorithm!', 'success');
|
||||||
|
|
||||||
|
// Sort tasks by priority and overdue status
|
||||||
|
this.tasks.sort((a, b) => {
|
||||||
|
if (a.isOverdue && !b.isOverdue) return -1;
|
||||||
|
if (!a.isOverdue && b.isOverdue) return 1;
|
||||||
|
|
||||||
|
const priorityOrder = { 'High': 0, 'Medium': 1, 'Low': 2 };
|
||||||
|
return (priorityOrder[a.priority] || 2) - (priorityOrder[b.priority] || 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.renderTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkUpdate() {
|
||||||
|
this.updateTaskStats();
|
||||||
|
this.showToast('📝 Bulk update feature coming soon!', 'info');
|
||||||
|
}
|
||||||
|
|
||||||
|
generateReport() {
|
||||||
|
const completionRate = this.stats.total > 0 ? Math.round((this.stats.completed / this.stats.total) * 100) : 0;
|
||||||
|
|
||||||
|
this.showAIModal(`
|
||||||
|
<div class="space-y-4">
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800">📊 Progress Report</h4>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="bg-blue-50 rounded-lg p-4 text-center">
|
||||||
|
<div class="text-2xl font-bold text-blue-600">${this.stats.total}</div>
|
||||||
|
<div class="text-sm text-blue-600">Total Tasks</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 rounded-lg p-4 text-center">
|
||||||
|
<div class="text-2xl font-bold text-green-600">${completionRate}%</div>
|
||||||
|
<div class="text-sm text-green-600">Completion Rate</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-50 rounded-lg p-4">
|
||||||
|
<h5 class="font-medium text-gray-700 mb-3">Task Breakdown</h5>
|
||||||
|
<div class="space-y-2">
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-gray-600">Completed:</span>
|
||||||
|
<span class="font-medium text-green-600">${this.stats.completed}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-gray-600">In Progress:</span>
|
||||||
|
<span class="font-medium text-orange-600">${this.stats.inProgress}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-gray-600">To Do:</span>
|
||||||
|
<span class="font-medium text-blue-600">${this.stats.toDo}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<span class="text-red-600">Overdue:</span>
|
||||||
|
<span class="font-medium text-red-600">${this.stats.overdue}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-orange-50 border border-orange-200 p-4 rounded-lg">
|
||||||
|
<h5 class="font-medium text-orange-800 mb-2">💡 AI Insights</h5>
|
||||||
|
<ul class="text-sm text-orange-700 space-y-1">
|
||||||
|
<li>• Your completion rate is ${completionRate > 70 ? 'excellent' : completionRate > 50 ? 'good' : 'needs improvement'}</li>
|
||||||
|
<li>• ${this.stats.overdue > 0 ? `Focus on ${this.stats.overdue} overdue tasks first` : 'Great job staying on top of deadlines!'}</li>
|
||||||
|
<li>• Consider breaking down large tasks into smaller chunks</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search and filter functions
|
||||||
|
async handleSearch() {
|
||||||
|
const searchInput = document.getElementById('taskSearchInput');
|
||||||
|
if (searchInput) {
|
||||||
|
await this.searchTasks(searchInput.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleFilter(status) {
|
||||||
|
await this.filterTasks(status);
|
||||||
|
|
||||||
|
// Update filter button states
|
||||||
|
document.querySelectorAll('.filter-btn').forEach(btn => {
|
||||||
|
btn.classList.remove('bg-orange-200', 'text-orange-800');
|
||||||
|
btn.classList.add('bg-gray-100', 'text-gray-700');
|
||||||
|
});
|
||||||
|
|
||||||
|
const activeBtn = document.querySelector(`[data-status="${status}"]`);
|
||||||
|
if (activeBtn) {
|
||||||
|
activeBtn.classList.remove('bg-gray-100', 'text-gray-700');
|
||||||
|
activeBtn.classList.add('bg-orange-200', 'text-orange-800');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Task Agent when DOM is loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
console.log('Initializing Task Agent...');
|
||||||
|
window.taskAgent = new TaskAgent();
|
||||||
|
|
||||||
|
// Make functions globally available for onclick handlers
|
||||||
|
window.executeTaskCommand = () => taskAgent.executeTaskCommand();
|
||||||
|
window.setTaskCommand = (cmd) => taskAgent.setTaskCommand(cmd);
|
||||||
|
window.createTask = () => taskAgent.createTask();
|
||||||
|
window.prioritizeTasks = () => taskAgent.prioritizeTasks();
|
||||||
|
window.bulkUpdate = () => taskAgent.bulkUpdate();
|
||||||
|
window.generateReport = () => taskAgent.generateReport();
|
||||||
|
window.closeAIModal = () => taskAgent.hideAIModal();
|
||||||
|
|
||||||
|
console.log('✅ Task Agent initialized successfully');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Global helper functions
|
||||||
|
function goHome() {
|
||||||
|
window.location.href = 'index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Task Agent JS loaded successfully');
|
||||||
1066
assets/js/trade-intelligence.js
Normal file
1066
assets/js/trade-intelligence.js
Normal file
File diff suppressed because it is too large
Load Diff
634
assets/js/utils.js
Normal file
634
assets/js/utils.js
Normal file
@ -0,0 +1,634 @@
|
|||||||
|
/**
|
||||||
|
* Universal Utilities for All AI Agent Pages
|
||||||
|
* Compatible with: Task Agent, Email Agent, Calendar Agent, Trade Intelligence
|
||||||
|
* Enhanced with offline handling, performance optimizations, and better error handling
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Create Utils object if it doesn't exist
|
||||||
|
window.Utils = window.Utils || {};
|
||||||
|
|
||||||
|
// Time utilities
|
||||||
|
Utils.time = {
|
||||||
|
updateLastUpdated: function(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = new Date().toLocaleTimeString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatTimestamp: function(date) {
|
||||||
|
if (!date) return 'Unknown';
|
||||||
|
try {
|
||||||
|
return new Date(date).toLocaleString();
|
||||||
|
} catch (e) {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Form utilities
|
||||||
|
Utils.form = {
|
||||||
|
setInputValue: function(elementId, value) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.value = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getInputValue: function(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
return element ? element.value : '';
|
||||||
|
},
|
||||||
|
|
||||||
|
clearInput: function(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.value = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Button utilities
|
||||||
|
Utils.button = {
|
||||||
|
setLoading: function(elementId, text, iconClass) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.innerHTML = `<i class="${iconClass}"></i> ${text}`;
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
restore: function(elementId, text, iconClass) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.innerHTML = `<i class="${iconClass}"></i> <span>${text}</span>`;
|
||||||
|
element.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Event utilities
|
||||||
|
Utils.events = {
|
||||||
|
onEnterKey: function(elementId, callback) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.addEventListener('keypress', function(e) {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stats utilities
|
||||||
|
Utils.stats = {
|
||||||
|
increment: function(statName) {
|
||||||
|
console.log('Incrementing stat:', statName);
|
||||||
|
const element = document.getElementById(statName);
|
||||||
|
if (element) {
|
||||||
|
const currentValue = parseInt(element.textContent) || 0;
|
||||||
|
element.textContent = currentValue + 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function(statName, value) {
|
||||||
|
const element = document.getElementById(statName);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enhanced API utilities with offline handling
|
||||||
|
Utils.api = {
|
||||||
|
// Enhanced request with better offline detection
|
||||||
|
async request(url, options = {}) {
|
||||||
|
try {
|
||||||
|
console.log('🔄 Making API request to:', url);
|
||||||
|
|
||||||
|
// Check if browser is online
|
||||||
|
if (!navigator.onLine) {
|
||||||
|
throw new Error('OFFLINE');
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
// Add timeout to detect slow/failed connections
|
||||||
|
signal: AbortSignal.timeout(30000) // 30 second timeout
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(url, { ...defaultOptions, ...options });
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP_${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('✅ API request successful');
|
||||||
|
return data;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ API Request failed:', error);
|
||||||
|
|
||||||
|
// Handle different types of errors with user-friendly messages
|
||||||
|
let userMessage = '';
|
||||||
|
let errorType = 'error';
|
||||||
|
|
||||||
|
if (error.message === 'OFFLINE' || !navigator.onLine) {
|
||||||
|
userMessage = '📱 You appear to be offline. Please check your internet connection and try again.';
|
||||||
|
errorType = 'warning';
|
||||||
|
} else if (error.name === 'TimeoutError' || error.message.includes('timeout')) {
|
||||||
|
userMessage = '⏱️ Request timed out. The server may be busy. Please try again.';
|
||||||
|
errorType = 'warning';
|
||||||
|
} else if (error.message.includes('Failed to fetch')) {
|
||||||
|
userMessage = '🌐 Unable to connect to server. Please check your connection and try again.';
|
||||||
|
errorType = 'warning';
|
||||||
|
} else if (error.message.includes('HTTP_5')) {
|
||||||
|
userMessage = '🔧 Server error (5xx). Please try again in a few moments.';
|
||||||
|
errorType = 'error';
|
||||||
|
} else if (error.message.includes('HTTP_4')) {
|
||||||
|
userMessage = '⚠️ Request error (4xx). Please check your input and try again.';
|
||||||
|
errorType = 'warning';
|
||||||
|
} else {
|
||||||
|
userMessage = '❌ Something went wrong. Please try again.';
|
||||||
|
errorType = 'error';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show user-friendly toast
|
||||||
|
Utils.toast.show(userMessage, errorType);
|
||||||
|
|
||||||
|
// Re-throw for handling by calling function
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Quick method for GET requests with parameters
|
||||||
|
async get(url, params = {}) {
|
||||||
|
const urlWithParams = new URL(url);
|
||||||
|
Object.keys(params).forEach(key => {
|
||||||
|
if (params[key] !== undefined && params[key] !== null) {
|
||||||
|
urlWithParams.searchParams.append(key, params[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.request(urlWithParams.toString());
|
||||||
|
},
|
||||||
|
|
||||||
|
// Test connection method
|
||||||
|
async testConnection() {
|
||||||
|
try {
|
||||||
|
await fetch('https://httpbin.org/status/200', {
|
||||||
|
method: 'HEAD',
|
||||||
|
signal: AbortSignal.timeout(5000)
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Network status detection
|
||||||
|
Utils.network = {
|
||||||
|
isOnline: navigator.onLine,
|
||||||
|
|
||||||
|
init() {
|
||||||
|
// Listen for online/offline events
|
||||||
|
window.addEventListener('online', () => {
|
||||||
|
this.isOnline = true;
|
||||||
|
Utils.toast.success('🌐 Connection restored!');
|
||||||
|
console.log('✅ Back online');
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('offline', () => {
|
||||||
|
this.isOnline = false;
|
||||||
|
Utils.toast.warning('📱 You are now offline. Some features may not work.');
|
||||||
|
console.log('⚠️ Gone offline');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Check if we should even attempt API calls
|
||||||
|
canMakeRequests() {
|
||||||
|
if (!this.isOnline) {
|
||||||
|
Utils.toast.warning('📱 No internet connection. Please check your network.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Performance utilities
|
||||||
|
Utils.performance = {
|
||||||
|
// Debounce function for search inputs (prevents too many API calls)
|
||||||
|
debounce(func, wait) {
|
||||||
|
let timeout;
|
||||||
|
return function executedFunction(...args) {
|
||||||
|
const later = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
func(...args);
|
||||||
|
};
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = setTimeout(later, wait);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Throttle function for scroll events
|
||||||
|
throttle(func, limit) {
|
||||||
|
let inThrottle;
|
||||||
|
return function() {
|
||||||
|
const args = arguments;
|
||||||
|
const context = this;
|
||||||
|
if (!inThrottle) {
|
||||||
|
func.apply(context, args);
|
||||||
|
inThrottle = true;
|
||||||
|
setTimeout(() => inThrottle = false, limit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// Optimize search inputs automatically
|
||||||
|
optimizeSearchInputs() {
|
||||||
|
const searchInputs = document.querySelectorAll('#query, #searchQuery, #taskSearchInput, #taskCommand, #calendarCommand');
|
||||||
|
|
||||||
|
searchInputs.forEach(input => {
|
||||||
|
if (input) {
|
||||||
|
// Remove any existing event listeners to avoid duplicates
|
||||||
|
const newInput = input.cloneNode(true);
|
||||||
|
input.parentNode.replaceChild(newInput, input);
|
||||||
|
|
||||||
|
// Add optimized event listener
|
||||||
|
newInput.addEventListener('input', this.debounce((e) => {
|
||||||
|
// Only trigger if user has typed something meaningful
|
||||||
|
if (e.target.value.length >= 2) {
|
||||||
|
console.log('Optimized search triggered for:', e.target.value);
|
||||||
|
}
|
||||||
|
}, 300));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modal utilities
|
||||||
|
Utils.modal = {
|
||||||
|
showAI: function(content) {
|
||||||
|
const modal = document.getElementById('aiModal');
|
||||||
|
const responseDiv = document.getElementById('aiResponse');
|
||||||
|
if (modal && responseDiv) {
|
||||||
|
responseDiv.innerHTML = content;
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hideAI: function() {
|
||||||
|
const modal = document.getElementById('aiModal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(modalId, content) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
if (modal) {
|
||||||
|
if (content) {
|
||||||
|
const contentDiv = modal.querySelector('.modal-content') ||
|
||||||
|
modal.querySelector('#aiResponse') ||
|
||||||
|
modal.querySelector('.p-6:last-child');
|
||||||
|
if (contentDiv) {
|
||||||
|
contentDiv.innerHTML = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modal.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function(modalId) {
|
||||||
|
const modal = document.getElementById(modalId);
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enhanced toast notifications
|
||||||
|
Utils.toast = {
|
||||||
|
show: function(message, type = 'info') {
|
||||||
|
// Remove existing toasts
|
||||||
|
document.querySelectorAll('.utils-toast').forEach(toast => toast.remove());
|
||||||
|
|
||||||
|
const toast = document.createElement('div');
|
||||||
|
toast.className = 'utils-toast fixed top-4 right-4 z-50 max-w-sm transform transition-all duration-300 translate-x-full';
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
success: { bg: 'bg-green-500', icon: 'fas fa-check-circle' },
|
||||||
|
error: { bg: 'bg-red-500', icon: 'fas fa-exclamation-circle' },
|
||||||
|
warning: { bg: 'bg-yellow-500', icon: 'fas fa-exclamation-triangle' },
|
||||||
|
info: { bg: 'bg-blue-500', icon: 'fas fa-info-circle' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const style = styles[type] || styles.info;
|
||||||
|
|
||||||
|
toast.innerHTML = `
|
||||||
|
<div class="${style.bg} text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3">
|
||||||
|
<i class="${style.icon}"></i>
|
||||||
|
<span class="text-sm font-medium flex-1">${message}</span>
|
||||||
|
<button onclick="this.parentElement.parentElement.remove()" class="text-white hover:text-gray-200">
|
||||||
|
<i class="fas fa-times text-xs"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(toast);
|
||||||
|
|
||||||
|
// Animate in
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
toast.classList.remove('translate-x-full');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Auto remove after 5 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
if (toast.parentElement) {
|
||||||
|
toast.classList.add('translate-x-full');
|
||||||
|
setTimeout(() => toast.remove(), 300);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
},
|
||||||
|
|
||||||
|
success: function(message) { this.show(message, 'success'); },
|
||||||
|
error: function(message) { this.show(message, 'error'); },
|
||||||
|
warning: function(message) { this.show(message, 'warning'); },
|
||||||
|
info: function(message) { this.show(message, 'info'); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Navigation utilities
|
||||||
|
Utils.navigation = {
|
||||||
|
goHome: function() {
|
||||||
|
window.location.href = 'index.html';
|
||||||
|
},
|
||||||
|
|
||||||
|
goToPage: function(page) {
|
||||||
|
window.location.href = page;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validation utilities
|
||||||
|
Utils.validation = {
|
||||||
|
isEmail: function(email) {
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||||
|
return emailRegex.test(email);
|
||||||
|
},
|
||||||
|
|
||||||
|
isEmpty: function(value) {
|
||||||
|
return !value || value.toString().trim().length === 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
isValidDate: function(date) {
|
||||||
|
return date instanceof Date && !isNaN(date);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loading utilities
|
||||||
|
Utils.loading = {
|
||||||
|
show: function(elementId, message = 'Loading...') {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.classList.remove('hidden');
|
||||||
|
const messageEl = element.querySelector('.loading-message');
|
||||||
|
if (messageEl) {
|
||||||
|
messageEl.textContent = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function(elementId) {
|
||||||
|
const element = document.getElementById(elementId);
|
||||||
|
if (element) {
|
||||||
|
element.classList.add('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggle: function(elementId, show, message) {
|
||||||
|
if (show) {
|
||||||
|
this.show(elementId, message);
|
||||||
|
} else {
|
||||||
|
this.hide(elementId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Storage utilities (for local data)
|
||||||
|
Utils.storage = {
|
||||||
|
set: function(key, value) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, JSON.stringify(value));
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('localStorage not available, using memory storage');
|
||||||
|
this._memoryStorage = this._memoryStorage || {};
|
||||||
|
this._memoryStorage[key] = value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function(key, defaultValue = null) {
|
||||||
|
try {
|
||||||
|
const item = localStorage.getItem(key);
|
||||||
|
return item ? JSON.parse(item) : defaultValue;
|
||||||
|
} catch (e) {
|
||||||
|
this._memoryStorage = this._memoryStorage || {};
|
||||||
|
return this._memoryStorage[key] || defaultValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(key) {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
} catch (e) {
|
||||||
|
if (this._memoryStorage) {
|
||||||
|
delete this._memoryStorage[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Formatting utilities
|
||||||
|
Utils.format = {
|
||||||
|
currency: function(amount, currency = 'USD') {
|
||||||
|
try {
|
||||||
|
return new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: currency
|
||||||
|
}).format(amount);
|
||||||
|
} catch (e) {
|
||||||
|
return `$${amount}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
number: function(num, decimals = 0) {
|
||||||
|
return Number(num).toFixed(decimals);
|
||||||
|
},
|
||||||
|
|
||||||
|
date: function(date, format = 'short') {
|
||||||
|
try {
|
||||||
|
return new Date(date).toLocaleDateString('en-US', {
|
||||||
|
dateStyle: format
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
time: function(date) {
|
||||||
|
try {
|
||||||
|
return new Date(date).toLocaleTimeString('en-US', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit'
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Searchable dropdown utility for countries
|
||||||
|
Utils.dropdown = {
|
||||||
|
createSearchableCountryDropdown: function(selectElement, countries) {
|
||||||
|
if (!selectElement) return;
|
||||||
|
|
||||||
|
const container = selectElement.parentNode;
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'relative';
|
||||||
|
|
||||||
|
// Create input field
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'text';
|
||||||
|
input.placeholder = 'Type to search countries...';
|
||||||
|
input.className = selectElement.className;
|
||||||
|
input.id = selectElement.id + '_input';
|
||||||
|
|
||||||
|
// Create dropdown
|
||||||
|
const dropdown = document.createElement('div');
|
||||||
|
dropdown.className = 'absolute z-10 w-full bg-white border border-gray-300 rounded-lg shadow-lg max-h-48 overflow-y-auto hidden';
|
||||||
|
dropdown.style.top = '100%';
|
||||||
|
|
||||||
|
// Create options
|
||||||
|
const createOptions = (filteredCountries) => {
|
||||||
|
dropdown.innerHTML = '';
|
||||||
|
|
||||||
|
if (filteredCountries.length === 0) {
|
||||||
|
dropdown.innerHTML = '<div class="p-3 text-gray-500 text-sm">No countries found</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredCountries.forEach(country => {
|
||||||
|
const option = document.createElement('div');
|
||||||
|
option.className = 'p-3 hover:bg-gray-100 cursor-pointer text-sm border-b border-gray-100 last:border-b-0';
|
||||||
|
option.textContent = country;
|
||||||
|
option.addEventListener('click', () => {
|
||||||
|
input.value = country;
|
||||||
|
selectElement.value = country;
|
||||||
|
dropdown.classList.add('hidden');
|
||||||
|
|
||||||
|
// Trigger change event
|
||||||
|
const event = new Event('change', { bubbles: true });
|
||||||
|
selectElement.dispatchEvent(event);
|
||||||
|
});
|
||||||
|
dropdown.appendChild(option);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize with all countries
|
||||||
|
createOptions(countries);
|
||||||
|
|
||||||
|
// Handle input changes
|
||||||
|
input.addEventListener('input', (e) => {
|
||||||
|
const query = e.target.value.toLowerCase();
|
||||||
|
const filtered = countries.filter(country =>
|
||||||
|
country.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
|
createOptions(filtered);
|
||||||
|
dropdown.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show dropdown on focus
|
||||||
|
input.addEventListener('focus', () => {
|
||||||
|
dropdown.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Hide dropdown when clicking outside
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!wrapper.contains(e.target)) {
|
||||||
|
dropdown.classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build wrapper
|
||||||
|
wrapper.appendChild(input);
|
||||||
|
wrapper.appendChild(dropdown);
|
||||||
|
|
||||||
|
// Replace original select
|
||||||
|
container.replaceChild(wrapper, selectElement);
|
||||||
|
|
||||||
|
// Keep original select hidden for form submission
|
||||||
|
selectElement.style.display = 'none';
|
||||||
|
wrapper.appendChild(selectElement);
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global convenience functions for backward compatibility
|
||||||
|
function goHome() {
|
||||||
|
Utils.navigation.goHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLastUpdated(elementId) {
|
||||||
|
Utils.time.updateLastUpdated(elementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showToast(message, type = 'info') {
|
||||||
|
Utils.toast.show(message, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global error handler
|
||||||
|
window.addEventListener('error', function(event) {
|
||||||
|
console.error('Global error caught:', event.error);
|
||||||
|
Utils.toast.error('An unexpected error occurred. Please refresh the page.');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Global unhandled promise rejection handler
|
||||||
|
window.addEventListener('unhandledrejection', function(event) {
|
||||||
|
console.error('Unhandled promise rejection:', event.reason);
|
||||||
|
Utils.toast.error('A network or processing error occurred.');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Export for global use
|
||||||
|
window.goHome = goHome;
|
||||||
|
window.updateLastUpdated = updateLastUpdated;
|
||||||
|
window.showToast = showToast;
|
||||||
|
|
||||||
|
// Initialize everything when DOM loads
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Initialize network detection
|
||||||
|
Utils.network.init();
|
||||||
|
|
||||||
|
// Apply performance optimizations
|
||||||
|
setTimeout(() => {
|
||||||
|
Utils.performance.optimizeSearchInputs();
|
||||||
|
console.log('✅ Performance optimizations applied');
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
// Update any "Last updated" timestamps on the page
|
||||||
|
const timestampElements = document.querySelectorAll('[id*="last"], [id*="Last"], [id*="update"], [id*="Update"], [id*="sync"], [id*="Sync"]');
|
||||||
|
timestampElements.forEach(element => {
|
||||||
|
if (element.id) {
|
||||||
|
Utils.time.updateLastUpdated(element.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('✅ Universal Utils.js loaded and initialized');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('✅ Universal Utils.js loaded successfully');
|
||||||
400
calendar-agent.html
Normal file
400
calendar-agent.html
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Calendar Agent - AI Calendar Management</title>
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Your Custom Files -->
|
||||||
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation Header -->
|
||||||
|
<nav class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button onclick="goHome()" class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center hover:bg-indigo-200 transition-colors">
|
||||||
|
<i class="fas fa-home text-indigo-600"></i>
|
||||||
|
</button>
|
||||||
|
<div class="w-10 h-10 bg-green-600 rounded-xl flex items-center justify-center shadow-lg">
|
||||||
|
<i class="fas fa-calendar-alt text-white text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-lg font-bold text-gray-800">Calendar Agent</h1>
|
||||||
|
<p class="text-sm text-gray-500">AI Calendar Management</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm text-gray-500">Last sync</p>
|
||||||
|
<p class="font-semibold text-gray-800" id="lastSync">Just now</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<span class="text-sm text-green-600 font-medium">Synced</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 bg-gray-50 min-h-screen">
|
||||||
|
|
||||||
|
<!-- Header Section -->
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl lg:text-4xl font-bold text-gray-800 mb-4">AI Calendar Management</h1>
|
||||||
|
<p class="text-xl text-gray-600 max-w-2xl mx-auto">
|
||||||
|
Smart scheduling, optimal time finding, and intelligent meeting management powered by AI.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Calendar Command Center -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div class="w-10 h-10 bg-green-600 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-brain text-white"></i>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-800">Calendar AI Command</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
id="calendarCommand"
|
||||||
|
type="text"
|
||||||
|
placeholder="Ask AI: 'Schedule team meeting tomorrow 2PM', 'Find free time this week', 'Reschedule conflicting meetings'"
|
||||||
|
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-green-400 focus:ring-2 focus:ring-green-400/50 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="executeCalendarCommand()"
|
||||||
|
class="w-full sm:w-auto bg-green-600 hover:bg-green-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||||||
|
id="calendarAiBtn"
|
||||||
|
>
|
||||||
|
<i class="fas fa-robot"></i>
|
||||||
|
<span>Execute</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Commands -->
|
||||||
|
<div class="mt-4 flex flex-wrap gap-2">
|
||||||
|
<span class="text-sm text-gray-500 mr-2">Quick commands:</span>
|
||||||
|
<button onclick="setCalendarCommand('Show today\'s schedule')" class="text-xs bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Today's Schedule
|
||||||
|
</button>
|
||||||
|
<button onclick="setCalendarCommand('Find free time this week')" class="text-xs bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Find Free Time
|
||||||
|
</button>
|
||||||
|
<button onclick="setCalendarCommand('Schedule team meeting')" class="text-xs bg-green-100 hover:bg-green-200 text-green-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Schedule Meeting
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Dashboard -->
|
||||||
|
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-calendar-day text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="todayMeetings">5</div>
|
||||||
|
<div class="text-sm text-gray-500">Today</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-clock text-orange-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="nextMeeting">2:30 PM</div>
|
||||||
|
<div class="text-sm text-gray-500">Next</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-check-circle text-green-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="freeSlots">3</div>
|
||||||
|
<div class="text-sm text-gray-500">Free Slots</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-robot text-purple-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="aiScheduled">12</div>
|
||||||
|
<div class="text-sm text-gray-500">AI Scheduled</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Calendar Interface -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
<!-- Calendar View & Today's Schedule -->
|
||||||
|
<div class="lg:col-span-2 space-y-6">
|
||||||
|
|
||||||
|
<!-- Mini Calendar -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">December 2024</h3>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button class="p-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors">
|
||||||
|
<i class="fas fa-chevron-left text-gray-600"></i>
|
||||||
|
</button>
|
||||||
|
<button class="p-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors">
|
||||||
|
<i class="fas fa-chevron-right text-gray-600"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-7 gap-1 mb-2">
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Sun</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Mon</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Tue</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Wed</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Thu</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Fri</div>
|
||||||
|
<div class="text-center text-sm font-medium text-gray-500 py-2">Sat</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-7 gap-1">
|
||||||
|
<!-- Calendar days -->
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-500 bg-gray-50">1</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 today bg-blue-100 border-2 border-blue-500">2</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 has-events bg-green-100">3</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">4</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 has-events bg-green-100">5</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">6</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">7</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">8</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 has-events bg-green-100">9</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">10</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">11</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 has-events bg-green-100">12</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">13</div>
|
||||||
|
<div class="calendar-day rounded-lg p-2 text-center text-gray-800 hover:bg-gray-100">14</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Today's Schedule -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Today's Schedule</h3>
|
||||||
|
<span class="text-sm text-gray-500">Monday, Dec 2, 2024</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-4 custom-scrollbar max-h-96 overflow-y-auto" id="scheduleList">
|
||||||
|
<!-- Current Meeting -->
|
||||||
|
<div class="meeting-current p-4 rounded-lg border border-red-200">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-3 h-3 bg-red-500 rounded-full animate-pulse"></div>
|
||||||
|
<span class="font-semibold text-gray-800">Team Standup</span>
|
||||||
|
<span class="px-2 py-1 bg-red-100 text-red-700 text-xs rounded-full">Live</span>
|
||||||
|
</div>
|
||||||
|
<span class="text-sm text-gray-500">9:00 - 9:30 AM</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mb-2">Daily sync with development team</p>
|
||||||
|
<div class="flex items-center gap-4 text-xs text-gray-500">
|
||||||
|
<span><i class="fas fa-users mr-1"></i>8 attendees</span>
|
||||||
|
<span><i class="fas fa-video mr-1"></i>Zoom Meeting</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upcoming Meetings -->
|
||||||
|
<div class="meeting-upcoming p-4 rounded-lg border border-blue-200">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="font-semibold text-gray-800">Client Presentation</span>
|
||||||
|
<span class="text-sm text-gray-500">2:30 - 3:30 PM</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mb-2">Q4 strategy review with ABC Corp</p>
|
||||||
|
<div class="flex items-center gap-4 text-xs text-gray-500 mb-2">
|
||||||
|
<span><i class="fas fa-users mr-1"></i>5 attendees</span>
|
||||||
|
<span><i class="fas fa-map-marker-alt mr-1"></i>Conference Room A</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button class="px-3 py-1 bg-blue-600 text-white text-xs rounded-lg hover:bg-blue-700 transition-colors">Join</button>
|
||||||
|
<button class="px-3 py-1 bg-gray-100 text-gray-700 text-xs rounded-lg hover:bg-gray-200 transition-colors">Reschedule</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meeting-upcoming p-4 rounded-lg border border-blue-200">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="font-semibold text-gray-800">Budget Review</span>
|
||||||
|
<span class="text-sm text-gray-500">4:00 - 5:00 PM</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mb-2">Monthly financial planning session</p>
|
||||||
|
<div class="flex items-center gap-4 text-xs text-gray-500">
|
||||||
|
<span><i class="fas fa-users mr-1"></i>3 attendees</span>
|
||||||
|
<span><i class="fas fa-video mr-1"></i>Teams Meeting</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Free Time Block -->
|
||||||
|
<div class="p-4 rounded-lg border-2 border-dashed border-green-400 bg-green-50">
|
||||||
|
<div class="flex items-center justify-between mb-2">
|
||||||
|
<span class="font-semibold text-green-700">Focus Time</span>
|
||||||
|
<span class="text-sm text-green-600">10:00 - 12:00 PM</span>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-green-600">2-hour block reserved for deep work</p>
|
||||||
|
<div class="flex items-center gap-2 text-xs text-green-600 mt-2">
|
||||||
|
<i class="fas fa-brain mr-1"></i>AI Protected Time
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Actions Panel -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Quick Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Quick Actions</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<button onclick="scheduleMeeting()" class="w-full p-3 bg-green-600 hover:bg-green-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
<span>Schedule Meeting</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="findFreeTime()" class="w-full p-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<span>Find Free Time</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="blockFocusTime()" class="w-full p-3 bg-purple-600 hover:bg-purple-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-brain"></i>
|
||||||
|
<span>Block Focus Time</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="optimizeSchedule()" class="w-full p-3 bg-orange-600 hover:bg-orange-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-magic"></i>
|
||||||
|
<span>Optimize Schedule</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Time Analysis -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Time Analysis</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="bg-blue-50 rounded-lg p-3 border border-blue-200">
|
||||||
|
<h4 class="font-medium text-blue-700 mb-1">Meeting Load</h4>
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-2 mb-1">
|
||||||
|
<div class="bg-blue-500 h-2 rounded-full" style="width: 65%"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-blue-600">65% of day in meetings</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 rounded-lg p-3 border border-green-200">
|
||||||
|
<h4 class="font-medium text-green-700 mb-1">Focus Time</h4>
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-2 mb-1">
|
||||||
|
<div class="bg-green-500 h-2 rounded-full" style="width: 35%"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-green-600">2.8 hours available</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||||||
|
<h4 class="font-medium text-orange-700 mb-1">Efficiency Score</h4>
|
||||||
|
<p class="text-2xl font-bold text-orange-600">87%</p>
|
||||||
|
<p class="text-sm text-orange-600">Above average</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upcoming Conflicts -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">AI Insights</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-yellow-700 mb-1">⚠️ Potential Conflict</h4>
|
||||||
|
<p class="text-sm text-yellow-600">Tomorrow 3PM: Two meetings scheduled</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-blue-700 mb-1">💡 Suggestion</h4>
|
||||||
|
<p class="text-sm text-blue-600">Move standup to 8:30 AM for better flow</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 border border-green-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-green-700 mb-1">✨ Opportunity</h4>
|
||||||
|
<p class="text-sm text-green-600">Friday 2-4 PM available for deep work</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent AI Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Recent AI Actions</h3>
|
||||||
|
<div class="space-y-3 custom-scrollbar max-h-48 overflow-y-auto">
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-green-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-calendar-plus text-green-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Scheduled team meeting</p>
|
||||||
|
<p class="text-xs text-gray-500">3 minutes ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-blue-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-search text-blue-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Found optimal meeting time</p>
|
||||||
|
<p class="text-xs text-gray-500">8 minutes ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-purple-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-brain text-purple-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Protected focus time</p>
|
||||||
|
<p class="text-xs text-gray-500">15 minutes ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Response Modal -->
|
||||||
|
<div id="aiModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-robot text-green-600"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Calendar AI Response</h3>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeAIModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 overflow-y-auto custom-scrollbar" id="aiResponse">
|
||||||
|
<!-- AI response content will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts at the end -->
|
||||||
|
<script src="assets/js/utils.js"></script>
|
||||||
|
<script src="assets/js/navigation.js"></script>
|
||||||
|
<script src="assets/js/calendar-agent.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
253
email-agent.html
Normal file
253
email-agent.html
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Email Agent - AI Email Management</title>
|
||||||
|
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Your Custom Files -->
|
||||||
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation Header -->
|
||||||
|
<nav class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button onclick="goHome()" class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center hover:bg-indigo-200 transition-colors">
|
||||||
|
<i class="fas fa-home text-indigo-600"></i>
|
||||||
|
</button>
|
||||||
|
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center shadow-lg">
|
||||||
|
<i class="fas fa-envelope text-white text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-lg font-bold text-gray-800">Email Agent</h1>
|
||||||
|
<p class="text-sm text-gray-500">AI Email Management</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm text-gray-500">Last sync</p>
|
||||||
|
<p class="font-semibold text-gray-800" id="lastSync">Just now</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<span class="text-sm text-green-600 font-medium">Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 bg-gray-50 min-h-screen">
|
||||||
|
|
||||||
|
<!-- Header Section -->
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl lg:text-4xl font-bold text-gray-800 mb-4">AI Email Management</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Search & Filter -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div class="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-search text-white"></i>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-800">Email Summary Search</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3 mb-4">
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
id="searchQuery"
|
||||||
|
type="text"
|
||||||
|
placeholder="Search emails by subject, sender, or content..."
|
||||||
|
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/50 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="searchEmails()"
|
||||||
|
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||||||
|
id="searchBtn"
|
||||||
|
>
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<span>Search</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Buttons -->
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span class="text-sm text-gray-500 mr-2">Filter by:</span>
|
||||||
|
<button onclick="filterEmails('all')" class="filter-btn active text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors" data-filter="all">
|
||||||
|
All Items
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('email')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-filter="email">
|
||||||
|
<i class="fas fa-envelope mr-1"></i>Emails
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('pdf')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-filter="pdf">
|
||||||
|
<i class="fas fa-file-pdf mr-1"></i>PDFs
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('image')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-filter="image">
|
||||||
|
<i class="fas fa-image mr-1"></i>Images
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Dashboard -->
|
||||||
|
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-envelope text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="totalCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Total Items</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-exclamation-triangle text-orange-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="priorityCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">High Priority</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-check-circle text-green-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="processedCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Processed</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-robot text-purple-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="aiActionsCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">AI Analyzed</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Email Interface -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
<!-- Email List -->
|
||||||
|
<div class="lg:col-span-2">
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Summarised Emails</h3>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<button onclick="refreshEmails()" class="p-2 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors" title="Refresh">
|
||||||
|
<i class="fas fa-sync-alt text-gray-600"></i>
|
||||||
|
</button>
|
||||||
|
<button onclick="exportEmails()" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-2 rounded-lg transition-colors flex items-center gap-2" title="Export">
|
||||||
|
<i class="fas fa-download text-xs"></i>
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div id="loadingState" class="hidden">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="loading-skeleton rounded-lg p-4 h-20"></div>
|
||||||
|
<div class="loading-skeleton rounded-lg p-4 h-20"></div>
|
||||||
|
<div class="loading-skeleton rounded-lg p-4 h-20"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email List Container -->
|
||||||
|
<div id="emailList" class="space-y-3 custom-scrollbar max-h-96 overflow-y-auto">
|
||||||
|
<!-- Emails will be loaded here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Empty State -->
|
||||||
|
<div id="emptyState" class="text-center py-12">
|
||||||
|
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||||
|
<i class="fas fa-inbox text-gray-400 text-2xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-600 mb-2">No emails found</h3>
|
||||||
|
<p class="text-gray-500">Your processed emails will appear here</p>
|
||||||
|
<button onclick="loadEmails()" class="mt-4 bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors">
|
||||||
|
Load Emails
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Actions Panel -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Quick Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Quick Actions</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<button onclick="loadEmails()" class="w-full p-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-refresh"></i>
|
||||||
|
<span>Refresh Emails</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('email')" class="w-full p-3 bg-green-600 hover:bg-green-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-envelope"></i>
|
||||||
|
<span>Show Emails Only</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('pdf')" class="w-full p-3 bg-red-600 hover:bg-red-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-file-pdf"></i>
|
||||||
|
<span>Show PDFs Only</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="filterEmails('image')" class="w-full p-3 bg-purple-600 hover:bg-purple-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-image"></i>
|
||||||
|
<span>Show Images Only</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Detail Modal -->
|
||||||
|
<div id="emailModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-4xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-envelope text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Email Details</h3>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeEmailModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 overflow-y-auto custom-scrollbar" id="emailContent">
|
||||||
|
<!-- Email details will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts at the end -->
|
||||||
|
<script src="assets/js/utils.js"></script>
|
||||||
|
<script src="assets/js/navigation.js"></script>
|
||||||
|
<script src="assets/js/email-agent.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
250
index.html
Normal file
250
index.html
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Victor AI - AI Services Hub</title>
|
||||||
|
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Your Custom Files -->
|
||||||
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Header -->
|
||||||
|
<nav class="bg-white/10 backdrop-blur-md border-b border-white/20 sticky top-0 z-50">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-[180px] h-12 flex items-center">
|
||||||
|
|
||||||
|
|
||||||
|
<img src="/logo.png" alt="Logo" class="w-full h-full object-contain" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm text-gray-200">System Status</p>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<span class="text-sm font-medium text-white">All Systems Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-16">
|
||||||
|
|
||||||
|
<!-- Hero Section -->
|
||||||
|
<div class="text-center mb-16">
|
||||||
|
<div class="float-animation mb-8">
|
||||||
|
<div class="w-24 h-24 bg-indigo-600 rounded-3xl flex items-center justify-center mx-auto shadow-2xl pulse-glow">
|
||||||
|
<i class="fas fa-rocket text-white text-4xl"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h1 class="text-4xl lg:text-6xl font-bold text-white mb-6">
|
||||||
|
Welcome to <span class="text-indigo-200">Victor AI</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Services Grid -->
|
||||||
|
<div class="service-grid grid gap-8 lg:gap-12">
|
||||||
|
|
||||||
|
<!-- AI Agents Section -->
|
||||||
|
<div class="col-span-full">
|
||||||
|
<h2 class="text-2xl font-bold text-white text-center mb-8">AI Agents</h2>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
|
|
||||||
|
<!-- Trade Intelligence Agent -->
|
||||||
|
<div class="service-card rounded-2xl p-6 group cursor-pointer shadow-lg" onclick="navigateToService('trade-intelligence')">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-12 h-12 bg-blue-600 rounded-xl flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform shadow-lg">
|
||||||
|
<i class="fas fa-ship text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-2">Trade Intelligence</h3>
|
||||||
|
<p class="text-gray-600 text-sm mb-4">Find exporters, importers, and trade data worldwide</p>
|
||||||
|
<div class="bg-blue-50 rounded-lg p-3 mb-4">
|
||||||
|
<div class="text-lg font-bold text-blue-600">50K+</div>
|
||||||
|
<div class="text-xs text-gray-600">Companies</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 px-4 rounded-lg text-sm transition-colors">
|
||||||
|
Open Trade Intelligence
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Email Agent -->
|
||||||
|
<div class="service-card rounded-2xl p-6 group cursor-pointer shadow-lg" onclick="navigateToService('email-agent')">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-12 h-12 bg-purple-600 rounded-xl flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform shadow-lg">
|
||||||
|
<i class="fas fa-envelope text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-2">Email Agent</h3>
|
||||||
|
<p class="text-gray-600 text-sm mb-4">Smart email management and summarization</p>
|
||||||
|
<div class="bg-purple-50 rounded-lg p-3 mb-4">
|
||||||
|
<div class="text-lg font-bold text-purple-600">23</div>
|
||||||
|
<div class="text-xs text-gray-600">Unread Emails</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full bg-purple-600 hover:bg-purple-700 text-white py-2 px-4 rounded-lg text-sm transition-colors">
|
||||||
|
Open Email Agent
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Calendar Agent -->
|
||||||
|
<div class="service-card rounded-2xl p-6 group cursor-pointer shadow-lg" onclick="navigateToService('calendar-agent')">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-12 h-12 bg-green-600 rounded-xl flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform shadow-lg">
|
||||||
|
<i class="fas fa-calendar text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-2">Calendar Agent</h3>
|
||||||
|
<p class="text-gray-600 text-sm mb-4">Intelligent scheduling and meeting management</p>
|
||||||
|
<div class="bg-green-50 rounded-lg p-3 mb-4">
|
||||||
|
<div class="text-lg font-bold text-green-600">2:30 PM</div>
|
||||||
|
<div class="text-xs text-gray-600">Next Meeting</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full bg-green-600 hover:bg-green-700 text-white py-2 px-4 rounded-lg text-sm transition-colors">
|
||||||
|
Open Calendar
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Task Agent -->
|
||||||
|
<div class="service-card rounded-2xl p-6 group cursor-pointer shadow-lg" onclick="navigateToService('task-agent')">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-12 h-12 bg-orange-600 rounded-xl flex items-center justify-center mx-auto mb-4 group-hover:scale-110 transition-transform shadow-lg">
|
||||||
|
<i class="fas fa-tasks text-white text-xl"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-2">Task Agent</h3>
|
||||||
|
<p class="text-gray-600 text-sm mb-4">Smart task management and prioritization</p>
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3 mb-4">
|
||||||
|
<div class="text-lg font-bold text-orange-600">4</div>
|
||||||
|
<div class="text-xs text-gray-600">Due Today</div>
|
||||||
|
</div>
|
||||||
|
<button class="w-full bg-orange-600 hover:bg-orange-700 text-white py-2 px-4 rounded-lg text-sm transition-colors">
|
||||||
|
Open Tasks
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Demo Modal -->
|
||||||
|
<div id="demoModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-4xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Victor AI Demo</h3>
|
||||||
|
<button onclick="closeDemoModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="aspect-video bg-gray-100 rounded-lg flex items-center justify-center mb-4">
|
||||||
|
<div class="text-center">
|
||||||
|
<i class="fas fa-play-circle text-6xl text-indigo-600 mb-4"></i>
|
||||||
|
<p class="text-gray-600">Demo video would be embedded here</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div class="bg-blue-50 p-4 rounded-lg">
|
||||||
|
<h4 class="font-semibold text-blue-800 mb-2">🚢 Trade Intelligence</h4>
|
||||||
|
<p class="text-blue-600 text-sm">Search 50K+ companies across 150+ countries</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-purple-50 p-4 rounded-lg">
|
||||||
|
<h4 class="font-semibold text-purple-800 mb-2">📧 Email Management</h4>
|
||||||
|
<p class="text-purple-600 text-sm">AI-powered email summarization and organization</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 p-4 rounded-lg">
|
||||||
|
<h4 class="font-semibold text-green-800 mb-2">📅 Smart Calendar</h4>
|
||||||
|
<p class="text-green-600 text-sm">Intelligent meeting scheduling and optimization</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-orange-50 p-4 rounded-lg">
|
||||||
|
<h4 class="font-semibold text-orange-800 mb-2">✅ Task Management</h4>
|
||||||
|
<p class="text-orange-600 text-sm">AI-driven task prioritization and tracking</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Documentation Modal -->
|
||||||
|
<div id="docModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Documentation</h3>
|
||||||
|
<button onclick="closeDocModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 overflow-y-auto">
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div>
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800 mb-3">Getting Started</h4>
|
||||||
|
<ul class="space-y-2 text-gray-600">
|
||||||
|
<li>• Choose an AI agent from the main dashboard</li>
|
||||||
|
<li>• Use natural language commands to interact</li>
|
||||||
|
<li>• View results in real-time</li>
|
||||||
|
<li>• Export data as needed</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800 mb-3">AI Agents Overview</h4>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="border-l-4 border-blue-500 pl-4">
|
||||||
|
<h5 class="font-medium text-blue-700">Trade Intelligence</h5>
|
||||||
|
<p class="text-sm text-gray-600">Search global trade data, find exporters and importers</p>
|
||||||
|
</div>
|
||||||
|
<div class="border-l-4 border-purple-500 pl-4">
|
||||||
|
<h5 class="font-medium text-purple-700">Email Agent</h5>
|
||||||
|
<p class="text-sm text-gray-600">Manage emails, create summaries, organize inbox</p>
|
||||||
|
</div>
|
||||||
|
<div class="border-l-4 border-green-500 pl-4">
|
||||||
|
<h5 class="font-medium text-green-700">Calendar Agent</h5>
|
||||||
|
<p class="text-sm text-gray-600">Schedule meetings, find optimal times, manage calendar</p>
|
||||||
|
</div>
|
||||||
|
<div class="border-l-4 border-orange-500 pl-4">
|
||||||
|
<h5 class="font-medium text-orange-700">Task Agent</h5>
|
||||||
|
<p class="text-sm text-gray-600">Prioritize tasks, track progress, manage workload</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4 class="text-lg font-semibold text-gray-800 mb-3">Support</h4>
|
||||||
|
<p class="text-gray-600 mb-3">Need help? Contact our support team:</p>
|
||||||
|
<div class="bg-gray-50 p-4 rounded-lg">
|
||||||
|
<p class="text-sm text-gray-700">📧 support@victorai.com</p>
|
||||||
|
<p class="text-sm text-gray-700">💬 Live chat available 24/7</p>
|
||||||
|
<p class="text-sm text-gray-700">📞 +1 (555) 123-4567</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts at the end -->
|
||||||
|
<script src="assets/js/utils.js"></script>
|
||||||
|
<script src="assets/js/navigation.js"></script>
|
||||||
|
<script src="assets/js/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
477
task-agent.html
Normal file
477
task-agent.html
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Task Agent - AI Task Management</title>
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Your Custom Files -->
|
||||||
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation Header -->
|
||||||
|
<nav class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button onclick="goHome()" class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center hover:bg-indigo-200 transition-colors">
|
||||||
|
<i class="fas fa-home text-indigo-600"></i>
|
||||||
|
</button>
|
||||||
|
<div class="w-10 h-10 bg-orange-600 rounded-xl flex items-center justify-center shadow-lg">
|
||||||
|
<i class="fas fa-tasks text-white text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-lg font-bold text-gray-800">Task Agent</h1>
|
||||||
|
<p class="text-sm text-gray-500">AI Task Management</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm text-gray-500">Last update</p>
|
||||||
|
<p class="font-semibold text-gray-800" id="lastUpdate">Loading...</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<span class="text-sm text-green-600 font-medium">Connected</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 bg-gray-50 min-h-screen">
|
||||||
|
|
||||||
|
<!-- Header Section -->
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl lg:text-4xl font-bold text-gray-800 mb-4">AI Task Management</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Task Command Center & Search -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div class="w-10 h-10 bg-orange-600 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-brain text-white"></i>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-800">Task AI Command & Search</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-4">
|
||||||
|
<!-- AI Command -->
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
id="taskCommand"
|
||||||
|
type="text"
|
||||||
|
placeholder="Ask AI: 'Show overdue tasks', 'Prioritize my tasks', 'Create daily standup task'"
|
||||||
|
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-orange-400 focus:ring-2 focus:ring-orange-400/50 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="executeTaskCommand()"
|
||||||
|
class="w-full sm:w-auto bg-orange-600 hover:bg-orange-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||||||
|
id="taskAiBtn"
|
||||||
|
>
|
||||||
|
<i class="fas fa-robot"></i>
|
||||||
|
<span>Execute</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Task Search -->
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3">
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
id="taskSearchInput"
|
||||||
|
type="text"
|
||||||
|
placeholder="Search tasks by name or description..."
|
||||||
|
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/50 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="taskAgent && taskAgent.handleSearch()"
|
||||||
|
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||||||
|
>
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<span>Search</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Commands -->
|
||||||
|
<div class="flex flex-wrap gap-2 mb-4">
|
||||||
|
<span class="text-sm text-gray-500 mr-2">Quick commands:</span>
|
||||||
|
<button onclick="setTaskCommand('Show overdue tasks')" class="text-xs bg-orange-100 hover:bg-orange-200 text-orange-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Overdue Tasks
|
||||||
|
</button>
|
||||||
|
<button onclick="setTaskCommand('Create daily standup task')" class="text-xs bg-orange-100 hover:bg-orange-200 text-orange-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Create Task
|
||||||
|
</button>
|
||||||
|
<button onclick="setTaskCommand('Prioritize by deadline')" class="text-xs bg-orange-100 hover:bg-orange-200 text-orange-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Smart Prioritize
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Filters -->
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span class="text-sm text-gray-500 mr-2">Filter by status:</span>
|
||||||
|
<button onclick="taskAgent && taskAgent.handleFilter('all')" class="filter-btn text-xs bg-orange-200 text-orange-800 px-3 py-1 rounded-full transition-colors" data-status="all">
|
||||||
|
All Tasks
|
||||||
|
</button>
|
||||||
|
<button onclick="taskAgent && taskAgent.handleFilter('todo')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-status="todo">
|
||||||
|
To Do
|
||||||
|
</button>
|
||||||
|
<button onclick="taskAgent && taskAgent.handleFilter('inprogress')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-status="inprogress">
|
||||||
|
In Progress
|
||||||
|
</button>
|
||||||
|
<button onclick="taskAgent && taskAgent.handleFilter('done')" class="filter-btn text-xs bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-1 rounded-full transition-colors" data-status="done">
|
||||||
|
Completed
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Stats Dashboard -->
|
||||||
|
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-red-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-exclamation-triangle text-red-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="overdueCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Overdue</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-clock text-orange-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="dueTodayCount">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Due Today</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-list text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="totalTasks">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Total</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||||||
|
<i class="fas fa-check-circle text-green-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="text-2xl font-bold text-gray-800" id="completedToday">0</div>
|
||||||
|
<div class="text-sm text-gray-500">Completed</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div id="loadingState" class="hidden bg-white rounded-2xl p-8 shadow-lg border border-gray-200 mb-8">
|
||||||
|
<div class="flex items-center justify-center">
|
||||||
|
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-orange-600 mr-3"></div>
|
||||||
|
<span class="text-gray-600">Loading tasks...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Task Interface -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
||||||
|
|
||||||
|
<!-- Kanban Board -->
|
||||||
|
<div class="lg:col-span-3">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
<!-- To Do Column -->
|
||||||
|
<div id="todoColumn" class="bg-white rounded-2xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<div class="w-3 h-3 bg-gray-400 rounded-full"></div>
|
||||||
|
To Do
|
||||||
|
</h3>
|
||||||
|
<span class="text-sm text-gray-500 bg-gray-100 px-2 py-1 rounded-full">0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3 kanban-column custom-scrollbar overflow-y-auto" style="min-height: 400px;">
|
||||||
|
<!-- Tasks will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- In Progress Column -->
|
||||||
|
<div id="inProgressColumn" class="bg-white rounded-2xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<div class="w-3 h-3 bg-orange-400 rounded-full"></div>
|
||||||
|
In Progress
|
||||||
|
</h3>
|
||||||
|
<span class="text-sm text-gray-500 bg-gray-100 px-2 py-1 rounded-full">0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3 kanban-column custom-scrollbar overflow-y-auto" style="min-height: 400px;">
|
||||||
|
<!-- Tasks will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Done Column -->
|
||||||
|
<div id="doneColumn" class="bg-white rounded-2xl p-4 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-4">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 flex items-center gap-2">
|
||||||
|
<div class="w-3 h-3 bg-green-400 rounded-full"></div>
|
||||||
|
Done
|
||||||
|
</h3>
|
||||||
|
<span class="text-sm text-gray-500 bg-gray-100 px-2 py-1 rounded-full">0</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="space-y-3 kanban-column custom-scrollbar overflow-y-auto" style="min-height: 400px;">
|
||||||
|
<!-- Tasks will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Actions Panel -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Quick Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Quick Actions</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<button onclick="createTask()" class="w-full p-3 bg-orange-600 hover:bg-orange-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
<span>Create Task</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="prioritizeTasks()" class="w-full p-3 bg-purple-600 hover:bg-purple-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-sort-amount-down"></i>
|
||||||
|
<span>AI Prioritize</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="bulkUpdate()" class="w-full p-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
<span>Bulk Update</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="generateReport()" class="w-full p-3 bg-green-600 hover:bg-green-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-chart-bar"></i>
|
||||||
|
<span>Progress Report</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Connection Status -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Data Source</h3>
|
||||||
|
<div class="flex items-center gap-3 p-3 bg-green-50 border border-green-200 rounded-lg">
|
||||||
|
<div class="w-8 h-8 bg-green-100 rounded flex items-center justify-center">
|
||||||
|
<i class="fas fa-table text-green-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<p class="text-sm font-medium text-green-800">Sample Data</p>
|
||||||
|
<p class="text-xs text-green-600">Demo Mode Active</p>
|
||||||
|
</div>
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
</div>
|
||||||
|
<button onclick="taskAgent && taskAgent.loadSampleTasks()" class="w-full mt-3 text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 py-2 px-3 rounded-lg transition-colors">
|
||||||
|
<i class="fas fa-sync-alt mr-1"></i>
|
||||||
|
Refresh Data
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Productivity Insights -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Productivity Insights</h3>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="bg-green-50 rounded-lg p-3 border border-green-200">
|
||||||
|
<h4 class="font-medium text-green-700 mb-1">Completion Rate</h4>
|
||||||
|
<div class="w-full bg-gray-200 rounded-full h-2 mb-1">
|
||||||
|
<div class="bg-green-500 h-2 rounded-full" style="width: 87%"></div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-green-600">87% (Above average)</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-blue-50 rounded-lg p-3 border border-blue-200">
|
||||||
|
<h4 class="font-medium text-blue-700 mb-1">Focus Score</h4>
|
||||||
|
<div class="text-2xl font-bold text-blue-600">8.2/10</div>
|
||||||
|
<p class="text-sm text-blue-600">Excellent focus</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||||||
|
<h4 class="font-medium text-orange-700 mb-1">Avg Task Time</h4>
|
||||||
|
<p class="text-lg font-bold text-orange-600">2.3 days</p>
|
||||||
|
<p class="text-sm text-orange-600">15% faster this week</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Recommendations -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">AI Recommendations</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="bg-red-50 border border-red-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-red-700 mb-1">🚨 Urgent Action</h4>
|
||||||
|
<p class="text-sm text-red-600">Security audit is 2 days overdue</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-blue-50 border border-blue-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-blue-700 mb-1">💡 Suggestion</h4>
|
||||||
|
<p class="text-sm text-blue-600">Break large tasks into smaller chunks</p>
|
||||||
|
</div>
|
||||||
|
<div class="bg-green-50 border border-green-200 rounded-lg p-3">
|
||||||
|
<h4 class="font-medium text-green-700 mb-1">✨ Optimization</h4>
|
||||||
|
<p class="text-sm text-green-600">Batch similar tasks for efficiency</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent AI Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Recent AI Actions</h3>
|
||||||
|
<div class="space-y-3 custom-scrollbar max-h-48 overflow-y-auto">
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-orange-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-sort text-orange-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Auto-prioritized 5 tasks</p>
|
||||||
|
<p class="text-xs text-gray-500">3 minutes ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-green-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-check text-green-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Marked deployment complete</p>
|
||||||
|
<p class="text-xs text-gray-500">2 hours ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||||||
|
<div class="w-6 h-6 bg-blue-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||||||
|
<i class="fas fa-plus text-blue-600 text-xs"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 min-w-0">
|
||||||
|
<p class="text-sm text-gray-800">Created 3 subtasks</p>
|
||||||
|
<p class="text-xs text-gray-500">4 hours ago</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Response Modal -->
|
||||||
|
<div id="aiModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-robot text-orange-600"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Task AI Response</h3>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeAIModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 overflow-y-auto custom-scrollbar" id="aiResponse">
|
||||||
|
<!-- AI response content will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts in correct order to fix loading issues -->
|
||||||
|
<script>
|
||||||
|
// Global functions that need to be available immediately
|
||||||
|
function goHome() {
|
||||||
|
window.location.href = 'index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeTaskCommand() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.executeTaskCommand();
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTaskCommand(cmd) {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.setTaskCommand(cmd);
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTask() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.createTask();
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prioritizeTasks() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.prioritizeTasks();
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bulkUpdate() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.bulkUpdate();
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateReport() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.generateReport();
|
||||||
|
} else {
|
||||||
|
console.log('Task agent not ready yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAIModal() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
window.taskAgent.hideAIModal();
|
||||||
|
} else {
|
||||||
|
const modal = document.getElementById('aiModal');
|
||||||
|
if (modal) {
|
||||||
|
modal.classList.add('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Global functions loaded');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Load Utils first, then Task Agent -->
|
||||||
|
<script src="assets/js/utils.js"></script>
|
||||||
|
<script src="assets/js/navigation.js"></script>
|
||||||
|
<script src="assets/js/task-agent.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Override API URL for your n8n instance (after task agent loads)
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
if (window.taskAgent) {
|
||||||
|
// Replace this URL with your actual n8n webhook URL
|
||||||
|
window.taskAgent.apiUrl = 'https://thecyberlearn.app.n8n.cloud/webhook/tasks';
|
||||||
|
console.log('✅ API URL configured');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
504
trade-intelligence.html
Normal file
504
trade-intelligence.html
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Trade Intelligence - AI Trade Management</title>
|
||||||
|
<!-- External Dependencies -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Link to your existing CSS file -->
|
||||||
|
<link rel="stylesheet" href="/assets/css/styles.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation Header -->
|
||||||
|
<nav class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center py-4">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<button onclick="goHome()" class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center hover:bg-indigo-200 transition-colors">
|
||||||
|
<i class="fas fa-home text-indigo-600"></i>
|
||||||
|
</button>
|
||||||
|
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center shadow-lg">
|
||||||
|
<i class="fas fa-ship text-white text-lg"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-lg font-bold text-gray-800">Trade Intelligence</h1>
|
||||||
|
<p class="text-sm text-gray-500">Victor AI Agent</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden md:flex items-center gap-6">
|
||||||
|
<div class="text-right">
|
||||||
|
<p class="text-sm text-gray-500">Last updated</p>
|
||||||
|
<p class="font-semibold text-gray-800" id="lastUpdated">Just now</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||||||
|
<span class="text-sm text-green-600 font-medium">Online</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 bg-gray-50 min-h-screen">
|
||||||
|
|
||||||
|
<!-- Header Section -->
|
||||||
|
<div class="text-center mb-8">
|
||||||
|
<h1 class="text-3xl lg:text-4xl font-bold text-gray-800 mb-4">AI Trade Intelligence</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Enhanced Search Command Center -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center gap-3 mb-4">
|
||||||
|
<div class="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-brain text-white"></i>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-xl font-bold text-gray-800">Trade AI Command</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Search Bar -->
|
||||||
|
<div class="flex flex-col sm:flex-row gap-3 mb-4">
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
id="query"
|
||||||
|
type="text"
|
||||||
|
placeholder="Ask AI: 'find seller from india', 'find buyer from uk', 'find coca cola sellers'"
|
||||||
|
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/50 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onclick="callWorkflow()"
|
||||||
|
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||||||
|
id="searchBtn"
|
||||||
|
>
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<span>Search</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Quick Searches -->
|
||||||
|
<div class="mb-4">
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span class="text-sm text-gray-500 mr-2">Quick searches:</span>
|
||||||
|
<button onclick="setQuickSearch('find seller from india')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Sellers from India
|
||||||
|
</button>
|
||||||
|
<button onclick="setQuickSearch('find buyer from uk')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
UK Buyers
|
||||||
|
</button>
|
||||||
|
<button onclick="setQuickSearch('find pepsi sellers')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Pepsi Sellers
|
||||||
|
</button>
|
||||||
|
<button onclick="setQuickSearch('find cosmetic buyers')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||||||
|
Cosmetic Buyers
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Advanced Search Panel -->
|
||||||
|
<div class="border-t border-gray-200 pt-4">
|
||||||
|
<div class="flex items-center gap-2 mb-4">
|
||||||
|
<i class="fas fa-sliders-h text-gray-600"></i>
|
||||||
|
<h3 class="text-sm font-semibold text-gray-700">Advanced Filters</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||||
|
<!-- Search Type -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Search Type</label>
|
||||||
|
<select id="searchType" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||||
|
<option value="all">All Companies</option>
|
||||||
|
<option value="buyer">Buyers Only</option>
|
||||||
|
<option value="seller">Sellers Only</option>
|
||||||
|
<option value="product-match">Product Mapping</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Product/Brand -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Product/Brand</label>
|
||||||
|
<input
|
||||||
|
id="productSearch"
|
||||||
|
type="text"
|
||||||
|
placeholder="e.g., Pepsi, Coca Cola, FMCG"
|
||||||
|
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Country -->
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Country</label>
|
||||||
|
<select id="countryFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||||
|
<option value="">All Countries</option>
|
||||||
|
<option value="India">India</option>
|
||||||
|
<option value="United Kingdom">United Kingdom</option>
|
||||||
|
<option value="United States">United States</option>
|
||||||
|
<option value="UAE">UAE</option>
|
||||||
|
<option value="China">China</option>
|
||||||
|
<option value="Germany">Germany</option>
|
||||||
|
<option value="France">France</option>
|
||||||
|
<option value="Italy">Italy</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Advanced Search Actions -->
|
||||||
|
<div class="flex flex-wrap gap-3">
|
||||||
|
<button
|
||||||
|
onclick="performAdvancedSearch()"
|
||||||
|
class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-lg font-semibold transition-all flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
Advanced Search
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="performProductMatching()"
|
||||||
|
class="bg-purple-600 hover:bg-purple-700 text-white px-6 py-2 rounded-lg font-semibold transition-all flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<i class="fas fa-link"></i>
|
||||||
|
Find Product Mapping
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="resetAdvancedFilters()"
|
||||||
|
class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg font-medium transition-all flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<i class="fas fa-undo"></i>
|
||||||
|
Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Product Matching Results Section -->
|
||||||
|
<div id="productMatchingResults" class="hidden bg-white rounded-2xl p-6 shadow-lg border border-gray-200 mb-8">
|
||||||
|
<div class="flex items-center gap-3 mb-6">
|
||||||
|
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-link text-purple-600"></i>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Product Mapping Results</h3>
|
||||||
|
<p class="text-gray-600" id="productMatchingSubtitle">Find buyers and sellers for your products</p>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeProductMatching()" class="text-gray-400 hover:text-gray-600 p-2">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Product Info Header -->
|
||||||
|
<div class="bg-gradient-to-r from-purple-50 to-blue-50 rounded-lg p-4 mb-6" id="productInfoHeader">
|
||||||
|
<!-- Product details will be populated here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Buyers and Sellers Grid -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
|
<!-- Buyers Section -->
|
||||||
|
<div class="bg-blue-50 rounded-lg p-4">
|
||||||
|
<div class="flex items-center gap-2 mb-4">
|
||||||
|
<i class="fas fa-shopping-cart text-blue-600"></i>
|
||||||
|
<h4 class="text-lg font-semibold text-blue-800" id="buyersTitle">Buyers (0)</h4>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3 max-h-96 overflow-y-auto custom-scrollbar" id="buyersList">
|
||||||
|
<!-- Buyers will be populated here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sellers Section -->
|
||||||
|
<div class="bg-green-50 rounded-lg p-4">
|
||||||
|
<div class="flex items-center gap-2 mb-4">
|
||||||
|
<i class="fas fa-store text-green-600"></i>
|
||||||
|
<h4 class="text-lg font-semibold text-green-800" id="sellersTitle">Sellers (0)</h4>
|
||||||
|
</div>
|
||||||
|
<div class="space-y-3 max-h-96 overflow-y-auto custom-scrollbar" id="sellersList">
|
||||||
|
<!-- Sellers will be populated here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Main Content Grid -->
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
|
|
||||||
|
<!-- Results Section -->
|
||||||
|
<div class="lg:col-span-2">
|
||||||
|
<!-- Results will show here -->
|
||||||
|
<div id="resultsSection" class="hidden">
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<div class="flex items-center justify-between mb-6">
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Search Results</h3>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<p id="resultsCount" class="text-sm text-gray-600"></p>
|
||||||
|
<select id="sortBy" onchange="sortResults()" class="text-sm border border-gray-300 rounded px-2 py-1">
|
||||||
|
<option value="default">Default</option>
|
||||||
|
<option value="name">Sort by Name</option>
|
||||||
|
<option value="country">Sort by Country</option>
|
||||||
|
<option value="products">Sort by Products</option>
|
||||||
|
</select>
|
||||||
|
<button onclick="exportResults()" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-2 rounded-lg transition-colors flex items-center gap-2">
|
||||||
|
<i class="fas fa-download text-xs"></i>
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="results" class="grid grid-cols-1 gap-4 custom-scrollbar max-h-dvh overflow-y-auto"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Actions Panel -->
|
||||||
|
<div class="space-y-6">
|
||||||
|
|
||||||
|
<!-- Quick Actions -->
|
||||||
|
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||||||
|
<h3 class="text-lg font-bold text-gray-800 mb-4">Quick Actions</h3>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<button onclick="quickSearch('all buyers')" class="w-full p-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
<span>All Buyers</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="quickSearch('all sellers')" class="w-full p-3 bg-green-600 hover:bg-green-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-ship"></i>
|
||||||
|
<span>All Sellers</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="quickSearch('gulfood data')" class="w-full p-3 bg-orange-600 hover:bg-orange-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-globe"></i>
|
||||||
|
<span>Gulfood Data</span>
|
||||||
|
</button>
|
||||||
|
<button onclick="clearResults()" class="w-full p-3 bg-gray-600 hover:bg-gray-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||||||
|
<i class="fas fa-broom"></i>
|
||||||
|
<span>Clear Results</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CRUD Elements - Fixed positioning outside main content -->
|
||||||
|
|
||||||
|
<!-- Minimal CRUD Wrench Icon -->
|
||||||
|
<div class="fixed bottom-6 right-6 z-50">
|
||||||
|
<button
|
||||||
|
onclick="toggleCrudModal()"
|
||||||
|
class="w-14 h-14 bg-indigo-600 hover:bg-indigo-700 text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-300 flex items-center justify-center group"
|
||||||
|
id="crudWrenchBtn"
|
||||||
|
title="Data Management Tools"
|
||||||
|
>
|
||||||
|
<i class="fas fa-wrench text-xl group-hover:rotate-12 transition-transform"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Enhanced CRUD Modal -->
|
||||||
|
<div id="crudModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-4xl w-full max-h-[90vh] overflow-hidden shadow-2xl">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-wrench text-indigo-600"></i>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">Data Management</h3>
|
||||||
|
<p class="text-gray-600">Create, update, or delete company records</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeCrudModal()" class="text-gray-400 hover:text-gray-600 p-2">
|
||||||
|
<i class="fas fa-times text-xl"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-6 max-h-[calc(90vh-120px)] overflow-y-auto">
|
||||||
|
<!-- Operation Selector -->
|
||||||
|
<div class="flex bg-gray-100 rounded-lg p-1 mb-6">
|
||||||
|
<button
|
||||||
|
onclick="selectCrudOperation('create')"
|
||||||
|
class="flex-1 py-3 px-4 rounded-md font-medium transition-all flex items-center justify-center gap-2"
|
||||||
|
id="createTab"
|
||||||
|
>
|
||||||
|
<i class="fas fa-plus"></i>
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="selectCrudOperation('update')"
|
||||||
|
class="flex-1 py-3 px-4 rounded-md font-medium transition-all flex items-center justify-center gap-2"
|
||||||
|
id="updateTab"
|
||||||
|
>
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onclick="selectCrudOperation('delete')"
|
||||||
|
class="flex-1 py-3 px-4 rounded-md font-medium transition-all flex items-center justify-center gap-2"
|
||||||
|
id="deleteTab"
|
||||||
|
>
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Create Form -->
|
||||||
|
<div id="createOperation" class="hidden">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Type *</label>
|
||||||
|
<select id="createType" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
<option value="">Select Type</option>
|
||||||
|
<option value="importer">Importer</option>
|
||||||
|
<option value="exporter">Exporter</option>
|
||||||
|
<option value="gulfood">Gulfood</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Company Name *</label>
|
||||||
|
<input id="createName" type="text" placeholder="Company name" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Country</label>
|
||||||
|
<select id="createCountry" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
<option value="">Loading countries...</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Email</label>
|
||||||
|
<input id="createEmail" type="email" placeholder="company@example.com" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Phone</label>
|
||||||
|
<input id="createPhone" type="text" placeholder="+1234567890" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Website</label>
|
||||||
|
<input id="createWebsite" type="url" placeholder="https://company.com" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Products/Services</label>
|
||||||
|
<textarea id="createProducts" placeholder="List of products or services" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 h-24 resize-none"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Address</label>
|
||||||
|
<textarea id="createAddress" placeholder="Company address" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 h-24 resize-none"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onclick="executeCrud('create')" class="w-full bg-green-600 hover:bg-green-700 text-white py-3 rounded-lg font-semibold transition-colors" id="createBtn">
|
||||||
|
<i class="fas fa-plus mr-2"></i>Create Company
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Update Form -->
|
||||||
|
<div id="updateOperation" class="hidden">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Company Name *</label>
|
||||||
|
<input id="updateName" type="text" placeholder="Enter company name to update" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Field to Update *</label>
|
||||||
|
<select id="updateField" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
<option value="">Select Field</option>
|
||||||
|
<option value="email">Email</option>
|
||||||
|
<option value="phone">Phone</option>
|
||||||
|
<option value="country">Country</option>
|
||||||
|
<option value="website">Website</option>
|
||||||
|
<option value="products">Products/Services</option>
|
||||||
|
<option value="address">Address</option>
|
||||||
|
<option value="type">Type</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">New Value *</label>
|
||||||
|
<input id="updateValue" type="text" placeholder="Enter new value" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onclick="executeCrud('update')" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-3 rounded-lg font-semibold transition-colors" id="updateBtn">
|
||||||
|
<i class="fas fa-edit mr-2"></i>Update Company
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete Form -->
|
||||||
|
<div id="deleteOperation" class="hidden">
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-2">Company Name *</label>
|
||||||
|
<input id="deleteName" type="text" placeholder="Enter company name to delete" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-red-500">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-red-50 border border-red-200 rounded-lg p-4">
|
||||||
|
<div class="flex items-start gap-3">
|
||||||
|
<i class="fas fa-exclamation-triangle text-red-600 mt-1"></i>
|
||||||
|
<div>
|
||||||
|
<p class="text-red-800 font-medium">Warning</p>
|
||||||
|
<p class="text-red-700 text-sm">This action cannot be undone. The company will be permanently deleted.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="flex items-center gap-2">
|
||||||
|
<input type="checkbox" id="deleteConfirm" class="rounded border-gray-300 text-red-600 focus:ring-red-500">
|
||||||
|
<span class="text-sm text-gray-700">I understand this action is permanent</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button onclick="executeCrud('delete')" class="w-full bg-red-600 hover:bg-red-700 text-white py-3 rounded-lg font-semibold transition-colors opacity-50 cursor-not-allowed" id="deleteBtn" disabled>
|
||||||
|
<i class="fas fa-trash mr-2"></i>Delete Company
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Toast Notification Container -->
|
||||||
|
<div id="toastContainer" class="fixed top-4 right-4 z-50 space-y-2">
|
||||||
|
<!-- Toast notifications will be added here -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AI Response Modal -->
|
||||||
|
<div id="aiModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||||||
|
<div class="bg-white rounded-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
|
||||||
|
<div class="p-6 border-b border-gray-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||||||
|
<i class="fas fa-robot text-blue-600"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-800">Trade AI Response</h3>
|
||||||
|
</div>
|
||||||
|
<button onclick="closeAIModal()" class="text-gray-400 hover:text-gray-600">
|
||||||
|
<i class="fas fa-times"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 overflow-y-auto custom-scrollbar" id="aiResponse">
|
||||||
|
<!-- AI response content will be loaded here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Scripts -->
|
||||||
|
<script src="assets/js/utils.js"></script>
|
||||||
|
<script src="assets/js/navigation.js"></script>
|
||||||
|
<script src="/assets/js/trade-intelligence.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user