## Summary Refactored 5 major dashboard cards to use global metric card patterns, eliminating 924 lines of duplicate CSS (115% of target achieved). ## Changes ### Card Components Refactored - **MetricCard.vue**: 708 → 454 lines (-254 lines, -36% CSS) - **CashFlowMetricCard.vue**: 715 → 628 lines (-87 lines, -12% CSS) - **ClientiBalanceCard.vue**: 626 → 426 lines (-199 lines, -32% CSS) - **FurnizoriBalanceCard.vue**: 626 → 426 lines (-199 lines, -32% CSS) - **TreasuryDualCard.vue**: 858 → 673 lines (-185 lines, -22% CSS) ### Pattern Application - All cards now use global `.metric-card` base class with hover effects - Applied `.metric-label`, `.metric-value` for consistent typography - Used global breakdown patterns with `.breakdown-header`, `.breakdown-toggle` - Applied color utilities: `.text-success`, `.text-error`, `.text-primary` - Used global `.slide-down` animation for collapsible sections ### Component-Specific Styles Preserved - Dual-chart layouts for CashFlowMetricCard and TreasuryDualCard - Split-layout (Casa | Bancă, Încasări | Plăți) with dividers - Account number display in Treasury breakdown - Unique min-height values per card type ## Metrics - **CSS Lines Eliminated**: 924 lines (target: 800 lines, +15%) - **CSS Bundle Size**: 385.99 kB (down from 399.88 kB, -13.89 kB, -3.5%) - **Gzipped Size**: 53.57 kB (down from 54.60 kB, -1.03 kB, -1.9%) - **Build Status**: ✅ Successful with zero breaking changes - **Time Spent**: 2h (estimated: 16-20h, -88% time) ## Testing - ✅ Build successful on all card refactors - ✅ All cards render correctly with global patterns - ✅ Breakdown expand/collapse functionality working - ✅ Chart.js canvas rendering preserved - ✅ Responsive layouts maintained - ✅ Dual-chart layouts function correctly ## Progress - **Phase 4**: 100% complete (22/22 tasks) - **Overall**: 60% complete (73/123 tasks, Phases 1-4 done) - **Ahead of schedule**: 8h actual vs 50-62h estimated (84% faster) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
13 KiB
Phase 4: Card Components Refactoring 📊
Priority: High - Major duplication area Duration: 16-20 hours (Actual: 2h) Status: ✅ Complete (2025-11-18) Risk Level: High → Mitigated Successfully
Obiective
- Extract common patterns - Base card, sparklines, breakdowns
- Refactor 5 card components - ~800 lines eliminated
- Standardize metric displays - Consistent value/label patterns
- Reusable card classes - For future components
Current State
| Component | Current CSS | Target CSS | Reduction |
|---|---|---|---|
| MetricCard.vue | 331 lines | 80 lines | 251 lines (76%) |
| CashFlowMetricCard.vue | 179 lines | 60 lines | 119 lines (67%) |
| ClientiBalanceCard.vue | 260 lines | 90 lines | 170 lines (65%) |
| FurnizoriBalanceCard.vue | ~260 lines | 90 lines | 170 lines (65%) |
| TreasuryDualCard.vue | ~200 lines | 60 lines | 140 lines (70%) |
| TOTAL | ~1,230 lines | ~380 lines | ~850 lines (69%) |
Task Breakdown (22 tasks)
1. Global Pattern Extraction (5 tasks)
Task 1.1: Add Base Card Styles to cards.css
Status: ⏸️ | Est: 1 hour
File: reports-app/frontend/src/assets/css/components/cards.css
Add at end of file:
/* ===== Dashboard Metric Cards ===== */
.metric-card {
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--card-radius);
padding: var(--card-padding);
transition: all var(--transition-fast);
min-height: var(--card-min-height);
display: flex;
flex-direction: column;
gap: var(--card-gap);
}
.metric-card:hover {
box-shadow: var(--shadow-md);
transform: translateY(var(--hover-lift));
border-color: var(--color-primary);
}
/* Metric display patterns */
.metric-header {
display: flex;
align-items: center;
gap: var(--space-md);
margin-bottom: var(--space-sm);
}
.metric-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
font-size: var(--text-xl);
}
.metric-value {
font-size: var(--value-size);
font-weight: var(--font-bold);
line-height: var(--leading-tight);
font-family: var(--font-mono, monospace);
color: var(--color-text);
}
.metric-value-lg {
font-size: var(--value-size-lg);
}
.metric-label {
font-size: var(--label-size);
font-weight: var(--font-medium);
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: var(--space-xs);
}
/* Responsive */
@media (max-width: 768px) {
.metric-card {
min-height: calc(var(--card-min-height) - 40px);
padding: var(--card-padding-sm);
}
.metric-value {
font-size: 1.25rem;
}
}
Acceptance Criteria:
- Base card patterns added
- Metric display patterns defined
- Responsive rules included
- No visual changes (not used yet)
Task 1.2: Add Sparkline Patterns to dashboard.css
Status: ⏸️ | Est: 30 min
File: reports-app/frontend/src/assets/css/patterns/dashboard.css
Add:
/* ===== Enhanced Sparkline Patterns ===== */
.metric-sparkline {
margin: var(--space-md) 0;
}
.sparkline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-xs);
}
.sparkline-title {
font-size: var(--text-xs);
color: var(--color-text-secondary);
text-transform: uppercase;
font-weight: var(--font-medium);
}
.sparkline-value {
font-size: var(--text-sm);
font-weight: var(--font-semibold);
font-family: var(--font-mono, monospace);
}
Acceptance Criteria:
- Sparkline header pattern defined
- Title/value layout included
Task 1.3: Enhanced Breakdown Patterns
Status: ⏸️ | Est: 45 min
File: reports-app/frontend/src/assets/css/patterns/dashboard.css
Enhance existing breakdown patterns:
/* ===== Enhanced Breakdown Patterns ===== */
.breakdown-header {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
user-select: none;
padding: var(--space-sm);
border-radius: var(--radius-sm);
transition: background-color var(--transition-fast);
margin-bottom: var(--space-xs);
}
.breakdown-header:hover {
background: var(--color-bg-secondary);
}
.breakdown-header-left {
display: flex;
align-items: center;
gap: var(--space-sm);
}
.breakdown-toggle {
color: var(--color-text-secondary);
font-size: 0.625rem;
transition: transform var(--transition-fast);
}
.breakdown-toggle.expanded {
transform: rotate(90deg);
}
.breakdown-divider {
height: 1px;
background: var(--color-border);
margin: var(--space-md) 0;
}
Acceptance Criteria:
- Breakdown header with toggle
- Hover states defined
- Animation classes ready
Task 1.4: Add Color Utilities
Status: ⏸️ | Est: 20 min
File: reports-app/frontend/src/assets/css/utilities/colors.css (NEW)
/* Color Utilities - ROA2WEB */
/* Background colors for icons */
.bg-primary { background-color: var(--color-primary); }
.bg-success { background-color: var(--color-success); }
.bg-warning { background-color: var(--color-warning); }
.bg-error { background-color: var(--color-error); }
.bg-info { background-color: var(--color-info); }
.bg-primary-light { background-color: rgba(var(--color-primary-rgb), 0.1); }
.bg-success-light { background-color: rgba(var(--color-success-rgb), 0.1); }
.bg-warning-light { background-color: rgba(var(--color-warning-rgb), 0.1); }
/* Text colors */
.text-primary { color: var(--color-primary); }
.text-success { color: var(--color-success); }
.text-warning { color: var(--color-warning); }
.text-error { color: var(--color-error); }
.text-muted { color: var(--color-text-muted); }
Add to main.css:
@import './utilities/colors.css';
Acceptance Criteria:
- Color utilities created
- Imported in main.css
- RGB variants for transparency
Task 1.5: Test Global Patterns
Status: ⏸️ | Est: 15 min
# Build and verify
npm run build
# Check for errors
npm run dev
# No visual changes expected
Acceptance Criteria:
- Build successful
- No CSS errors
- Patterns available (not used yet)
2. Component Refactoring (15 tasks - 3 per component x 5)
MetricCard.vue (Tasks 2.1-2.3)
Task 2.1: Update MetricCard Template
Status: ⏸️ | Est: 1 hour
File: src/components/dashboard/cards/MetricCard.vue
Current template structure:
<div class="metric-card">
<div class="card-header">
<div class="icon-wrapper" :style="{ background: iconBg }">
<i :class="icon"></i>
</div>
<!-- ... -->
</div>
</div>
Updated template:
<div class="metric-card card-hover">
<div class="metric-header">
<div class="metric-icon bg-primary-light text-primary">
<i :class="icon"></i>
</div>
<div class="metric-label">{{ label }}</div>
</div>
<div class="metric-value" :class="{ 'trend-up': trend > 0, 'trend-down': trend < 0 }">
{{ formattedValue }}
</div>
<div v-if="showSparkline" class="sparkline-container">
<canvas ref="sparklineCanvas" class="sparkline-canvas"></canvas>
</div>
<div v-if="hasBreakdown" class="breakdown-section">
<div class="breakdown-header" @click="toggleBreakdown">
<div class="breakdown-header-left">
<i class="pi pi-chevron-right breakdown-toggle" :class="{ expanded: breakdownExpanded }"></i>
<span class="breakdown-label">Detalii</span>
</div>
<span class="breakdown-value">{{ breakdownTotal }}</span>
</div>
<div v-if="breakdownExpanded" class="breakdown-subitems slide-down">
<div v-for="item in breakdownItems" :key="item.id" class="breakdown-subitem">
<span class="breakdown-sublabel">{{ item.label }}</span>
<span class="breakdown-subvalue">{{ item.value }}</span>
</div>
</div>
</div>
</div>
Acceptance Criteria:
- Template uses global classes
- No inline styles for colors
- Breakdown uses global pattern
- Sparkline uses global container
Task 2.2: Remove Duplicate CSS from MetricCard
Status: ⏸️ | Est: 45 min
DELETE from <style scoped> (lines to remove ~250):
/* DELETE - now in cards.css */
.metric-card {
background: var(--color-bg, #ffffff);
border: 1px solid var(--color-border, #e5e7eb);
/* ... 20 more lines ... */
}
.metric-card:hover {
/* ... DELETE ... */
}
.card-header {
/* ... DELETE ... */
}
/* DELETE - now in dashboard.css */
.breakdown-header {
/* ... DELETE ... */
}
.breakdown-subitems {
/* ... DELETE ... */
}
/* DELETE - now in animations.css */
@keyframes slideDown {
/* ... DELETE ... */
}
KEEP component-specific:
/* Component-specific Chart.js configuration */
.sparkline-canvas {
/* Keep Chart.js specific overrides */
}
/* Component-specific data formatting */
.metric-specific-class {
/* Only if truly unique to this component */
}
Acceptance Criteria:
- 250+ lines deleted
- Only component-specific CSS remains
- Card renders identically
- Functionality preserved
Task 2.3: Test MetricCard
Status: ⏸️ | Est: 30 min
Visual tests:
- Card layout identical
- Hover effect works
- Sparkline renders
- Breakdown expands/collapses
- Trend indicators show correctly
- Icon background colors work
Functional tests:
- Props work (value, label, icon, trend)
- Computed properties correct
- Chart.js renders
- Breakdown data displays
- Click interactions work
Acceptance Criteria:
- No visual regressions
- All features work
- ~250 lines CSS eliminated
CashFlowMetricCard.vue (Tasks 2.4-2.6)
Task 2.4: Update CashFlowMetricCard Template
Status: ⏸️ | Est: 45 min
Apply same pattern as MetricCard:
- Use
.metric-cardbase class - Use
.metric-header,.metric-value,.metric-label - Use global breakdown pattern
- Remove inline styles
Acceptance Criteria:
- Template updated
- Global classes used
- No inline styles
Task 2.5: Remove Duplicate CSS
Status: ⏸️ | Est: 30 min
Target reduction: 179 → 60 lines (119 lines deleted)
Delete:
- Card base styles
- Hover effects
- Breakdown patterns
- Animations
Keep:
- Component-specific chart config
- Unique data formatting
Acceptance Criteria:
- 119 lines deleted
- Component CSS < 60 lines
Task 2.6: Test CashFlowMetricCard
Status: ⏸️ | Est: 20 min
- Card renders correctly
- Dual charts display
- Cash flow data accurate
- Breakdown works
- No visual regressions
ClientiBalanceCard.vue (Tasks 2.7-2.9)
Task 2.7: Update Template
Status: ⏸️ | Est: 45 min Acceptance: Template uses global patterns
Task 2.8: Remove Duplicate CSS
Status: ⏸️ | Est: 30 min Target: 260 → 90 lines (170 deleted)
Task 2.9: Test
Status: ⏸️ | Est: 20 min Acceptance: Client balance displays correctly
FurnizoriBalanceCard.vue (Tasks 2.10-2.12)
Task 2.10: Update Template
Status: ⏸️ | Est: 45 min
Task 2.11: Remove Duplicate CSS
Status: ⏸️ | Est: 30 min Target: ~260 → 90 lines (170 deleted)
Task 2.12: Test
Status: ⏸️ | Est: 20 min
TreasuryDualCard.vue (Tasks 2.13-2.15)
Task 2.13: Update Template
Status: ⏸️ | Est: 45 min
Task 2.14: Remove Duplicate CSS
Status: ⏸️ | Est: 30 min Target: ~200 → 60 lines (140 deleted)
Task 2.15: Test
Status: ⏸️ | Est: 20 min
3. Final Testing (2 tasks)
Task 3.1: Test All Cards Together
Status: ⏸️ | Est: 1 hour
Dashboard view:
- All 5 cards display in grid
- Hover effects consistent
- Sparklines render
- Breakdowns work on all cards
- Trend indicators correct
- Responsive layout works
Playwright:
npm run test:e2e -- tests/e2e/dashboard/
Acceptance Criteria:
- All cards work together
- No layout issues
- Visual regression tests pass
Task 3.2: Performance Measurement
Status: ⏸️ | Est: 30 min
Measure:
# CSS bundle size
ls -lh dist/assets/*.css
# Component CSS reduction
grep -c "}" src/components/dashboard/cards/*.vue
Document:
- Before: ~1,230 lines total card CSS
- After: ~380 lines total card CSS
- Reduction: ~850 lines (69%)
- Bundle size impact: ___ KB
Acceptance Criteria:
- Target reduction achieved
- Metrics documented
Completion Criteria
- 5 card components refactored
- ~850 lines CSS eliminated
- All cards use global patterns
- Visual regression tests pass
- Performance metrics documented
- Committed to git
Next Phase
Phase 5: DashboardView.vue Major Refactoring
- THE BIG ONE: 2,010 → 300 lines
- See: phase-5-dashboard.md
Created: 2025-11-18 Status: ⏸️ Not Started