-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce dialog for goals, improve ux
- Loading branch information
Showing
10 changed files
with
311 additions
and
207 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { atom, useAtom } from "jotai"; | ||
import { useEffect } from "react"; | ||
import { Goal, PartialGoal } from "../types/Goals"; | ||
import { | ||
golfSwingDataKeysInDegrees, | ||
golfSwingDataKeysInMeters, | ||
} from "../types/GolfSwingData"; | ||
import { useAveragedSwings } from "../utils/calculateAverages"; | ||
import { useIsEnglish } from "./useIsEnglish"; | ||
|
||
export const goalAtom = atom<PartialGoal[]>([]); | ||
export const useGoals: () => Goal[] = () => { | ||
const isEnglish = useIsEnglish(); | ||
const [goals, setGoals] = useAtom(goalAtom); | ||
useEffect( | ||
() => | ||
setGoals( | ||
isEnglish | ||
? [ | ||
{ | ||
id: "1", | ||
title: "Driving distance", | ||
target: 200, | ||
metric: "Carry Distance", | ||
}, | ||
] | ||
: [ | ||
{ | ||
id: "1", | ||
title: "Driving distance", | ||
target: 200, | ||
metric: "Gesamtstrecke", | ||
}, | ||
], | ||
), | ||
[isEnglish, setGoals], | ||
); | ||
const averages = useAveragedSwings(); | ||
|
||
const calculateGoalProgress = (partialGoal: PartialGoal) => { | ||
const current = | ||
averages.find((average) => average.name === "Driver")?.[ | ||
"Carry Distance" | ||
] || | ||
averages.find((average) => average.name === "Driver")?.["Gesamtstrecke"]; | ||
|
||
const progress = current ? (current / partialGoal.target) * 100 : 0; | ||
const progressText = `${(current ? (current / partialGoal.target) * 100 : 0).toFixed(2)}%`; | ||
const unit = golfSwingDataKeysInMeters.includes(partialGoal.metric) | ||
? "m" | ||
: golfSwingDataKeysInDegrees.includes(partialGoal.metric) | ||
? "°" | ||
: ""; | ||
return { progress, progressText, current, unit }; | ||
}; | ||
|
||
return goals.map((goal) => ({ | ||
...goal, | ||
...calculateGoalProgress(goal), | ||
})); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { useSelectedSessions } from "./useSelectedSessions"; | ||
|
||
export const useIsEnglish = () => { | ||
const sessions = useSelectedSessions(); | ||
return Object.values(sessions).some( | ||
(session) => session.results.length && !!session.results[0]?.["Ball Speed"], | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { GolfSwingDataDE, GolfSwingDataEN } from "./GolfSwingData"; | ||
|
||
export type Goal = { | ||
id: string; | ||
title: string; | ||
current: string | number | null | undefined; | ||
target: number; | ||
progressText: string; | ||
progress: number; | ||
unit: string; | ||
}; | ||
|
||
export type PartialGoal = { | ||
id: string; | ||
title: string; | ||
target: number; | ||
club?: string; | ||
metric: keyof GolfSwingDataDE | keyof GolfSwingDataEN; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import type { Goal as GoalType } from "../types/Goals"; | ||
import { ProgressBar } from "./ProgressBar"; | ||
|
||
export const Goal = ({ goal }: { goal: GoalType }) => { | ||
return ( | ||
<div className="mt-4 max-w-2xl rounded-md bg-white p-4"> | ||
<h3 className="text-lg font-semibold">{goal.title}</h3> | ||
<hr /> | ||
<div className="flex flex-col justify-between text-lg lg:flex-row"> | ||
<p> | ||
Current: <b>{goal.current + goal.unit}</b> | ||
</p> | ||
<p> | ||
Target: <b>{goal.target + goal.unit}</b> | ||
</p> | ||
<p> | ||
Progress: <b>{goal.progressText}</b> | ||
</p> | ||
</div> | ||
<ProgressBar progress={goal.progress} /> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { useAtom } from "jotai"; | ||
import { useForm } from "react-hook-form"; | ||
import { useClubsPerSession } from "../hooks/useClubsPerSesssion"; | ||
import { goalAtom } from "../hooks/useGoals"; | ||
import { useIsEnglish } from "../hooks/useIsEnglish"; | ||
import { | ||
GolfSwingDataDE, | ||
GolfSwingDataEN, | ||
englishDegreeMetrics, | ||
englishMetersMetrics, | ||
germanDegreeMetrics, | ||
germanMetersMetrics, | ||
golfSwingDataKeysInMeters, | ||
} from "../types/GolfSwingData"; | ||
|
||
export const GoalForm = ({ closeAction }: { closeAction: () => void }) => { | ||
const formMethods = useForm<{ | ||
title: string; | ||
target: number; | ||
club?: string; | ||
metric: keyof GolfSwingDataDE | keyof GolfSwingDataEN; | ||
}>(); | ||
|
||
const isEnglish = useIsEnglish(); | ||
const metricOptions = isEnglish | ||
? [...englishDegreeMetrics, ...englishMetersMetrics] | ||
: [...germanDegreeMetrics, ...germanMetersMetrics]; | ||
const [, setGoals] = useAtom(goalAtom); | ||
const clubs = useClubsPerSession(); | ||
return ( | ||
<div className="mt-4 rounded-md bg-white p-4"> | ||
<form | ||
onSubmit={formMethods.handleSubmit((data) => { | ||
setGoals((goals) => [ | ||
...goals, | ||
{ | ||
id: (goals.length + 1).toString(), | ||
title: data.title, | ||
target: data.target, | ||
metric: data.metric, | ||
}, | ||
]); | ||
closeAction(); | ||
})} | ||
> | ||
<div className="flex flex-wrap gap-4"> | ||
<input | ||
type="text" | ||
placeholder="Title" | ||
{...formMethods.register("title", { required: true })} | ||
className="input w-full" | ||
/> | ||
|
||
<select | ||
{...formMethods.register("metric", { required: true })} | ||
className="input w-full" | ||
> | ||
{metricOptions.map((option) => ( | ||
<option key={option} value={option}> | ||
{option} | ||
</option> | ||
))} | ||
</select> | ||
|
||
<select | ||
{...formMethods.register("club")} | ||
className="input w-full" | ||
defaultValue="" | ||
> | ||
{Object.keys(clubs).map((club) => ( | ||
<option key={club} value={club}> | ||
{club} | ||
</option> | ||
))} | ||
<option value="">All clubs</option> | ||
</select> | ||
|
||
<input | ||
type="number" | ||
placeholder={`Target (${ | ||
golfSwingDataKeysInMeters.includes(formMethods.watch("metric")) | ||
? "m" | ||
: "°" | ||
})`} | ||
{...formMethods.register("target", { required: true })} | ||
className="input w-full" | ||
/> | ||
</div> | ||
<button type="submit" className="btn mt-4 w-full"> | ||
Add goal | ||
</button> | ||
</form> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { useGoals } from "../hooks/useGoals"; | ||
import { Goal } from "./Goal"; | ||
|
||
export const GoalList = () => { | ||
const goals = useGoals(); | ||
|
||
return ( | ||
<div className="mt-4"> | ||
<h2 className="text-xl font-semibold">Your goals</h2> | ||
{goals.map((goal) => ( | ||
<Goal key={goal.id} goal={goal} /> | ||
))} | ||
</div> | ||
); | ||
}; |
Oops, something went wrong.