- {renderPage()}
+
+
+
Аналитика Email-рассылок
+
+
+ {/* Основные метрики */}
+
+
+
👥
+
+
{stats.totalSubscribers}
+
Подписчиков
+
+
+
+
📧
+
+
{stats.totalSent}
+
Отправлено писем
+
+
+
+
+
📊
+
+
{getOpenRate()}%
+
Процент открытий
+
+
+
+
+
🔗
+
+
{getClickRate()}%
+
Процент кликов
+
+
+
+
+
📝
+
+
{stats.totalTemplates}
+
Шаблонов
+
+
+
+
+
🎯
+
+
{stats.totalCampaigns}
+
Кампаний
+
+
+
+
+ {/* Дополнительная статистика */}
+
+
+
+ Групп подписчиков:
+ {stats.totalGroups}
+
+
+ Открыто писем:
+ {stats.totalOpened}
+
+
+ Кликов по ссылкам:
+ {stats.totalClicked}
+
+
+ Отписок:
+ {stats.totalUnsubscribed} ({getUnsubscribeRate()}%)
+
+
+
+
+ {/* Последние кампании */}
+
+
Последние кампании
+ {stats.recentCampaigns.length > 0 ? (
+
+ {stats.recentCampaigns.map(campaign => (
+
+
+
Кампания #{campaign.id}
+
+
+ {campaign.status}
+
+
+
+
+ {campaign.scheduled_at ? new Date(campaign.scheduled_at).toLocaleDateString() : 'Не запланировано'}
+
+
+ ))}
+
+ ) : (
+
+
📧
+
Нет кампаний
+
Создайте первую кампанию для начала работы
+
+ )}
+
+
+ {/* Последние доставки */}
+
+
Последние доставки
+ {stats.recentDeliveries.length > 0 ? (
+
+ {stats.recentDeliveries.slice(0, 5).map(delivery => (
+
+
+
+ {delivery.Subscriber?.email || delivery.subscriber_id}
+
+
+
+ {delivery.status}
+
+
+
+
+ {delivery.sent_at ? new Date(delivery.sent_at).toLocaleString() : 'Не отправлено'}
+
+
+ ))}
+
+ ) : (
+
+
📊
+
Нет доставок
+
История доставок появится после отправки писем
+
+ )}
);
-};
+}
export default Dashboard;
\ No newline at end of file
diff --git a/frontend/src/styles/Common.module.css b/frontend/src/styles/Common.module.css
index ff0492b..23afbc4 100644
--- a/frontend/src/styles/Common.module.css
+++ b/frontend/src/styles/Common.module.css
@@ -1,3 +1,58 @@
+/* Стили для макета приложения */
+.dashboard {
+ display: flex;
+ min-height: 100vh;
+ background: #f8fafc;
+}
+
+.content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ min-width: 0; /* Предотвращает переполнение на мобильных */
+}
+
+.pageContent {
+ flex: 1;
+ padding: 32px;
+ overflow-x: auto;
+}
+
+/* Адаптивные стили для планшетов */
+@media (max-width: 1024px) {
+ .pageContent {
+ padding: 24px;
+ }
+}
+
+/* Адаптивные стили для мобильных устройств */
+@media (max-width: 768px) {
+ .dashboard {
+ flex-direction: column;
+ }
+
+ .content {
+ margin-left: 0;
+ }
+
+ .pageContent {
+ padding: 16px;
+ }
+}
+
+@media (max-width: 480px) {
+ .pageContent {
+ padding: 12px;
+ }
+}
+
+/* Улучшенная поддержка touch устройств */
+@media (hover: none) and (pointer: coarse) {
+ .pageContent {
+ -webkit-overflow-scrolling: touch;
+ }
+}
+
/* Общие стили для таблиц */
.table {
width: 100%;
@@ -383,4 +438,261 @@
.emptyStateText {
font-size: 14px;
color: #9ca3af;
+}
+
+/* Стили для главной страницы с аналитикой */
+.statsGrid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
+ gap: 12px;
+ margin-bottom: 32px;
+}
+
+.statCard {
+ background: #fff;
+ border-radius: 8px;
+ padding: 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: transform 0.2s, box-shadow 0.2s;
+}
+
+.statCard:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
+}
+
+.statIcon {
+ font-size: 20px;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #6366f1, #06b6d4);
+ border-radius: 8px;
+ color: white;
+ flex-shrink: 0;
+}
+
+.statContent {
+ flex: 1;
+ min-width: 0;
+}
+
+.statNumber {
+ font-size: 18px;
+ font-weight: 700;
+ color: #111827;
+ margin-bottom: 2px;
+ line-height: 1.1;
+}
+
+.statLabel {
+ font-size: 11px;
+ color: #6b7280;
+ font-weight: 500;
+ line-height: 1.1;
+}
+
+.additionalStats {
+ background: #fff;
+ border-radius: 12px;
+ padding: 24px;
+ margin-bottom: 32px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.statRow {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 16px;
+}
+
+.statItem {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 0;
+ border-bottom: 1px solid #f3f4f6;
+}
+
+.statItem:last-child {
+ border-bottom: none;
+}
+
+.statItem .statLabel {
+ font-size: 14px;
+ color: #6b7280;
+ font-weight: 500;
+}
+
+.statItem .statValue {
+ font-size: 16px;
+ font-weight: 600;
+ color: #111827;
+}
+
+.section {
+ background: #fff;
+ border-radius: 12px;
+ padding: 24px;
+ margin-bottom: 24px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+}
+
+.sectionTitle {
+ font-size: 20px;
+ font-weight: 600;
+ color: #111827;
+ margin: 0 0 20px 0;
+}
+
+.campaignsList,
+.deliveriesList {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.campaignItem,
+.deliveryItem {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 16px;
+ background: #f9fafb;
+ border-radius: 8px;
+ border: 1px solid #e5e7eb;
+}
+
+.campaignInfo,
+.deliveryInfo {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.campaignName,
+.deliveryEmail {
+ font-size: 16px;
+ font-weight: 500;
+ color: #111827;
+}
+
+.campaignDate,
+.deliveryDate {
+ font-size: 14px;
+ color: #6b7280;
+}
+
+.campaignStatus,
+.deliveryStatus {
+ display: flex;
+ gap: 8px;
+}
+
+.statusBadge {
+ padding: 4px 8px;
+ border-radius: 6px;
+ font-size: 12px;
+ font-weight: 500;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.statusdraft {
+ background: #fef3c7;
+ color: #92400e;
+}
+
+.statusactive {
+ background: #d1fae5;
+ color: #065f46;
+}
+
+.statussent {
+ background: #dbeafe;
+ color: #1e40af;
+}
+
+.statusdelivered {
+ background: #d1fae5;
+ color: #065f46;
+}
+
+.statusfailed {
+ background: #fee2e2;
+ color: #991b1b;
+}
+
+.statusopened {
+ background: #dbeafe;
+ color: #1e40af;
+}
+
+.statusclicked {
+ background: #e0e7ff;
+ color: #3730a3;
+}
+
+/* Адаптивные стили для главной страницы */
+@media (max-width: 768px) {
+ .statsGrid {
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
+ gap: 10px;
+ }
+
+ .statCard {
+ padding: 12px;
+ }
+
+ .statIcon {
+ width: 40px;
+ height: 40px;
+ font-size: 18px;
+ }
+
+ .statNumber {
+ font-size: 18px;
+ }
+
+ .statRow {
+ grid-template-columns: 1fr;
+ gap: 12px;
+ }
+
+ .campaignItem,
+ .deliveryItem {
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 8px;
+ }
+
+ .campaignDate,
+ .deliveryDate {
+ align-self: flex-end;
+ }
+}
+
+@media (max-width: 480px) {
+ .statsGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .statCard {
+ padding: 10px;
+ }
+
+ .statIcon {
+ width: 32px;
+ height: 32px;
+ font-size: 16px;
+ }
+
+ .statNumber {
+ font-size: 16px;
+ }
}
\ No newline at end of file