""" Dashboard tab: at-a-glance counts of what's come in. Kept intentionally simple (stat cards, no charts) per the "just a dashboard for now" scope. The stats themselves come from app.workers.get_dashboard_stats(), so adding a new stat later is a matter of adding a key there and a card here - this widget doesn't know anything about how orders are fetched or stored. """ from __future__ import annotations from PyQt6.QtCore import Qt from PyQt6.QtWidgets import ( QWidget, QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QSizePolicy, ) class StatCard(QFrame): def __init__(self, title: str, parent=None): super().__init__(parent) self.setFrameShape(QFrame.Shape.StyledPanel) self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred) layout = QVBoxLayout(self) self.value_label = QLabel("0") value_font = self.value_label.font() value_font.setPointSize(28) value_font.setBold(True) self.value_label.setFont(value_font) self.value_label.setAlignment(Qt.AlignmentFlag.AlignCenter) title_label = QLabel(title) title_label.setAlignment(Qt.AlignmentFlag.AlignCenter) title_label.setWordWrap(True) layout.addWidget(self.value_label) layout.addWidget(title_label) def set_value(self, value) -> None: self.value_label.setText(str(value)) class DashboardWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) outer = QVBoxLayout(self) heading = QLabel("Today's Orders at a Glance") heading_font = heading.font() heading_font.setPointSize(16) heading_font.setBold(True) heading.setFont(heading_font) outer.addWidget(heading) # Top row: overall pipeline health top_row = QHBoxLayout() self.total_card = StatCard("Total Orders") self.fulfilled_card = StatCard("Fulfilled") self.fulfilled_card.setStyleSheet("QLabel { color: #1a7a1a; }") self.cancelled_card = StatCard("Cancelled") self.cancelled_card.setStyleSheet("QLabel { color: #b00020; }") self.carryover_card = StatCard("Carryover (still open from an earlier day)") self.carryover_card.setStyleSheet("QLabel { color: #b06a00; }") for card in (self.total_card, self.fulfilled_card, self.cancelled_card, self.carryover_card): top_row.addWidget(card) outer.addLayout(top_row) # Second row: tracking pull progress, since that's the 5PM task outer.addWidget(self._section_label("Tracking Numbers")) tracking_row = QHBoxLayout() self.tracking_received_card = StatCard("Tickets With Tracking Pulled") tracking_row.addWidget(self.tracking_received_card) outer.addLayout(tracking_row) # Third row: per-company totals (grid so adding a 3rd company later just works) outer.addWidget(self._section_label("By Company")) self.company_grid = QGridLayout() self.company_cards: dict[str, StatCard] = {} outer.addLayout(self.company_grid) outer.addStretch() @staticmethod def _section_label(text: str) -> QLabel: label = QLabel(text) font = label.font() font.setBold(True) label.setFont(font) return label def update_stats(self, stats: dict) -> None: self.total_card.set_value(stats.get("total", 0)) self.fulfilled_card.set_value(stats.get("fulfilled_count", 0)) self.cancelled_card.set_value(stats.get("cancelled_count", 0)) self.carryover_card.set_value(stats.get("carryover_count", 0)) self.tracking_received_card.set_value(stats.get("tracking_received_count", 0)) by_company = stats.get("by_company", {}) # Rebuild company cards if the set of companies changed (e.g. a 3rd company added) if set(by_company.keys()) != set(self.company_cards.keys()): self._rebuild_company_cards(by_company.keys()) for company, count in by_company.items(): self.company_cards[company].set_value(count) def _rebuild_company_cards(self, companies) -> None: while self.company_grid.count(): item = self.company_grid.takeAt(0) widget = item.widget() if widget: widget.deleteLater() self.company_cards.clear() for i, company in enumerate(sorted(companies)): card = StatCard(company) self.company_cards[company] = card self.company_grid.addWidget(card, i // 3, i % 3)