Skip to content

Commit

Permalink
feat(user): add favorites screen
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut committed Jul 21, 2021
1 parent d7b4970 commit 7f94e98
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 40 deletions.
18 changes: 18 additions & 0 deletions src/components/Favorites/Favorites.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@use '../../styles/variables';
@use '../../styles/theme';
@use '../../styles/mixins/responsive';

.header {
display: flex;
margin-bottom: variables.$base-spacing * 1.5;
}

h3 {
margin-right: variables.$base-spacing * 1.5;
font-weight: bold;
font-size: 34px;
font-style: normal;
line-height: 36px;
letter-spacing: 0.25px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.14), 0 3px 4px rgba(0, 0, 0, 0.12), 0 1px 5px rgba(0, 0, 0, 0.2);
}
31 changes: 31 additions & 0 deletions src/components/Favorites/Favorites.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { render } from '@testing-library/react';

import QueryProvider from '../../providers/QueryProvider';
import { PersonalShelf } from '../../enum/PersonalShelf';
import PlaylistContainer from '../../containers/Playlist/PlaylistContainer';

import Favorites from './Favorites';

describe('<Favorites>', () => {
test('renders and matches snapshot', () => {
const { container } = render(
<QueryProvider>
<PlaylistContainer playlistId={PersonalShelf.Favorites}>
{({ playlist, error, isLoading }) => (
<Favorites
playlist={playlist.playlist}
error={error}
isLoading={isLoading}
onCardClick={() => null}
onCardHover={() => null}
onClearFavoritesClick={() => null}
/>
)}
</PlaylistContainer>
</QueryProvider>,
);

expect(container).toMatchSnapshot();
});
});
60 changes: 60 additions & 0 deletions src/components/Favorites/Favorites.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useContext } from 'react';
import { useTranslation } from 'react-i18next';
import type { PlaylistItem } from 'types/playlist';
import type { Config } from 'types/Config';

import { ConfigContext } from '../../providers/ConfigProvider';
import Button from '../Button/Button';
import CardGrid from '../CardGrid/CardGrid';
import LoadingOverlay from '../LoadingOverlay/LoadingOverlay';
import ErrorPage from '../ErrorPage/ErrorPage';
import { Breakpoint, Breakpoints } from '../../hooks/useBreakpoint';

import styles from './Favorites.module.scss';

type Props = {
playlist: PlaylistItem[];
error: unknown;
isLoading: boolean;
onCardClick: (item: PlaylistItem) => void;
onCardHover: (item: PlaylistItem) => void;
onClearFavoritesClick: () => void;
};

const cols: Breakpoints = {
[Breakpoint.xs]: 2,
[Breakpoint.sm]: 3,
[Breakpoint.md]: 3,
[Breakpoint.lg]: 3,
[Breakpoint.xl]: 3,
};

const Favorites = ({ playlist, error, isLoading, onCardClick, onCardHover, onClearFavoritesClick }: Props): JSX.Element => {
const { t } = useTranslation('user');
const config: Config = useContext(ConfigContext);

if (isLoading) return <LoadingOverlay />;

if (error || !playlist) {
return <ErrorPage title={t('favorites.not_found')} />;
}

return (
<div>
<div className={styles.header}>
<h3>{t('favorites.title')}</h3>
<Button label={t('favorites.clear')} onClick={onClearFavoritesClick} />
</div>
<CardGrid
playlist={playlist}
onCardClick={onCardClick}
onCardHover={onCardHover}
cols={cols}
isLoading={isLoading}
enableCardTitles={config.options.shelveTitles}
/>
</div>
);
};

