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
30 changes: 28 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,41 @@
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Run calculator is the best tool to help you pace your next workout or race."
content="Runner's Toolkit is the best tool to help you pace your next workout or race."
/>
<meta
name="google-site-verification"
content="7_6UZDsQ5XyvqnTBO_nj7ZgV3RzUr5ugsrynoCBCo3I"
/>
<meta property="og:title" content="Runner's Toolkit" />
<meta
property="og:description"
content="Runner's Toolkit is the best tool to help you pace your next workout or race."
/>
<meta
property="og:image"
content="https://runner-toolkit.netlify.app/runcalculator.jpg"
/>
<meta property="og:url" content="https://runner-toolkit.netlify.app" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Runner Toolkit" />

<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image" />
<meta property="twitter:domain" content="runner-toolkit.netlify.app" />
<meta property="twitter:url" content="https://runner-toolkit.netlify.app" />
<meta name="twitter:title" content="Runner's Toolkit" />
<meta
name="twitter:description"
content="Runner's Toolkit is the best tool to help you pace your next workout or race."
/>
<meta
name="twitter:image"
content="https://runner-toolkit.netlify.app/runcalculator.jpg"
/>
<link rel="manifest" href="manifest.json" />
<link rel="shortcut icon" href="favicon.ico" />
<title>Running Calculator</title>
<title>Runner's Toolkit</title>
</head>

<body>
Expand Down
Binary file added public/runcalculator.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 14 additions & 3 deletions src/components/pace-calculator/distance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ export const Distance = () => {
: 0;
setFieldValue("distance", distance);
};

const handleDistanceUnitChange = (value: string) => {
handleChange({ target: { name: "distanceUnit", value } });
setFieldValue(
"distance",
value === Unit.KILOMETERS
? // Coming from miles, so convert to kilometers
parseFloat(distance) * MILES_TO_KILOMETERS
: // Coming from kilometers, so convert to miles
parseFloat(distance) / MILES_TO_KILOMETERS,
);
};

return (
<div>
<h2 className="text-lg font-semibold">Distance</h2>
Expand All @@ -73,9 +86,7 @@ export const Distance = () => {
/>
<Select
value={distanceUnit}
onValueChange={(value) =>
handleChange({ target: { name: "distanceUnit", value } })
}
onValueChange={handleDistanceUnitChange}
name="distanceUnit"
>
<SelectTrigger ariaLabel="Distance Unit Menu">
Expand Down
71 changes: 59 additions & 12 deletions src/components/pace-calculator/pace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,81 @@ import { getTotalTimeInSeconds, calculatePace } from "@/utils/calc";
import { Placeholders } from "./content";

export const Pace = () => {
const { values, handleChange, setValues } = useFormikContext<FormState>();
const { values, handleChange, setFieldValue } = useFormikContext<FormState>();

const updatePaceFields = (
hours: number,
minutes: number,
seconds: number,
) => {
setFieldValue("paceHours", hours.toString());
setFieldValue("paceMinutes", minutes.toString());
setFieldValue("paceSeconds", seconds.toString());
};

const calculatePaceValues = (
totalSeconds: number,
distance: number,
paceUnit: Unit,
distanceUnit: Unit,
) => {
if (distance === 0) return { hours: 0, minutes: 0, seconds: 0 };
return calculatePace(totalSeconds, distance, paceUnit, distanceUnit);
};

const setPace = () => {
const distance = Number.parseFloat(values.distance) || 0;
if (distance === 0) return;

const totalSeconds = getTotalTimeInSeconds(
values.hours,
values.minutes,
values.seconds,
);

const { seconds, minutes, hours } = calculatePace(
const paceValues = calculatePaceValues(
totalSeconds,
distance,
values.paceUnit,
values.distanceUnit,
);

setValues({
...values,
paceHours: hours.toString(),
paceMinutes: minutes.toString(),
paceSeconds: seconds.toString(),
});
if (paceValues) {
updatePaceFields(
paceValues.hours,
paceValues.minutes,
paceValues.seconds,
);
}
};

const handlePaceUnitChange = (value: string) => {
setFieldValue("paceUnit", value);

const distance = Number.parseFloat(values.distance);
if (distance === 0) return;

const totalSeconds = getTotalTimeInSeconds(
values.hours,
values.minutes,
values.seconds,
);

const paceValues = calculatePaceValues(
totalSeconds,
distance,
value as Unit,
values.distanceUnit,
);

if (paceValues) {
updatePaceFields(
paceValues.hours,
paceValues.minutes,
paceValues.seconds,
);
}
};

return (
<div>
<h2 className="text-lg font-semibold">Pace</h2>
Expand Down Expand Up @@ -73,9 +122,7 @@ export const Pace = () => {
/>
<Select
value={values.paceUnit}
onValueChange={(value) =>
handleChange({ target: { name: "paceUnit", value } })
}
onValueChange={handlePaceUnitChange}
name="paceUnit"
>
<SelectTrigger
Expand Down
2 changes: 2 additions & 0 deletions src/components/pace-calculator/time.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const Time = () => {
const { seconds, minutes, hours } = calculateTime(
totalPaceSeconds,
distance,
values.paceUnit,
values.distanceUnit,
);

setValues({
Expand Down
33 changes: 19 additions & 14 deletions src/utils/calc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ export const calculatePace = (
return getTime(seconds / adjustedDistance);
};

export const calculateTime = (seconds: number, distance: number): Time => {
return getTime(seconds * distance);
export const calculateTime = (
seconds: number,
distance: number,
paceUnit: Unit,
distanceUnit: Unit,
): Time => {
const conversionFactor = getConversionFactor(paceUnit, distanceUnit);
return getTime(seconds * distance * conversionFactor);
};

export const calculateDistance = (
Expand All @@ -43,28 +49,27 @@ export const calculateDistance = (
paceUnit: Unit,
distanceUnit: Unit,
): number => {
const conversionFactor =
paceUnit === distanceUnit
? 1
: paceUnit === Unit.MILES
? KILOMETERS_TO_MILES
: MILES_TO_KILOMETERS;

const conversionFactor = getConversionFactor(paceUnit, distanceUnit);
return seconds / (paceSeconds * conversionFactor);
};

const getTime = (time: number): Time => {
const hours = Math.floor(time / SECONDS_PER_HOUR);
const remainingSeconds = time % SECONDS_PER_HOUR;
const getConversionFactor = (fromUnit: Unit, toUnit: Unit): number => {
if (fromUnit === toUnit) return 1;
return fromUnit === Unit.MILES ? KILOMETERS_TO_MILES : MILES_TO_KILOMETERS;
};

const getTime = (totalSeconds: number): Time => {
const hours = Math.floor(totalSeconds / SECONDS_PER_HOUR);
const remainingSeconds = totalSeconds % SECONDS_PER_HOUR;
const minutes = Math.floor(remainingSeconds / SECONDS_PER_MINUTE);
const seconds = Number.parseFloat(
(remainingSeconds % SECONDS_PER_MINUTE).toFixed(2),
);

return {
seconds,
minutes,
hours,
minutes,
seconds,
};
};

Expand Down