build: eb8f08f0-e41a-4086-9130-c5af05b58ec7
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user