comment sorting

This commit is contained in:
keyan 2021-12-21 15:29:42 -06:00
parent f6b1da64f9
commit 0dfda596b0
6 changed files with 126 additions and 16 deletions

View File

@ -5,18 +5,35 @@ import { decodeCursor, LIMIT, nextCursorEncoded } from '../../lib/cursor'
import { getMetadata, metadataRuleSets } from 'page-metadata-parser' import { getMetadata, metadataRuleSets } from 'page-metadata-parser'
import domino from 'domino' import domino from 'domino'
async function comments (models, id) { async function comments (models, id, sort) {
let orderBy
let join
switch (sort) {
case 'top':
orderBy = 'ORDER BY x.sats DESC NULLS LAST'
join = LEFT_JOIN_SATS
break
case 'recent':
orderBy = 'ORDER BY "Item".created_at DESC'
join = ''
break
default:
orderBy = ORDER_BY_SATS
join = LEFT_JOIN_SATS
break
}
const flat = await models.$queryRaw(` const flat = await models.$queryRaw(`
WITH RECURSIVE base AS ( WITH RECURSIVE base AS (
${SELECT}, ARRAY[row_number() OVER (${ORDER_BY_SATS}, "Item".path)] AS sort_path ${SELECT}, ARRAY[row_number() OVER (${orderBy}, "Item".path)] AS sort_path
FROM "Item" FROM "Item"
${LEFT_JOIN_SATS} ${join}
WHERE "parentId" = $1 WHERE "parentId" = $1
UNION ALL UNION ALL
${SELECT}, p.sort_path || row_number() OVER (${ORDER_BY_SATS}, "Item".path) ${SELECT}, p.sort_path || row_number() OVER (${orderBy}, "Item".path)
FROM base p FROM base p
JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path" JOIN "Item" ON ltree2text(subpath("Item"."path", 0, -1)) = p."path"
${LEFT_JOIN_SATS}) ${join})
SELECT * FROM base ORDER BY sort_path`, Number(id)) SELECT * FROM base ORDER BY sort_path`, Number(id))
return nestComments(flat, id)[0] return nestComments(flat, id)[0]
} }
@ -27,7 +44,7 @@ export async function getItem (parent, { id }, { models }) {
FROM "Item" FROM "Item"
WHERE id = $1`, Number(id)) WHERE id = $1`, Number(id))
if (item) { if (item) {
item.comments = comments(models, id) item.comments = comments(models, id, 'hot')
} }
return item return item
} }
@ -211,6 +228,9 @@ export default {
WHERE url SIMILAR TO $1 WHERE url SIMILAR TO $1
ORDER BY created_at DESC ORDER BY created_at DESC
LIMIT 3`, similar) LIMIT 3`, similar)
},
comments: async (parent, { id, sort }, { models }) => {
return comments(models, id, sort)
} }
}, },

View File

@ -5,6 +5,7 @@ export default gql`
moreItems(sort: String!, cursor: String, name: String, within: String): Items moreItems(sort: String!, cursor: String, name: String, within: String): Items
moreFlatComments(sort: String!, cursor: String, name: String, within: String): Comments moreFlatComments(sort: String!, cursor: String, name: String, within: String): Comments
item(id: ID!): Item item(id: ID!): Item
comments(id: ID!, sort: String): [Item!]!
pageTitle(url: String!): String pageTitle(url: String!): String
dupes(url: String!): [Item!] dupes(url: String!): [Item!]
} }

View File

@ -80,12 +80,12 @@
margin-bottom: 0; margin-bottom: 0;
} }
.comment:not(:last-child) { .comment:not(:last-of-type) {
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
} }
.comment:not(:first-child) { .comment:not(:first-of-type) {
padding-top: .25rem; padding-top: .25rem;
border-top-left-radius: 0; border-top-left-radius: 0;
border-top-right-radius: 0; border-top-right-radius: 0;

View File

@ -1,19 +1,98 @@
import { useQuery } from '@apollo/client' import { gql, useApolloClient, useLazyQuery, useQuery } from '@apollo/client'
import { useEffect } from 'react' import { useEffect, useState } from 'react'
import Comment, { CommentSkeleton } from './comment' import Comment, { CommentSkeleton } from './comment'
import styles from './header.module.css'
import { Nav, Navbar } from 'react-bootstrap'
import { COMMENTS_QUERY } from '../fragments/items'
import { COMMENTS } from '../fragments/comments'
export default function Comments ({ comments, ...props }) { export function CommentsHeader ({ handleSort }) {
const [sort, setSort] = useState('hot')
const getHandleClick = sort => {
return () => {
setSort(sort)
handleSort(sort)
}
}
return (
<Navbar className='py-0'>
<Nav
className={styles.navbarNav}
activeKey={sort}
>
<Nav.Item>
<Nav.Link
eventKey='hot'
className={styles.navLink}
onClick={getHandleClick('hot')}
>
hot
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link
eventKey='recent'
className={styles.navLink}
onClick={getHandleClick('recent')}
>
recent
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link
eventKey='top'
className={styles.navLink}
onClick={getHandleClick('top')}
>
top
</Nav.Link>
</Nav.Item>
</Nav>
</Navbar>
)
}
export default function Comments ({ parentId, comments, ...props }) {
const client = useApolloClient()
useEffect(() => { useEffect(() => {
// Your code here
const hash = window.location.hash const hash = window.location.hash
if (hash) { if (hash) {
document.querySelector(hash).scrollIntoView({ behavior: 'smooth' }) document.querySelector(hash).scrollIntoView({ behavior: 'smooth' })
} }
}, []) }, [])
const [getComments, { loading }] = useLazyQuery(COMMENTS_QUERY, {
fetchPolicy: 'network-only',
onCompleted: data => {
client.writeFragment({
id: `Item:${parentId}`,
fragment: gql`
${COMMENTS}
fragment Comments on Item {
comments {
...CommentsRecursive
}
}
`,
fragmentName: 'Comments',
data: {
comments: data.comments
}
})
}
})
return comments.map(item => ( return (
<Comment key={item.id} item={item} {...props} /> <>
)) {comments.length ? <CommentsHeader handleSort={sort => getComments({ variables: { id: parentId, sort } })} /> : null}
{loading
? <CommentsSkeleton />
: comments.map(item => (
<Comment key={item.id} item={item} {...props} />
))}
</>
)
} }
export function CommentsSkeleton () { export function CommentsSkeleton () {

View File

@ -57,7 +57,7 @@ export default function ItemFull ({ item, bio, ...props }) {
</div>)} </div>)}
{item.comments && {item.comments &&
<div className={styles.comments}> <div className={styles.comments}>
<Comments comments={item.comments} /> <Comments parentId={item.id} comments={item.comments} />
</div>} </div>}
</> </>
) )

View File

@ -52,6 +52,16 @@ export const ITEM = gql`
} }
}` }`
export const COMMENTS_QUERY = gql`
${COMMENTS}
query Comments($id: ID!, $sort: String) {
comments(id: $id, sort: $sort) {
...CommentsRecursive
}
}
`
export const ITEM_FULL = gql` export const ITEM_FULL = gql`
${ITEM_FIELDS} ${ITEM_FIELDS}
${COMMENTS} ${COMMENTS}