243 lines
6.4 KiB
TypeScript
243 lines
6.4 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
IonContent,
|
|
IonPage,
|
|
IonIcon,
|
|
IonText,
|
|
useIonViewWillEnter,
|
|
} from '@ionic/react';
|
|
import { useHistory } from 'react-router-dom';
|
|
import {
|
|
heartCircleOutline,
|
|
medkitOutline,
|
|
restaurantOutline,
|
|
moonOutline,
|
|
chevronForwardOutline,
|
|
} from 'ionicons/icons';
|
|
import WellbeingScoreCard from '../components/health/WellbeingScoreCard';
|
|
import MetricMiniCard from '../components/health/MetricMiniCard';
|
|
import RecentActivityList from '../components/health/RecentActivityList';
|
|
import {
|
|
getWellbeingSummary,
|
|
getRecentActivity,
|
|
} from '../services/localHealthStore';
|
|
import { WellbeingSummary, ActivityEntry } from '../types/health';
|
|
|
|
const Home: React.FC = () => {
|
|
const history = useHistory();
|
|
const [summary, setSummary] = useState<WellbeingSummary>(
|
|
getWellbeingSummary()
|
|
);
|
|
const [recentEntries, setRecentEntries] =
|
|
useState<ActivityEntry[]>(getRecentActivity());
|
|
|
|
const refreshData = () => {
|
|
setSummary(getWellbeingSummary());
|
|
setRecentEntries(getRecentActivity());
|
|
};
|
|
|
|
useIonViewWillEnter(() => {
|
|
refreshData();
|
|
});
|
|
|
|
return (
|
|
<IonPage style={{ background: '#eef7fb' }}>
|
|
<IonContent
|
|
fullscreen
|
|
style={{
|
|
'--background':
|
|
'linear-gradient(160deg, rgba(56,189,248,0.16) 0%, #eef7fb 58%, #f8fbfd 100%)',
|
|
}}
|
|
>
|
|
{/* Top Content Row */}
|
|
<div
|
|
style={{
|
|
padding: 'calc(16px + var(--ion-safe-area-top)) 20px 12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '12px',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
width: '40px',
|
|
height: '40px',
|
|
background: 'rgba(3,105,161,0.12)',
|
|
borderRadius: '12px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
<IonIcon
|
|
icon={heartCircleOutline}
|
|
style={{ fontSize: '22px', color: '#0369a1' }}
|
|
/>
|
|
</div>
|
|
<div style={{ flex: 1 }}>
|
|
<div
|
|
style={{
|
|
fontSize: '12px',
|
|
fontWeight: '700',
|
|
color: 'rgba(30,58,95,0.60)',
|
|
lineHeight: '16px',
|
|
}}
|
|
>
|
|
Wellbeing
|
|
</div>
|
|
<div
|
|
style={{
|
|
fontSize: '20px',
|
|
fontWeight: '700',
|
|
color: '#1e3a5f',
|
|
lineHeight: '24px',
|
|
}}
|
|
>
|
|
Good morning
|
|
</div>
|
|
</div>
|
|
<div
|
|
style={{
|
|
background: '#ffffff',
|
|
borderRadius: '999px',
|
|
padding: '8px 12px',
|
|
fontSize: '12px',
|
|
fontWeight: '700',
|
|
color: '#0369a1',
|
|
}}
|
|
>
|
|
Local
|
|
</div>
|
|
</div>
|
|
|
|
{/* Score Widget */}
|
|
<WellbeingScoreCard
|
|
score={summary.score}
|
|
message={summary.scoreMessage}
|
|
progress={summary.scoreProgress}
|
|
/>
|
|
|
|
{/* Metric Row */}
|
|
<div
|
|
style={{
|
|
margin: '0 20px 12px',
|
|
display: 'grid',
|
|
gridTemplateColumns: '1fr 1fr',
|
|
gap: '12px',
|
|
}}
|
|
>
|
|
<MetricMiniCard
|
|
label="Sleep"
|
|
value={summary.sleepHours.toString()}
|
|
helper="hrs"
|
|
progress={summary.sleepHours / 8}
|
|
icon={moonOutline}
|
|
/>
|
|
<MetricMiniCard
|
|
label="Water"
|
|
value={summary.hydrationCups.toString()}
|
|
helper="cups"
|
|
progress={summary.hydrationCups / 8}
|
|
icon={restaurantOutline}
|
|
/>
|
|
</div>
|
|
|
|
{/* Action Strip */}
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
gap: '8px',
|
|
overflowX: 'auto',
|
|
padding: '0 20px 20px',
|
|
msOverflowStyle: 'none',
|
|
scrollbarWidth: 'none',
|
|
}}
|
|
>
|
|
{[
|
|
{ label: 'Checkup', icon: medkitOutline, path: '/checkups' },
|
|
{ label: 'Diet', icon: restaurantOutline, path: '/diet' },
|
|
{ label: 'Sleep', icon: moonOutline, path: '/sleep' },
|
|
].map((action) => (
|
|
<div
|
|
key={action.label}
|
|
onClick={() => history.push(action.path)}
|
|
style={{
|
|
flexShrink: 0,
|
|
background: '#ffffff',
|
|
borderRadius: '999px',
|
|
padding: '10px 18px',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '8px',
|
|
minHeight: '44px',
|
|
cursor: 'pointer',
|
|
}}
|
|
>
|
|
<IonIcon
|
|
icon={action.icon}
|
|
style={{ fontSize: '18px', color: '#0369a1' }}
|
|
/>
|
|
<span
|
|
style={{
|
|
fontSize: '13px',
|
|
fontWeight: '700',
|
|
color: '#1e3a5f',
|
|
}}
|
|
>
|
|
{action.label}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Section Header */}
|
|
<div
|
|
style={{
|
|
margin: '4px 20px 12px',
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'baseline',
|
|
}}
|
|
>
|
|
<span
|
|
style={{ fontSize: '17px', fontWeight: '700', color: '#1e3a5f' }}
|
|
>
|
|
Recent Activity
|
|
</span>
|
|
<div
|
|
onClick={() => history.push('/insights')}
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: '2px',
|
|
cursor: 'pointer',
|
|
}}
|
|
>
|
|
<span
|
|
style={{ fontSize: '13px', fontWeight: '700', color: '#0369a1' }}
|
|
>
|
|
See insights
|
|
</span>
|
|
<IonIcon
|
|
icon={chevronForwardOutline}
|
|
style={{ fontSize: '14px', color: '#0369a1' }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Recent Activity List */}
|
|
<RecentActivityList
|
|
entries={recentEntries}
|
|
onCreate={() => history.push('/checkups')}
|
|
onSeeInsights={() => history.push('/insights')}
|
|
/>
|
|
|
|
<div style={{ height: '20px' }} />
|
|
</IonContent>
|
|
</IonPage>
|
|
);
|
|
};
|
|
|
|
export default Home;
|