-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement Cooccurrence display (#561)
refactor(components): move SideSection layout prop parent wrapper - so that layout can be performed on pages, enabling different layouts feat(pages): load cooccurrence data and implement CooccurrenceSection ## Screenshots https://dev.cofacts.tw/article/5pT69owBXtQmmerovXlq ### Desktop  ### Mobile 
- Loading branch information
Showing
11 changed files
with
321 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { useMemo } from 'react'; | ||
import Link from 'next/link'; | ||
import { ngettext, msgid, t } from 'ttag'; | ||
import gql from 'graphql-tag'; | ||
import { CooccurrenceSectionDataFragment } from 'typegen/graphql'; | ||
import { makeStyles } from '@material-ui/core/styles'; | ||
|
||
import Infos, { TimeInfo } from 'components/Infos'; | ||
import { | ||
SideSection, | ||
SideSectionHeader, | ||
SideSectionLinks, | ||
SideSectionLink, | ||
SideSectionText, | ||
} from 'components/SideSection'; | ||
import Thumbnail from 'components/Thumbnail'; | ||
|
||
export const fragments = { | ||
CooccurrenceSectionData: gql` | ||
fragment CooccurrenceSectionData on Cooccurrence { | ||
createdAt | ||
articles { | ||
id | ||
articleType | ||
text | ||
...ThumbnailArticleData | ||
} | ||
} | ||
${Thumbnail.fragments.ThumbnailArticleData} | ||
`, | ||
}; | ||
|
||
const useStyles = makeStyles(theme => ({ | ||
timeInfo: { | ||
margin: '8px 0 0', | ||
[theme.breakpoints.up('md')]: { | ||
margin: '0 0 16px', | ||
}, | ||
}, | ||
})); | ||
|
||
type Props = { | ||
/** Ignore the current article */ | ||
currentArticleId: string; | ||
cooccurrences: CooccurrenceSectionDataFragment[]; | ||
}; | ||
|
||
function CooccurrenceSection({ currentArticleId, cooccurrences }: Props) { | ||
const classes = useStyles(); | ||
// Group cooccurrences by same articles | ||
// then sort by count (more first) and then last createdAt (latest first) | ||
const cooccurrenceEntries = useMemo(() => { | ||
const entries = new Map< | ||
string, | ||
{ | ||
key: string; | ||
articles: CooccurrenceSectionDataFragment['articles']; | ||
count: number; | ||
lastCooccurred: Date; | ||
} | ||
>(); | ||
cooccurrences.forEach(cooccurrence => { | ||
const key = cooccurrence.articles | ||
.map(article => article.id) | ||
.sort() | ||
.join(','); | ||
const lastCooccurred = new Date(cooccurrence.createdAt); | ||
const entry = entries.get(key); | ||
const lastCooccurredInEntry = entry ? entry.lastCooccurred : null; | ||
entries.set(key, { | ||
key, | ||
articles: cooccurrence.articles.filter( | ||
({ id }) => id !== currentArticleId | ||
), | ||
count: entry ? entry.count + 1 : 1, | ||
lastCooccurred: | ||
lastCooccurredInEntry === null || | ||
lastCooccurredInEntry < lastCooccurred | ||
? lastCooccurred | ||
: lastCooccurredInEntry, | ||
}); | ||
}); | ||
return Array.from(entries.values()).sort((a, b) => { | ||
if (a.count !== b.count) return b.count - a.count; | ||
return +b.lastCooccurred - +a.lastCooccurred; | ||
}); | ||
}, [cooccurrences, currentArticleId]); | ||
|
||
if (!cooccurrences.length) return null; | ||
|
||
return ( | ||
<> | ||
{cooccurrenceEntries.map(entry => ( | ||
<SideSection key={entry.key}> | ||
<SideSectionHeader> | ||
{ngettext( | ||
msgid`Sent together ${entry.count} time`, | ||
`Sent together ${entry.count} times`, | ||
entry.count | ||
)} | ||
</SideSectionHeader> | ||
<SideSectionLinks> | ||
{entry.articles.map(article => ( | ||
<Link | ||
key={article.id} | ||
href="/article/[id]" | ||
as={`/article/${article.id}`} | ||
passHref | ||
> | ||
<SideSectionLink> | ||
{article.articleType !== 'TEXT' ? ( | ||
<Thumbnail article={article} /> | ||
) : ( | ||
<SideSectionText>{article.text}</SideSectionText> | ||
)} | ||
</SideSectionLink> | ||
</Link> | ||
))} | ||
</SideSectionLinks> | ||
<Infos className={classes.timeInfo}> | ||
<TimeInfo time={entry.lastCooccurred}> | ||
{time => t`Last reported at ${time}`} | ||
</TimeInfo> | ||
</Infos> | ||
</SideSection> | ||
))} | ||
</> | ||
); | ||
} | ||
|
||
export default CooccurrenceSection; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import CooccurrenceSection, { fragments } from './CooccurrenceSection'; | ||
|
||
export { fragments }; | ||
|
||
export default CooccurrenceSection; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.