Deploy on 2026-06-05 16:08:53

This commit is contained in:
Hamza-Ayed
2026-06-05 16:08:53 +03:00
parent c0da60069f
commit 54065628bf
12 changed files with 316 additions and 167 deletions

View File

@@ -71,4 +71,18 @@ return [
'language' => 'اللغة',
'arabic' => 'العربية',
'english' => 'English',
'title' => 'العنوان',
'grant' => 'المنح',
'competition' => 'المسابقات',
'demo_day' => 'أيام العروض',
'event' => 'الفعاليات',
'partnership' => 'الشراكات',
'investment' => 'الاستثمارات',
'other' => 'أخرى',
'ingested_opportunities' => 'الفرص المجمعة',
'interactions_logged' => 'التفاعلات المسجلة',
'today_contacts' => 'جهات اتصال مضافة اليوم',
'today_orgs' => 'منظمات جديدة',
'recent_activities' => 'آخر النشاطات',
'recent_opportunities' => 'آخر الفرص',
];

View File

@@ -71,4 +71,18 @@ return [
'language' => 'Language',
'arabic' => 'العربية',
'english' => 'English',
'title' => 'Title',
'grant' => 'Grants',
'competition' => 'Competitions',
'demo_day' => 'Demo Days',
'event' => 'Events',
'partnership' => 'Partnerships',
'investment' => 'Investments',
'other' => 'Other',
'ingested_opportunities' => 'Ingested Opportunities',
'interactions_logged' => 'Interactions Logged',
'today_contacts' => 'Contacts Added Today',
'today_orgs' => 'new organizations',
'recent_activities' => 'Recent Activities',
'recent_opportunities' => 'Recent Opportunities',
];

View File

