From 73aceae6a0ae861d2ef1e76eeb0d67531c9a532d Mon Sep 17 00:00:00 2001 From: lutangar Date: Mon, 9 Nov 2020 15:39:40 +0100 Subject: [PATCH] feat(profile): Show one, all, or none featured notices on contributor profile --- src/app/lmem/contributor.ts | 15 +++-- .../Pages/Profiles/Profile/FeaturedNotice.tsx | 2 - .../Profiles/Profile/FeaturedNotices.tsx | 53 +++++++++++++++ .../Profiles/Profile/FeaturedNoticesTitle.tsx | 23 +++++++ .../Profiles/Profile/Profile.stories.tsx | 66 +++++++++++++++++-- .../App/Pages/Profiles/Profile/Profile.tsx | 24 ++++--- .../Profiles/Profile/ProfileNoticeList.tsx | 19 +++--- .../App/Pages/Profiles/Profile/withConnect.ts | 8 +-- src/app/profiles/store/selectors/index.ts | 23 ++++--- 9 files changed, 188 insertions(+), 45 deletions(-) create mode 100644 src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotices.tsx create mode 100644 src/app/profiles/App/Pages/Profiles/Profile/FeaturedNoticesTitle.tsx diff --git a/src/app/lmem/contributor.ts b/src/app/lmem/contributor.ts index bf31fe830..e975d6481 100644 --- a/src/app/lmem/contributor.ts +++ b/src/app/lmem/contributor.ts @@ -11,12 +11,17 @@ interface Picture { export type ContributorId = number; +export interface PinnedNotice { + sort?: number; + matchingUrl: string; + noticeId: number; + noticeUrl: string; +} + interface Contribution { - example: { - matchingUrl: string; - noticeId: number; - noticeUrl: string; - }; + example: PinnedNotice; // @deprecated use `pinnedNotices` instead + starred: PinnedNotice; // @deprecated use `pinnedNotices` instead + pinnedNotices: PinnedNotice[]; } export interface BaseContributor { diff --git a/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotice.tsx b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotice.tsx index 9b23e4301..5500255f7 100644 --- a/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotice.tsx +++ b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotice.tsx @@ -2,8 +2,6 @@ import styled from 'styled-components'; import { ProfileNoticeListItem } from './ProfileNoticeListItem'; const FeaturedNotice = styled(ProfileNoticeListItem).attrs({ featured: true })` - margin-bottom: 40px; - img { margin-bottom: 10px; box-shadow: 4px 4px 18px 0 rgba(0, 0, 0, 0.3); diff --git a/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotices.tsx b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotices.tsx new file mode 100644 index 000000000..e9c07750b --- /dev/null +++ b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNotices.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import styled from 'styled-components'; +import FeaturedNotice from './FeaturedNotice'; +import { LoadingRotator } from 'components/atoms'; +import { LoadingBig } from 'components/atoms/icons'; +import { NoticeWithContributor } from 'app/lmem/notice'; +import { StatefulContributor } from 'app/lmem/contributor'; + +export interface FeaturedNoticesProps { + loading?: boolean; + notices: NoticeWithContributor[]; + seeNoticeInContext: (notice: NoticeWithContributor) => () => void; + contributor?: StatefulContributor; + className?: string; +} + +const FeatureNoticesContainer = styled.section` + margin-bottom: 40px; +`; + +const FeaturedNotices = ({ + loading, + notices, + seeNoticeInContext, + className +}: FeaturedNoticesProps) => { + if (typeof loading === 'undefined') { + return null; + } + + return ( + + {loading ? ( + + + + ) : ( + <> + {notices.map(notice => ( + + ))} + + )} + + ); +}; + +export default FeaturedNotices; diff --git a/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNoticesTitle.tsx b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNoticesTitle.tsx new file mode 100644 index 000000000..d20483c6e --- /dev/null +++ b/src/app/profiles/App/Pages/Profiles/Profile/FeaturedNoticesTitle.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Title2 } from 'components/atoms'; +import { StatefulContributor } from 'app/lmem/contributor'; + +export interface FeaturedNoticesTitleProps { + plural: boolean; + contributor?: StatefulContributor; + className?: string; +} + +const FeaturedNoticesTitle = ({ + plural, + contributor, + className +}: FeaturedNoticesTitleProps) => ( + + {`L${plural ? 'es' : 'a'} contribution${plural ? 's' : ''} phare${ + plural ? 's' : '' + } ${contributor && `de ${contributor.name}`}`} + +); + +export default FeaturedNoticesTitle; diff --git a/src/app/profiles/App/Pages/Profiles/Profile/Profile.stories.tsx b/src/app/profiles/App/Pages/Profiles/Profile/Profile.stories.tsx index cfeeb6dd4..2d0310997 100644 --- a/src/app/profiles/App/Pages/Profiles/Profile/Profile.stories.tsx +++ b/src/app/profiles/App/Pages/Profiles/Profile/Profile.stories.tsx @@ -20,7 +20,7 @@ storiesOf('Profile/Profile', module) )) .add('Normal', () => ( ( ( ( + )) + .add('no featured notices', () => ( + + )) + .add('1 featured notices', () => ( + )); diff --git a/src/app/profiles/App/Pages/Profiles/Profile/Profile.tsx b/src/app/profiles/App/Pages/Profiles/Profile/Profile.tsx index 03759bc94..0789b74cd 100644 --- a/src/app/profiles/App/Pages/Profiles/Profile/Profile.tsx +++ b/src/app/profiles/App/Pages/Profiles/Profile/Profile.tsx @@ -11,7 +11,6 @@ import { TwoColumns } from 'components/atoms'; import SimilarProfiles from '../../../SimilarProfiles'; -import FeaturedNotice from './FeaturedNotice'; import ProfileIntro from './ProfileIntro'; import ProfileNoticeList from './ProfileNoticeList'; import CenterContainer from 'components/atoms/CenterContainer'; @@ -23,6 +22,8 @@ import { AddToBrowserMessageBox, PrivacyMessageBox } from 'components/molecules/SidebarBox'; +import FeaturedNotices from './FeaturedNotices'; +import FeaturedNoticesTitle from './FeaturedNoticesTitle'; export const MainCol = styled.div` ${CenterContainer} { @@ -111,7 +112,7 @@ export interface ProfileProps { contributor?: StatefulContributor; noticesLoading?: boolean; notices: NoticeWithContributor[]; - featuredNotice?: NoticeWithContributor; + featuredNotices: NoticeWithContributor[]; subscribe: (contributorId: ContributorId) => void; unsubscribe: (contributorId: ContributorId) => void; fetchMoreNotices: () => void | undefined; @@ -126,7 +127,7 @@ export const Profile = ({ subscribe, unsubscribe, noticesLoading, - featuredNotice, + featuredNotices, notices, connected, addToBrowser, @@ -194,15 +195,18 @@ export const Profile = ({ unsubscribe={handleUnsubscribe(contributor)} usernameAs={'h1'} /> - - La contribution phare {contributor && `de ${contributor.name}`} - - 0 && ( + 1} + /> + )} + - Ses dernières contributions Pas d'autres contributions )} - {notices && - notices.map(notice => ( - - ))} - {notices && notices.length && !loading && !fetchedAll && ( + {notices.map(notice => ( + + ))} + {notices.length > 0 && !loading && !fetchedAll && ( Voir plus diff --git a/src/app/profiles/App/Pages/Profiles/Profile/withConnect.ts b/src/app/profiles/App/Pages/Profiles/Profile/withConnect.ts index 659bf0009..0d968d2dd 100644 --- a/src/app/profiles/App/Pages/Profiles/Profile/withConnect.ts +++ b/src/app/profiles/App/Pages/Profiles/Profile/withConnect.ts @@ -5,8 +5,8 @@ import { subscribe, unsubscribe } from 'app/actions/subscription'; import { areContributorNoticesAllFetched, getContributorFromRouteParam, - getContributorNoticesButFeaturedOne, - getFeaturedNotice, + getContributorNoticesButFeaturedOnes, + getFeaturedNotices, getStatefulContributors } from 'app/profiles/store/selectors'; import { areNoticesLoading } from 'app/profiles/store/selectors/notices'; @@ -27,9 +27,9 @@ const mapStateToProps = ( loading: areContributorsLoading(state), contributor: getContributorFromRouteParam(state, props), contributors: getStatefulContributors(state), - featuredNotice: getFeaturedNotice(state, props), + featuredNotices: getFeaturedNotices(state, props), noticesLoading: areNoticesLoading(state), - notices: getContributorNoticesButFeaturedOne(state, props), + notices: getContributorNoticesButFeaturedOnes(state, props), fetchedAll: (contributorId: ContributorId) => areContributorNoticesAllFetched(state, contributorId), connected: isConnected(state), diff --git a/src/app/profiles/store/selectors/index.ts b/src/app/profiles/store/selectors/index.ts index 7a4c7148c..b0666a36f 100644 --- a/src/app/profiles/store/selectors/index.ts +++ b/src/app/profiles/store/selectors/index.ts @@ -59,9 +59,12 @@ export const getContributorFromRouteParam = createSelector( (contributors, id) => findItemById(Number(id))(contributors) ); -export const getFeaturedNoticeId = createSelector( +export const getFeaturedNoticesIds = createSelector( [getContributorFromRouteParam], - contributor => contributor?.contribution?.example?.noticeId + contributor => + (contributor?.contribution?.pinnedNotices || []).map( + ({ noticeId }) => noticeId + ) ); export const enhanceNotice = (contributors: Contributor[]) => ( @@ -104,16 +107,16 @@ export const getNoticesForContributorId = createSelector( export const getContributorById = (id: number) => createSelector([getContributors], findItemById(id)); -export const getFeaturedNotice = createSelector( - [getFeaturedNoticeId, getNotices], - (featuredNoticeId, notices) => - notices.find(({ id }) => id === featuredNoticeId) +export const getFeaturedNotices = createSelector( + [getFeaturedNoticesIds, getNotices], + (featuredNoticesIds, notices) => + notices.filter(({ id }) => featuredNoticesIds.includes(id)) ); -export const getContributorNoticesButFeaturedOne = createSelector( - [getFeaturedNoticeId, getContributorNotices], - (featuredNoticeId, notices) => - notices.filter(({ id }) => id !== featuredNoticeId) +export const getContributorNoticesButFeaturedOnes = createSelector( + [getFeaturedNoticesIds, getContributorNotices], + (featuredNoticesIds, notices) => + notices.filter(({ id }) => !featuredNoticesIds.includes(id)) ); export const areContributorNoticesAllFetched = createSelector(