Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ next-env.d.ts
# Python
__pycache__/
*.pyc
.vercel
21 changes: 21 additions & 0 deletions web/app/(app)/connections/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { syncGarminMetrics } from "@/lib/server/garmin/sync"
import { importAllStravaHistory, importStravaHistory, syncRecentStrava } from "@/lib/server/strava/sync"
import { createClient } from "@/lib/supabase/server"

const POLAR_FULL_HISTORY_DAYS = 3650

export async function syncStrava(): Promise<{ synced?: number; error?: string }> {
const supabase = await createClient()
const {
Expand Down Expand Up @@ -158,3 +160,22 @@ export async function syncPolarHistory(days = 30): Promise<{ synced?: number; er
return { error: e instanceof Error ? e.message : "Synchronisation Polar échouée" }
}
}

export async function syncAllPolarHistory(): Promise<{ synced?: number; error?: string }> {
const supabase = await createClient()
const {
data: { user },
} = await supabase.auth.getUser()

if (!user) return { error: "Non authentifié" }

try {
const { syncPolarMetrics } = await import("@/lib/server/polar/sync")
const synced = await syncPolarMetrics(user.id, POLAR_FULL_HISTORY_DAYS)
revalidatePath("/connections")
revalidatePath("/dashboard")
return { synced }
} catch (e) {
return { error: e instanceof Error ? e.message : "Import complet Polar échoué" }
}
}
26 changes: 24 additions & 2 deletions web/app/(app)/connections/connections-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
disconnectTerra,
disconnectPolar,
syncGarminHistory,
syncAllPolarHistory,
syncPolarHistory,
syncAllStravaHistory,
syncStrava,
Expand Down Expand Up @@ -389,6 +390,7 @@ export function StravaCard({
export function PolarCard({ connected, providerUserId, lastSyncAt }: TerraCardProps) {
const router = useRouter()
const [syncing, setSyncing] = useState(false)
const [importingAll, setImportingAll] = useState(false)
const [disconnecting, setDisconnecting] = useState(false)

const lastSyncLabel = lastSyncAt
Expand All @@ -410,6 +412,18 @@ export function PolarCard({ connected, providerUserId, lastSyncAt }: TerraCardPr
}
}

async function handleImportAllHistory() {
setImportingAll(true)
const result = await syncAllPolarHistory()
setImportingAll(false)
if (result.error) {
toast.error(result.error)
} else {
toast.success(`Import complet Polar terminé — ${result.synced ?? 0} journée(s)`)
router.refresh()
}
}

return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
Expand Down Expand Up @@ -461,15 +475,23 @@ export function PolarCard({ connected, providerUserId, lastSyncAt }: TerraCardPr
router.refresh()
}
}}
disabled={syncing || disconnecting}
disabled={syncing || importingAll || disconnecting}
>
{syncing ? "Synchronisation…" : "Importer 30 jours"}
</Button>
<Button
size="sm"
variant="outline"
onClick={handleImportAllHistory}
disabled={syncing || importingAll || disconnecting}
>
{importingAll ? "Import complet…" : "Importer tout l'historique"}
</Button>
<Button
size="sm"
variant="destructive"
onClick={handleDisconnect}
disabled={syncing || disconnecting}
disabled={syncing || importingAll || disconnecting}
>
{disconnecting ? "Déconnexion…" : "Déconnecter"}
</Button>
Expand Down
4 changes: 2 additions & 2 deletions web/app/(app)/health/health-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export function HealthChart({ data }: HealthChartProps) {
</div>
) : (
<ResponsiveContainer width="100%" height={180}>
<LineChart data={chartData} margin={{ top: 5, right: 5, bottom: 5, left: -25 }}>
<LineChart data={chartData} margin={{ top: 5, right: 5, bottom: 5, left: 0 }}>
<CartesianGrid strokeDasharray="3 3" vertical={false} stroke="var(--border)" opacity={0.3} />
<XAxis
dataKey="date"
Expand All @@ -125,7 +125,7 @@ export function HealthChart({ data }: HealthChartProps) {
tick={{ fontSize: 9, fill: "var(--muted-foreground)" }}
tickLine={false}
axisLine={false}
width={35}
width={40}
unit={activeTab === "hr" ? " bpm" : " ms"}
/>
<Tooltip content={<CustomTooltip type={activeTab} />} />
Expand Down
8 changes: 4 additions & 4 deletions web/app/(app)/health/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export default async function HealthPage() {
{/* Main recovery metrics grid */}
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
{/* Sommeil */}
<Card className="relative overflow-hidden border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<Card className="relative border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<CardContent className="pt-4 flex flex-col justify-between h-full min-h-[110px]">
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span className="flex items-center gap-1.5 font-medium">
Expand All @@ -231,7 +231,7 @@ export default async function HealthPage() {
</Card>

{/* HRV */}
<Card className="relative overflow-hidden border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<Card className="relative border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<CardContent className="pt-4 flex flex-col justify-between h-full min-h-[110px]">
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span className="flex items-center gap-1.5 font-medium">
Expand Down Expand Up @@ -259,7 +259,7 @@ export default async function HealthPage() {
</Card>

{/* FC de repos */}
<Card className="relative overflow-hidden border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<Card className="relative border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<CardContent className="pt-4 flex flex-col justify-between h-full min-h-[110px]">
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span className="flex items-center gap-1.5 font-medium">
Expand All @@ -281,7 +281,7 @@ export default async function HealthPage() {
</Card>

{/* Body Battery & Stress */}
<Card className="relative overflow-hidden border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<Card className="relative border border-border bg-card/50 backdrop-blur-sm transition-all hover:bg-card">
<CardContent className="pt-4 flex flex-col justify-between h-full min-h-[110px]">
<div className="flex items-center justify-between text-sm text-muted-foreground">
<span className="flex items-center gap-1.5 font-medium">
Expand Down
Loading