@@ -1,143 +1,107 @@
<div class="dashboard-header">
<h1>Welcome, <?= $this->escape($user['name']) ?></h1>
<p>Here is your daily intelligence summary for ScoutIQ.</p>
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap;">
<div>
<h1><?= $t['dashboard'] ?? 'Dashboard' ?></h1>
<p><?= $t['welcome'] ?? 'Welcome' ?>, <?= $this->escape($user['name']) ?></p>
</div>
<a href="/admin/sources" class="btn btn-primary"><?= $t['run_collector'] ?? 'Run Collector' ?></a>
</div>
</div>
<!-- Metrics Row -->
<div class="metrics-grid">
<div class="glass-panel metric-card">
<span class="metric-title">Total Investors</span>
<span class="metric-value">142</span>
<span class="metric-title"><?= $t['total_organizations'] ?? 'Organizations' ?></span>
<span class="metric-value"><?= $stats['organizations'] ?></span>
<span class="metric-footer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline><polyline points="17 6 23 6 23 12"></polyline></svg>
<span>+12% vs last month</span>
<span><?= $stats['vc'] ?> VC • <?= $stats['accelerators'] ?> Accelerators</span>
</span>
</div>
<div class="glass-panel metric-card">
<span class="metric-title">Total Accelerators</span>
<span class="metric-value">38</span>
<span class="metric-title"><?= $t['total_opportunities'] ?? 'Opportunities' ?></span>
<span class="metric-value"><?= $stats['opportunities'] ?></span>
<span class="metric-footer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline><polyline points="17 6 23 6 23 12"></polyline></svg>
<span>+5% vs last month</span>
<span><?= $stats['today'] ?> new today</span>
</span>
</div>
<div class="glass-panel metric-card">
<span class="metric-title">Open Opportunities</span>
<span class="metric-value">29</span>
<span class="metric-footer" style="color: var(--warning);">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
<span>4 closing this week</span>
<span class="metric-title"><?= $t['total_contacts'] ?? 'Contacts' ?></span>
<span class="metric-value"><?= $stats['contacts'] ?></span>
<span class="metric-footer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline><polyline points="17 6 23 6 23 12"></polyline></svg>
<span><?= $t['view_all'] ?? 'View all' ?></span>
</span>
</div>
<div class="glass-panel metric-card">
<span class="metric-title">Contacts Added Today</span>
<span class="metric-value">7</span>
<span class="metric-title"><?= $t['active_sources'] ?? 'Sources' ?></span>
<span class="metric-value"><?= $stats['sources'] ?></span>
<span class="metric-footer">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="23 6 13.5 15.5 8.5 10.5 1 18"></polyline><polyline points="17 6 23 6 23 12"></polyline></svg>
<span>+3 new organizations</span>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
<span>RSS feeds active</span>
</span>
</div>
</div>
<!-- Charts Row -->
<div class="charts-grid">
<!-- Recent Opportunities -->
<div class="glass-panel chart-card">
<span class="chart-title">Opportunities by Category</span>
<div style="flex: 1; position: relative;">
<canvas id="categoryChart"></canvas>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
<span class="chart-title"><?= $t['recent_opportunities'] ?? 'Recent Opportunities' ?></span>
<a href="/admin/opportunities" class="btn btn-sm btn-secondary"><?= $t['view_all'] ?? 'View All' ?></a>
</div>
<div style="max-height: 400px; overflow-y: auto;">
<?php if (empty($recent_opportunities)): ?>
<p style="color: var(--text-muted); text-align: center; padding: 40px;">No opportunities yet. Run the collector to start gathering data.</p>
<?php else: ?>
<?php foreach ($recent_opportunities as $opp): ?>
<div class="list-item">
<div style="display: flex; justify-content: space-between; gap: 10px;">
<div style="flex: 1; min-width: 0;">
<a href="/admin/opportunities/<?= $opp['id'] ?>" style="font-weight: 600;"><?= $this->escape(mb_substr($opp['title'], 0, 80)) ?></a>
<div style="display: flex; gap: 8px; margin-top: 4px; flex-wrap: wrap;">
<span class="badge badge-type-<?= $opp['type'] ?>"><?= $this->escape($opp['type']) ?></span>
<span style="font-size: 0.8rem; color: var(--text-muted);">Score: <?= $opp['score'] ?></span>
</div>
</div>
<small style="color: var(--text-muted); white-space: nowrap;"><?= date('M j', strtotime($opp['created_at'])) ?></small>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<!-- Recent Activities -->
<div class="glass-panel chart-card">
<span class="chart-title">Monthly Growth & Ingestion</span>
<div style="flex: 1; position: relative;">
<canvas id="growthChart"></canvas>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
<span class="chart-title"><?= $t['recent_activities'] ?? 'Recent Activity' ?></span>
</div>
<div style="max-height: 400px; overflow-y: auto;">
<?php if (empty($recent_activities)): ?>
<p style="color: var(--text-muted); text-align: center; padding: 40px;">No recent activity.</p>
<?php else: ?>
<?php foreach ($recent_activities as $activity): ?>
<div class="list-item">
<div style="display: flex; justify-content: space-between; gap: 10px;">
<div>
<span class="badge" style="background: rgba(139, 92, 246, 0.2); color: #a78bfa;"><?= $this->escape($activity['action'] ?? 'info') ?></span>
<span style="font-size: 0.85rem; color: var(--text-muted); margin-left: 8px;"><?= $this->escape(mb_substr($activity['description'] ?? '', 0, 100)) ?></span>
</div>
<small style="color: var(--text-muted); white-space: nowrap;"><?= date('M j, g:i a', strtotime($activity['created_at'])) ?></small>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</div>
<script>
// Category Chart (Doughnut)
const ctxCategory = document.getElementById('categoryChart').getContext('2d');
new Chart(ctxCategory, {
type: 'doughnut',
data: {
labels: ['Mobility & Logistics', 'AI & Automation', 'SaaS', 'Fintech', 'Marketplaces'],
datasets: [{
data: [35, 25, 20, 12, 8],
backgroundColor: [
'hsl(263, 90%, 60%)',
'hsl(220, 95%, 50%)',
'hsl(180, 100%, 40%)',
'hsl(142, 70%, 45%)',
'hsl(38, 92%, 50%)'
],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: 'hsl(215, 20%, 75%)',
font: { family: 'Inter', size: 12 }
}
}
}
}
});
// Growth Chart (Line)
const ctxGrowth = document.getElementById('growthChart').getContext('2d');
new Chart(ctxGrowth, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
datasets: [{
label: 'Ingested Opportunities',
data: [12, 19, 32, 45, 68, 96],
borderColor: 'hsl(180, 100%, 50%)',
backgroundColor: 'rgba(0, 242, 254, 0.1)',
borderWidth: 3,
fill: true,
tension: 0.4
}, {
label: 'Interactions Logged',
data: [5, 12, 18, 25, 30, 48],
borderColor: 'hsl(263, 90%, 60%)',
backgroundColor: 'transparent',
borderWidth: 3,
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: 'hsl(215, 20%, 75%)',
font: { family: 'Inter', size: 12 }
}
}
},
scales: {
x: {
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: { color: 'hsl(215, 20%, 70%)' }
},
y: {
grid: { color: 'rgba(255, 255, 255, 0.05)' },
ticks: { color: 'hsl(215, 20%, 70%)' }
}
}
}
});
</script>
<style>
.list-item { padding: 12px 0; border-bottom: 1px solid rgba(255,255,255,0.05); }
.list-item:last-child { border-bottom: none; }
</style>

View File

@@ -33,15 +33,9 @@
</div>
<div style="display: flex; gap: 12px; margin-top: 16px; flex-wrap: wrap;">
<button type="submit" name="action" value="save" class="btn btn-primary"><?= $t['save'] ?? 'Save' ?></button>
<button type="submit" name="action" value="test" class="btn btn-secondary"><?= $t['test_notification'] ?? 'Send Test' ?></button>
</div>
</form>
<form action="/admin/settings/test-telegram" method="POST" style="margin-top: 12px;">
<input type="hidden" name="_csrf" value="<?= $this->session->getCsrfToken() ?>">
<input type="hidden" name="telegram_bot_token" value="<?= $this->escape($tg_token) ?>">
<input type="hidden" name="telegram_chat_id" value="<?= $this->escape($tg_chat_id) ?>">
<button type="submit" class="btn btn-secondary"><?= $t['test_notification'] ?? 'Send Test' ?></button>
</form>
</div>
<!-- Help Info -->