diligence/frontend/src/pages/WeekView.jsx
Claude c075eb9257 Stream A: DW brand theme — Instrument Sans + IBM Plex Mono, light/dark mode, all hardcoded colors replaced
- Replace Solar Momentum palette with DiligenceWorks brand identity
- Typography: Outfit → Instrument Sans, Plus Jakarta Sans → IBM Plex Mono (data/stats)
- CSS variables: --orange* → --accent*, new DW blue #2952CC / #6B9BFF
- Dark mode: prefers-color-scheme media query + manual data-theme override
- Border radii: 14/10/20px → 8/6/12px (professional, less playful)
- Font weights: 800/900 → 600/700 (DW uses lighter weights)
- Fixed 30+ hardcoded hex values across 16 files (UI-06)
- Gate banners, progress bars, category chips all use CSS variables
2026-06-21 23:12:25 +00:00

95 lines
4.2 KiB
JavaScript

import { useState, useEffect } from 'react'
import { api } from '../api'
export default function WeekView() {
const [week, setWeek] = useState(null)
const [loading, setLoading] = useState(true)
useEffect(() => { load() }, [])
async function load() {
try { setWeek(await api.week()) }
catch (err) { console.error(err) }
finally { setLoading(false) }
}
if (loading) return <div className="page"><div className="loading">Loading...</div></div>
if (!week) return <div className="page"><div className="error-msg">Failed to load</div></div>
const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
const pct = week.weekly_target > 0 ? Math.min(100, Math.round((week.total_points_earned / week.weekly_target) * 100)) : 0
const today = new Date().toISOString().split('T')[0]
return (
<div className="page">
<h1 className="page-title">This Week</h1>
{/* Summary hero */}
<div className="card" style={{ textAlign: 'center', background: 'var(--accent-bg)' }}>
<div className="section-label">Weekly Total</div>
<div style={{ fontFamily: 'var(--font-display)', fontSize: '2.6rem', fontWeight: 900, letterSpacing: '-0.03em' }}>
{week.total_points_earned}
</div>
<div style={{ color: 'var(--text-3)', fontWeight: 600, fontSize: '0.88rem', marginBottom: '12px' }}>
/ {week.weekly_target} pts
</div>
<div className="progress-bar" style={{ height: '12px' }}>
<div className="progress-bar-fill" style={{
width: `${pct}%`,
background: week.hit_weekly_target ? 'linear-gradient(90deg, #00C853, #69F0AE)' : 'linear-gradient(90deg, #7C4DFF, #B388FF)',
}} />
</div>
{week.hit_weekly_target && (
<div style={{ marginTop: '10px', color: 'var(--green-dark)', fontWeight: 700, fontSize: '0.9rem' }}>
🏆 Target hit! +{week.weekly_bonus_earned} bonus
</div>
)}
<div style={{ display: 'flex', justifyContent: 'center', gap: '28px', marginTop: '14px' }}>
<div>
<div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '1.3rem' }}>{week.active_days}</div>
<div style={{ fontSize: '0.72rem', color: 'var(--text-3)', fontWeight: 600 }}>active days</div>
</div>
<div>
<div style={{ fontFamily: 'var(--font-display)', fontWeight: 900, fontSize: '1.3rem' }}>{week.gate_passed_days}</div>
<div style={{ fontSize: '0.72rem', color: 'var(--text-3)', fontWeight: 600 }}>rewards earned</div>
</div>
</div>
</div>
{/* Daily breakdown */}
<div className="card">
<div className="section-label">Daily Breakdown</div>
{week.daily_breakdown.map((day, i) => {
const dayPct = day.daily_minimum > 0 ? Math.min(100, Math.round((day.points_earned / day.daily_minimum) * 100)) : 0
const isToday = day.date === today
return (
<div key={day.date} style={{
display: 'flex', alignItems: 'center', gap: '10px', padding: '10px 0',
borderBottom: i < 6 ? '1px solid var(--divider)' : 'none',
}}>
<div style={{
width: '38px', fontWeight: isToday ? 800 : 600, fontSize: '0.85rem',
color: isToday ? 'var(--accent)' : 'var(--text)',
}}>
{days[i]}
</div>
<div style={{ flex: 1 }}>
<div className="progress-bar" style={{ height: '8px' }}>
<div className="progress-bar-fill" style={{
width: `${dayPct}%`,
background: day.gate_passed ? 'var(--green)' : day.points_earned > 0 ? 'var(--amber)' : 'transparent',
}} />
</div>
</div>
<div style={{ width: '46px', textAlign: 'right', fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: '0.9rem' }}>
{day.points_earned}
</div>
<div style={{ width: '22px', textAlign: 'center', fontSize: '0.9rem' }}>
{day.gate_passed ? '✅' : day.points_earned > 0 ? '🟡' : '⬜'}
</div>
</div>
)
})}
</div>
</div>
)
}