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
31 changes: 31 additions & 0 deletions src/components/Routines/widgets/RoutineDetailsCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { RoutineDetailsCard } from "@/components/Routines/widgets/RoutineDetails
import React from 'react';
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { testRoutine1 } from "@/tests/workoutRoutinesTestData";
import { Routine } from "@/components/Routines/models/Routine";
import type { Mock } from 'vitest';

vi.mock("@/components/Exercises/api/language");
Expand Down Expand Up @@ -59,4 +60,34 @@ describe("Test the RoutineDetail component", () => {
expect(screen.getByText('Pull day')).toBeInTheDocument();
expect(screen.getByText('routines.restDay')).toBeInTheDocument();
});

test.each([
['with sequence data', testRoutine1],
['without sequence data', new Routine({ ...testRoutine1, dayData: [] })],
])('links the exercises to their detail page (%s)', async (_, routine) => {

// Arrange
(useRoutineDetailQuery as Mock).mockImplementation(() => ({
isSuccess: true,
isLoading: false,
data: routine
}));

// Act
render(
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={['/routine/101']}>
<Routes>
<Route path="routine/:routineId" element={<RoutineDetailsCard />} />
</Routes>
</MemoryRouter>
</QueryClientProvider>
);

// Assert
expect(screen.getByRole('link', { name: 'Squats' })).toHaveAttribute(
'href',
expect.stringMatching(/\/exercise\/345\/view\/squats$/)
);
});
});
27 changes: 24 additions & 3 deletions src/components/Routines/widgets/RoutineDetailsCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ExerciseImageAvatar, getLanguageByShortName, Language, useLanguageQuery } from "@/components/Exercises";
import { Exercise, ExerciseImageAvatar, getLanguageByShortName, Language, useLanguageQuery } from "@/components/Exercises";
import { Day, getDayName } from "@/components/Routines/models/Day";
import { RoutineDayData } from "@/components/Routines/models/RoutineDayData";
import { SetConfigData } from "@/components/Routines/models/SetConfigData";
Expand All @@ -19,6 +19,7 @@ import {
Container,
Divider,
IconButton,
Link,
Stack,
Typography,
useTheme
Expand Down Expand Up @@ -61,6 +62,26 @@ export const RoutineDetailsCard = () => {
};


/*
* Name of an exercise, linking to its detail page
*/
function ExerciseNameLink(props: { exercise: Exercise, language?: Language }) {
const { i18n } = useTranslation();
const translation = props.exercise.getTranslation(props.language);

return <Link
href={makeLink(WgerLink.EXERCISE_DETAIL, i18n.language, {
id: props.exercise.id!,
slug: translation.nameSlug
})}
color="inherit"
underline="hover"
>
{translation.name}
</Link>;
}


export function SetConfigDataDetails(props: {
setConfigData: SetConfigData,
rowHeight?: undefined | string,
Expand Down Expand Up @@ -91,7 +112,7 @@ export function SetConfigDataDetails(props: {
<Stack spacing={0}>
<Typography variant={"h6"}>
{props.showExercise && (props.setConfigData.exercise
? props.setConfigData.exercise.getTranslation(language).name
? <ExerciseNameLink exercise={props.setConfigData.exercise} language={language} />
: t('routines.exerciseNotAvailable'))}
</Typography>
<div>
Expand Down Expand Up @@ -200,7 +221,7 @@ function SlotEntryList(props: { slot: Slot }) {
{props.slot.entries.map((entry) =>
<Typography variant={"h6"} key={entry.id}>
{entry.exercise
? entry.exercise.getTranslation(language).name
? <ExerciseNameLink exercise={entry.exercise} language={language} />
: t('routines.exerciseNotAvailable')}
</Typography>
)}
Expand Down
Loading