export default Favorites;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<Favorites> renders and matches snapshot 1`] = `<div />`;
7 changes: 4 additions & 3 deletions src/components/ModalCloseButton/ModalCloseButton.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';

import styles from './ModalCloseButton.module.scss';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';

import Close from '../../icons/Close';
import IconButton from '../IconButton/IconButton';
import { useTranslation } from 'react-i18next';

import styles from './ModalCloseButton.module.scss';

type Props = {
onClick?: () => void;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Video/Video.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import { formatDuration } from '../../utils/formatting';
import Modal from '../Modal/Modal';
import FavoriteBorder from '../../icons/FavoriteBorder';
import Fade from '../Animation/Fade/Fade';
import ModalCloseButton from '../ModalCloseButton/ModalCloseButton';

import styles from './Video.module.scss';
import ModalCloseButton from '../ModalCloseButton/ModalCloseButton';

type Poster = 'fading' | 'normal';

Expand Down
2 changes: 1 addition & 1 deletion src/i18n/locales/en_US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export { default as common } from './en_US/common.json';
export { default as error } from './en_US/error.json';
export { default as menu } from './en_US/menu.json';
export { default as search } from './en_US/search.json';
export { default as video } from './en_US/video.json';
export { default as user } from './en_US/user.json';
export { default as video } from './en_US/video.json';
33 changes: 18 additions & 15 deletions src/i18n/locales/en_US/user.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
{
"account": {
"email": "Email",
"about_you": "About you",
"edit_account": "Edit account",
"security": "Security",
"password": "Password",
"edit_information": "Edit information",
"edit_password": "Edit password",
"about_you": "About you",
"email": "Email",
"firstname": "First name",
"lastname": "Last name",
"edit_information": "Edit information",
"terms_and_tracking": "Terms & tracking",
"password": "Password",
"security": "Security",
"update_consents": "Update consents"
},
"favorites": {
"clear": "Clear favorites",
"not_found": "Favorites not found!",
"title": "Favorites"
},
"payment": {
"subscription_details": "Subscription details",
"card_number": "Card number",
"cvc_cvv": "CVC / CVV",
"edit_subscription": "Edit subscription",
"expiry_date": "Expiry date",
"month": "month",
"monthly_subscription": "Monthly subscription",
"more_transactions": "{{ amount }} more transactions",
"next_billing_date_on": "Next billing date is on",
"month": "month",
"edit_subscription": "Edit subscription",
"payment_method": "Payment method",
"card_number": "Card number",
"expiry_date": "Expiry date",
"cvc_cvv": "CVC / CVV",
"transactions": "Transactions",
"price_payed_with_card": "Price payed with card",
"more_transactions": "{{ amount }} more transactions",
"show_all": "Show all"
"subscription_details": "Subscription details",
"transactions": "Transactions"
}
}
2 changes: 1 addition & 1 deletion src/i18n/locales/nl_NL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export { default as common } from './nl_NL/common.json';
export { default as error } from './nl_NL/error.json';
export { default as menu } from './nl_NL/menu.json';
export { default as search } from './nl_NL/search.json';
export { default as video } from './nl_NL/video.json';
export { default as user } from './nl_NL/user.json';
export { default as video } from './nl_NL/video.json';
33 changes: 18 additions & 15 deletions src/i18n/locales/nl_NL/user.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
{
"account": {
"email": "",
"about_you": "",
"edit_account": "",
"security": "",
"password": "",
"edit_information": "",
"edit_password": "",
"about_you": "",
"email": "",
"firstname": "",
"lastname": "",
"edit_information": "",
"terms_and_tracking": "",
"password": "",
"security": "",
"update_consents": ""
},
"favorites": {
"clear": "",
"not_found": "",
"title": ""
},
"payment": {
"subscription_details": "",
"card_number": "",
"cvc_cvv": "",
"edit_subscription": "",
"expiry_date": "",
"month": "",
"monthly_subscription": "",
"more_transactions": "",
"next_billing_date_on": "",
"month": "",
"edit_subscription": "",
"payment_method": "",
"card_number": "",
"expiry_date": "",
"cvc_cvv": "",
"transactions": "",
"price_payed_with_card": "",
"more_transactions": "",
"show_all": ""
"subscription_details": "",
"transactions": ""
}
}
2 changes: 1 addition & 1 deletion src/screens/User/User.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
}

@include responsive.tablet-only() {
margin: 0 variables.$base-spacing * 2;
margin: 0 variables.$base-spacing * 1.5;
}
}
.leftColumn {
Expand Down
29 changes: 27 additions & 2 deletions src/screens/User/User.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { Redirect, Route, Switch, useHistory } from 'react-router-dom';
import type { PlaylistItem } from 'types/playlist';

import Favorites from '../../components/Favorites/Favorites';
import PlaylistContainer from '../../containers/Playlist/PlaylistContainer';
import { PersonalShelf } from '../../enum/PersonalShelf';
import useBlurImageUpdater from '../../hooks/useBlurImageUpdater';
import { cardUrl } from '../../utils/formatting';
import Customer from '../../containers/Customer/Customer';
import SubscriptionContainer from '../../containers/Subscription/Subscription';
import useBreakpoint, { Breakpoint } from '../../hooks/useBreakpoint';
Expand All @@ -11,13 +17,21 @@ import AccountCircle from '../../icons/AccountCircle';
import Favorite from '../../icons/Favorite';
import BalanceWallet from '../../icons/BalanceWallet';
import Exit from '../../icons/Exit';
import { useFavorites } from '../../stores/FavoritesStore';

import styles from './User.module.scss';

const User = (): JSX.Element => {
const history = useHistory();
const breakpoint = useBreakpoint();
const isLargeScreen = breakpoint >= Breakpoint.md;

const updateBlurImage = useBlurImageUpdater();
const { clearList: clearFavorites } = useFavorites();

const onCardClick = (playlistItem: PlaylistItem) => history.push(cardUrl(playlistItem));
const onCardHover = (playlistItem: PlaylistItem) => updateBlurImage(playlistItem.image);

return (
<div className={styles.user}>
{isLargeScreen && (
Expand Down Expand Up @@ -50,7 +64,18 @@ const User = (): JSX.Element => {
</Customer>
</Route>
<Route path="/u/favorites">
<div>Favorites</div>
<PlaylistContainer playlistId={PersonalShelf.Favorites}>
{({ playlist, error, isLoading }) => (
<Favorites
playlist={playlist.playlist}
error={error}
isLoading={isLoading}
onCardClick={onCardClick}
onCardHover={onCardHover}
onClearFavoritesClick={clearFavorites}
/>
)}
</PlaylistContainer>
</Route>
<Route path="/u/payments">
<SubscriptionContainer>
Expand Down
10 changes: 9 additions & 1 deletion src/stores/FavoritesStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ const createFavorite = (item: PlaylistItem): Favorite =>
type SaveItemFn = (item: PlaylistItem) => void;
type RemoveItemFn = (item: PlaylistItem) => void;
type HasItemFn = (item: PlaylistItem) => boolean;
type ClearListFn = () => void;
type getPlaylistFn = () => Playlist;

type UseFavoritesReturn = {
saveItem: SaveItemFn;
removeItem: RemoveItemFn;
hasItem: HasItemFn;
clearList: ClearListFn;
getPlaylist: getPlaylistFn;
};

Expand All @@ -80,6 +82,12 @@ export const useFavorites = (): UseFavoritesReturn => {
return favorites.some(({ mediaid }) => mediaid === item.mediaid);
};

const clearList = () => {
favoritesStore.update((state) => {
state.favorites = [];
});
};

const getPlaylist = () => {
return {
feedid: PersonalShelf.Favorites,
Expand All @@ -88,5 +96,5 @@ export const useFavorites = (): UseFavoritesReturn => {
} as Playlist;
};

return { saveItem, removeItem, hasItem, getPlaylist };
return { saveItem, removeItem, hasItem, clearList, getPlaylist };
};

0 comments on commit 7f94e98

Please sign in to comment.