Skip to content

Commit

Permalink
Show pinned collection relation (#4227)
Browse files Browse the repository at this point in the history
  • Loading branch information
gewfy authored Nov 26, 2023
2 parents c50c954 + 06f8d94 commit 8a7cc44
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 69 deletions.
10 changes: 10 additions & 0 deletions client/src/lib/components/Cards/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {ExerciseCard} from '../../../../../shared/src/types/generated/Exercise';
import ExerciseGraphic from '../ExerciseGraphic/ExerciseGraphic';
import Markdown from '../Typography/Markdown/Markdown';
import textStyles from '../Typography/styles';
import {Collection} from '../../../../../shared/src/types/generated/Collection';
import CollectionTag from '../Tag/CollectionTag';

export const HEIGHT = 175;

Expand Down Expand Up @@ -124,6 +126,7 @@ type CardProps = {
isPinned?: boolean;
reminderEnabled?: boolean;
interestedCount?: number;
collection?: Collection | null;
style?: ViewStyle;
};

Expand All @@ -138,6 +141,7 @@ export const Card: React.FC<CardProps> = ({
isPinned,
reminderEnabled,
interestedCount,
collection,
style,
}) => {
const {t} = useTranslation('Component.Card');
Expand All @@ -164,6 +168,12 @@ export const Card: React.FC<CardProps> = ({
</>
)
)}
{collection && (
<>
<CollectionTag>{collection.name}</CollectionTag>
<Spacer4 />
</>
)}
{tags &&
tags.map(tag => (
<Fragment key={tag}>
Expand Down
16 changes: 14 additions & 2 deletions client/src/lib/components/Cards/CardSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import Tag from '../Tag/Tag';
import {UserType} from '../../../../../shared/src/schemas/User';
import {ExerciseCard} from '../../../../../shared/src/types/generated/Exercise';
import ExerciseGraphic from '../ExerciseGraphic/ExerciseGraphic';
import {Collection} from '../../../../../shared/src/types/generated/Collection';
import CollectionTag from '../Tag/CollectionTag';

export const HEIGHT = 80;

Expand Down Expand Up @@ -69,6 +71,7 @@ type CardProps = {
onPress?: () => void;
hostProfile?: UserType | null;
completed?: boolean;
collection?: Collection | null;
style?: ViewStyle;
children?: React.ReactNode;
};
Expand All @@ -80,6 +83,7 @@ export const CardSmall: React.FC<CardProps> = ({
onPress,
hostProfile,
completed,
collection,
style,
children,
}) => {
Expand All @@ -99,9 +103,15 @@ export const CardSmall: React.FC<CardProps> = ({
style={style}
backgroundColor={completed ? COLORS.LIGHT_GREEN : COLORS.CREAM}>
<Main>
{tags && (
{(tags || collection) && (
<>
<Tags>
{collection && (
<>
<CollectionTag>{collection.name}</CollectionTag>
<Spacer4 />
</>
)}
{tags &&
tags.map(tag => (
<Fragment key={tag}>
Expand All @@ -118,7 +128,9 @@ export const CardSmall: React.FC<CardProps> = ({
<Spacer4 />
</>
)}
<Title numberOfLines={children || tags ? 1 : 3}>{title}</Title>
<Title numberOfLines={children || tags || collection ? 1 : 3}>
{title}
</Title>
{hostProfile && (
<>
<Spacer4 />
Expand Down
40 changes: 40 additions & 0 deletions client/src/lib/components/Cards/Cards.library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Button from '../Buttons/Button';
import CardSmall from './CardSmall';
import Interested from '../Interested/Interested';
import Node from '../Node/Node';
import {Collection} from '../../../../../shared/src/types/generated/Collection';

const VerticalAlign = styled.View({
flexDirection: 'row',
Expand Down Expand Up @@ -71,6 +72,13 @@ const DUMMY_LOTTIE_GRAPHIC: ExerciseCard = {
},
};

const DUMMY_COLLECTION: Collection = {
id: 'some-id',
name: 'Collection name',
published: true,
exercises: [],
};

const CardsList = () => (
<>
<Card
Expand Down Expand Up @@ -113,6 +121,21 @@ const CardsList = () => (
</VerticalAlign>
</Card>
<Spacer16 />
<Card
title="Accepting thoughts and feeeeeeeeeeeeeelings"
tags={DUMMY_TAGS}
hostProfile={DUMMY_HOST}
graphic={DUMMY_IMAGE_GRAPHIC}
isPinned
collection={DUMMY_COLLECTION}
onPress={() => {}}>
<VerticalAlign>
<Body14>Starts</Body14>
<Spacer4 />
<Badge text="Mon, 7 Sep 17.30" IconAfter={<CommunityIcon />} />
</VerticalAlign>
</Card>
<Spacer16 />
<Card
title="Accepting thoughts and feelings"
tags={DUMMY_TAGS}
Expand Down Expand Up @@ -233,6 +256,23 @@ const CardSmallsList = () => (
onPress={() => {}}
/>
<Spacer16 />
<CardSmall
title="Accepting thoughts and feeeeeeeeeeeeeelings"
tags={DUMMY_TAGS}
collection={DUMMY_COLLECTION}
hostProfile={DUMMY_HOST}
graphic={DUMMY_IMAGE_GRAPHIC}
onPress={() => {}}
/>
<Spacer16 />
<CardSmall
title="Accepting thoughts and feeeeeeeeeeeeeelings"
collection={DUMMY_COLLECTION}
hostProfile={DUMMY_HOST}
graphic={DUMMY_IMAGE_GRAPHIC}
onPress={() => {}}
/>
<Spacer16 />
<CardSmall
title="Pure Simple Love"
hostProfile={DUMMY_HOST}
Expand Down
10 changes: 10 additions & 0 deletions client/src/lib/components/Cards/SessionCard/ExerciseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@ import CardSmall from '../CardSmall';
import {ViewStyle} from 'react-native';
import Card from '../Card';
import useGetSessionCardTags from './hooks/useGetSessionCardTags';
import useGetCollectionByExerciseId from '../../../content/hooks/useGetCollectionByExerciseId';

type ExerciseCardContainerProps = {
exercise: Exercise;
small?: boolean;
resolvePinnedCollection?: boolean;
onPress?: () => void;
style?: ViewStyle;
};

const ExerciseCard: React.FC<ExerciseCardContainerProps> = ({
exercise,
small,
resolvePinnedCollection,
onPress = () => {},
style,
}) => {
const {navigate} =
useNavigation<NativeStackNavigationProp<ModalStackProps>>();
const tags = useGetSessionCardTags(exercise);
const getCollectionByExerciseId = useGetCollectionByExerciseId();

const onPressHandle = useCallback(() => {
onPress();
Expand All @@ -35,11 +39,16 @@ const ExerciseCard: React.FC<ExerciseCardContainerProps> = ({
return null;
}

const collection = resolvePinnedCollection
? getCollectionByExerciseId(exercise.id)
: undefined;

if (small) {
return (
<CardSmall
title={formatContentName(exercise)}
graphic={exercise?.card}
collection={collection}
onPress={onPressHandle}
style={style}
/>
Expand All @@ -52,6 +61,7 @@ const ExerciseCard: React.FC<ExerciseCardContainerProps> = ({
description={exercise.description}
tags={tags}
graphic={exercise.card}
collection={collection}
onPress={onPressHandle}
style={style}
/>
Expand Down
5 changes: 5 additions & 0 deletions client/src/lib/components/Cards/SessionCard/SessionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import useSessionReminder from '../../../sessions/hooks/useSessionReminder';
import {ViewStyle} from 'react-native';
import {BodyBold} from '../../Typography/Body/Body';
import CardSmall from '../CardSmall';
import useGetCollectionByExerciseId from '../../../content/hooks/useGetCollectionByExerciseId';

const JoinButton: React.FC<{
startTime: LiveSessionType['startTime'];
Expand Down Expand Up @@ -69,11 +70,14 @@ const SessionCard: React.FC<SessionCardProps> = ({
const logSessionMetricEvent = useLogSessionMetricEvents();
const {isPinned} = usePinSession(session);
const {reminderEnabled} = useSessionReminder(session);
const getCollectionByExerciseId = useGetCollectionByExerciseId();

const isHost = user?.uid === session.hostId;
const interestedCount = isHost ? session.interestedCount : undefined;
const tags = useGetSessionCardTags(exercise);

const collection = getCollectionByExerciseId(exerciseId);

const onPress = useCallback(() => {
logSessionMetricEvent('Join Sharing Session', session); // Log before navigating for correct Origin property in event
navigate('LiveSessionStack', {
Expand Down Expand Up @@ -124,6 +128,7 @@ const SessionCard: React.FC<SessionCardProps> = ({
isPinned={isPinned}
reminderEnabled={reminderEnabled}
interestedCount={interestedCount}
collection={collection}
style={style}>
{!disableJoinButton && (
<JoinButton onPress={onPress} startTime={startTime} />
Expand Down
11 changes: 11 additions & 0 deletions client/src/lib/components/Tag/CollectionTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import styled from 'styled-components/native';
import Tag from './Tag';
import {CollectionIcon} from '../Icons';

const CollectionTag = styled(Tag).attrs({
LeftIcon: CollectionIcon,
})({
backgroundColor: '#FDB',
});

export default CollectionTag;
119 changes: 119 additions & 0 deletions client/src/lib/content/hooks/useGetCollectionByExerciseId.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {renderHook} from '@testing-library/react-hooks';
import useGetCollectionById from './useGetCollectionById';
import usePinnedCollections from '../../user/hooks/usePinnedCollections';
import useGetCollectionByExerciseId from './useGetCollectionByExerciseId';

jest.mock('../../user/hooks/usePinnedCollections');
const mockUsePinnedCollections = usePinnedCollections as jest.Mock;
mockUsePinnedCollections.mockReturnValue({
pinnedCollections: [],
});

const mockGetExercisesByCollectionId = jest.fn();
jest.mock(
'../../content/hooks/useGetExercisesByCollectionId',
() => () => mockGetExercisesByCollectionId,
);

const mockUseGetCollectionById = jest.mocked(useGetCollectionById);
const mockGetCollectionById = jest.fn();
mockUseGetCollectionById.mockReturnValue(mockGetCollectionById);
jest.mock('./useGetCollectionById');

afterEach(() => {
jest.clearAllMocks();
});

describe('useGetCollectionByExerciseId', () => {
it('returns collection if exercise is in pinned collection', () => {
mockUsePinnedCollections.mockReturnValueOnce({
pinnedCollections: [{id: 'some-collection-id'}],
});
mockGetExercisesByCollectionId.mockReturnValueOnce([
{id: 'some-exercise-id'},
]);
mockGetCollectionById.mockReturnValueOnce({
id: 'some-collection-id',
name: 'Some Collection',
});

const {result} = renderHook(() => useGetCollectionByExerciseId());

const collection = result.current('some-exercise-id');

expect(mockGetExercisesByCollectionId).toHaveBeenCalledTimes(1);
expect(mockGetExercisesByCollectionId).toHaveBeenCalledWith(
'some-collection-id',
);
expect(mockGetCollectionById).toHaveBeenCalledTimes(1);
expect(mockGetCollectionById).toHaveBeenCalledWith('some-collection-id');
expect(collection).toEqual({
id: 'some-collection-id',
name: 'Some Collection',
});
});

it('returns the first pinned collection', () => {
mockUsePinnedCollections.mockReturnValueOnce({
pinnedCollections: [
{id: 'some-collection-id'},
{id: 'some-other-collection-id'},
],
});
mockGetExercisesByCollectionId.mockReturnValueOnce([
{id: 'some-exercise-id'},
]);
mockGetCollectionById.mockReturnValueOnce({
id: 'some-collection-id',
name: 'Some Collection',
});

const {result} = renderHook(() => useGetCollectionByExerciseId());

const collection = result.current('some-exercise-id');

expect(mockGetExercisesByCollectionId).toHaveBeenCalledTimes(1);
expect(mockGetExercisesByCollectionId).toHaveBeenCalledWith(
'some-collection-id',
);
expect(mockGetCollectionById).toHaveBeenCalledTimes(1);
expect(mockGetCollectionById).toHaveBeenCalledWith('some-collection-id');
expect(collection).toEqual({
id: 'some-collection-id',
name: 'Some Collection',
});
});

it('returns undefined if no collections are pinned', () => {
mockUsePinnedCollections.mockReturnValueOnce({
pinnedCollections: [],
});
const {result} = renderHook(() => useGetCollectionByExerciseId());

const collection = result.current('some-exercise-id');

expect(mockGetExercisesByCollectionId).toHaveBeenCalledTimes(0);
expect(mockGetCollectionById).toHaveBeenCalledTimes(0);
expect(collection).toBeUndefined();
});

it("returns undefined if pinned collections don't include exercise", () => {
mockUsePinnedCollections.mockReturnValueOnce({
pinnedCollections: [{id: 'some-collection-id'}],
});
mockGetExercisesByCollectionId.mockReturnValueOnce([
{id: 'some-other-exercise-id'},
]);

const {result} = renderHook(() => useGetCollectionByExerciseId());

const collection = result.current('some-exercise-id');

expect(mockGetExercisesByCollectionId).toHaveBeenCalledTimes(1);
expect(mockGetExercisesByCollectionId).toHaveBeenCalledWith(
'some-collection-id',
);
expect(mockGetCollectionById).toHaveBeenCalledTimes(0);
expect(collection).toBeUndefined();
});
});
Loading

0 comments on commit 8a7cc44

Please sign in to comment.