pre recursive comments
This commit is contained in:
parent
28ed42fc29
commit
95d6d789fa
|
@ -31,24 +31,33 @@ export default {
|
||||||
Query: {
|
Query: {
|
||||||
items: async (parent, args, { models }) => {
|
items: async (parent, args, { models }) => {
|
||||||
return await models.$queryRaw(`
|
return await models.$queryRaw(`
|
||||||
SELECT id, "created_at" as "createdAt", title, url, text, "userId", ltree2text("path") AS "path"
|
SELECT id, "created_at" as "createdAt", title, url, text,
|
||||||
|
"userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
WHERE "parentId" IS NULL
|
WHERE "parentId" IS NULL`)
|
||||||
ORDER BY "path"`)
|
|
||||||
},
|
},
|
||||||
item: async (parent, { id }, { models }) => {
|
item: async (parent, { id }, { models }) => {
|
||||||
const res = await models.$queryRaw(`
|
const res = await models.$queryRaw(`
|
||||||
SELECT id, "created_at" as "createdAt", title, url, text, "parentId", "userId", ltree2text("path") AS "path"
|
SELECT id, "created_at" as "createdAt", title, url, text,
|
||||||
|
"parentId", "userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
WHERE id = ${id}
|
WHERE id = ${id}`)
|
||||||
ORDER BY "path"`)
|
|
||||||
return res.length ? res[0] : null
|
return res.length ? res[0] : null
|
||||||
},
|
},
|
||||||
ncomments: async (parent, { parentId }, { models }) => {
|
comments: async (parent, { parentId }, { models }) => {
|
||||||
return await models.$queryRaw(`
|
return await models.$queryRaw(`
|
||||||
SELECT id, "created_at" as "createdAt", title, url, text, "userId", ltree2text("path") AS "path"
|
SELECT id, "created_at" as "createdAt", text, "parentId",
|
||||||
|
"userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
|
WHERE path <@ (SELECT path FROM "Item" where id = ${parentId}) AND id != ${parentId}
|
||||||
ORDER BY "path"`)
|
ORDER BY "path"`)
|
||||||
|
},
|
||||||
|
root: async (parent, { id }, { models }) => {
|
||||||
|
const res = await models.$queryRaw(`
|
||||||
|
SELECT id, title
|
||||||
|
FROM "Item"
|
||||||
|
WHERE id = (SELECT ltree2text(subltree(path, 0, 1))::integer FROM "Item" WHERE id = ${id})`)
|
||||||
|
return res.length ? res[0] : null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -87,24 +96,11 @@ export default {
|
||||||
Item: {
|
Item: {
|
||||||
user: async (item, args, { models }) =>
|
user: async (item, args, { models }) =>
|
||||||
await models.user.findUnique({ where: { id: item.userId } }),
|
await models.user.findUnique({ where: { id: item.userId } }),
|
||||||
depth: async (item, args, { models }) => {
|
|
||||||
if (item.path) {
|
|
||||||
return item.path.split('.').length - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// as the result of a mutation, path is not populated
|
|
||||||
const [{ path }] = await models.$queryRaw`
|
|
||||||
SELECT ltree2text("path") AS "path"
|
|
||||||
FROM "Item"
|
|
||||||
WHERE id = ${item.id}`
|
|
||||||
|
|
||||||
return path.split('.').length - 1
|
|
||||||
},
|
|
||||||
ncomments: async (item, args, { models }) => {
|
ncomments: async (item, args, { models }) => {
|
||||||
const [{ count }] = await models.$queryRaw`
|
const [{ count }] = await models.$queryRaw`
|
||||||
SELECT count(*)
|
SELECT count(*)
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
WHERE path <@ text2ltree(${item.id}) AND id != ${item.id}`
|
WHERE path <@ text2ltree(${item.path}) AND id != ${item.id}`
|
||||||
return count
|
return count
|
||||||
},
|
},
|
||||||
sats: () => 0
|
sats: () => 0
|
||||||
|
|
|
@ -4,7 +4,8 @@ export default gql`
|
||||||
extend type Query {
|
extend type Query {
|
||||||
items: [Item!]!
|
items: [Item!]!
|
||||||
item(id: ID!): Item
|
item(id: ID!): Item
|
||||||
ncomments(id: ID!): [Item!]!
|
comments(parentId: ID!): [Item!]!
|
||||||
|
root(id: ID!): Item
|
||||||
}
|
}
|
||||||
|
|
||||||
extend type Mutation {
|
extend type Mutation {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Text from './text'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Reply from './reply'
|
import Reply from './reply'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import { gql, useQuery } from '@apollo/client'
|
||||||
|
|
||||||
function timeSince (timeStamp) {
|
function timeSince (timeStamp) {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
|
@ -26,8 +27,42 @@ function timeSince (timeStamp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Comment ({ item, children }) {
|
function Parent ({ item }) {
|
||||||
const [reply, setReply] = useState(false)
|
const { data } = useQuery(
|
||||||
|
gql`{
|
||||||
|
root(id: ${item.id}) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const ParentFrag = () => (
|
||||||
|
<>
|
||||||
|
<span> \ </span>
|
||||||
|
<Link href={`/items/${item.parentId}`} passHref>
|
||||||
|
<a className='text-reset'>parent</a>
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return <ParentFrag />
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data.root.id !== item.parentId && <ParentFrag />}
|
||||||
|
<span> \ </span>
|
||||||
|
<Link href={`/items/${data.root.id}`} passHref>
|
||||||
|
<a className='text-reset'>{data.root.title}</a>
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Comment ({ item, children, replyOpen, includeParent }) {
|
||||||
|
const [reply, setReply] = useState(replyOpen)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -43,7 +78,10 @@ export default function Comment ({ item, children }) {
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
<span>{item.sats} sats</span>
|
<span>{item.sats} sats</span>
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
<span>{item.ncomments} replies</span>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
|
<a className='text-reset'>{item.ncomments} replies</a>
|
||||||
|
</Link>
|
||||||
|
{includeParent && <Parent item={item} />}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.text}>
|
<div className={styles.text}>
|
||||||
<Text>{item.text}</Text>
|
<Text>{item.text}</Text>
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { useQuery, gql } from '@apollo/client'
|
||||||
|
import Comment from './comment'
|
||||||
|
|
||||||
|
export default function Comments ({ parentId, baseDepth }) {
|
||||||
|
const { data } = useQuery(
|
||||||
|
gql`{
|
||||||
|
comments(parentId: ${parentId}) {
|
||||||
|
id
|
||||||
|
createdAt
|
||||||
|
text
|
||||||
|
user {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
depth
|
||||||
|
sats
|
||||||
|
ncomments
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!data) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='mt-5'>
|
||||||
|
{data.comments.map(item => (
|
||||||
|
<div
|
||||||
|
key={item.id} className='mt-2'
|
||||||
|
style={{ marginLeft: `${42 * (item.depth - baseDepth - 1)}px` }}
|
||||||
|
>
|
||||||
|
<Comment item={item} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -37,7 +37,9 @@ export default function Item ({ item, children }) {
|
||||||
<div className={styles.other}>
|
<div className={styles.other}>
|
||||||
<span>{item.sats} sats</span>
|
<span>{item.sats} sats</span>
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
<span>{item.ncomments} comments</span>
|
<Link href={`/items/${item.id}`} passHref>
|
||||||
|
<a className='text-reset'>{item.ncomments} comments</a>
|
||||||
|
</Link>
|
||||||
<span> \ </span>
|
<span> \ </span>
|
||||||
<Link href={`/@${item.user.name}`} passHref>
|
<Link href={`/@${item.user.name}`} passHref>
|
||||||
<a>@{item.user.name}</a>
|
<a>@{item.user.name}</a>
|
||||||
|
@ -50,11 +52,6 @@ export default function Item ({ item, children }) {
|
||||||
{children && (
|
{children && (
|
||||||
<div className={styles.children}>
|
<div className={styles.children}>
|
||||||
{children}
|
{children}
|
||||||
{item.comments
|
|
||||||
? item.comments.map((item) => (
|
|
||||||
<Item key={item.id} item={item} />
|
|
||||||
))
|
|
||||||
: null}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ApolloClient from '../../api/client'
|
||||||
import Reply from '../../components/reply'
|
import Reply from '../../components/reply'
|
||||||
import Comment from '../../components/comment'
|
import Comment from '../../components/comment'
|
||||||
import Text from '../../components/text'
|
import Text from '../../components/text'
|
||||||
|
import Comments from '../../components/comments'
|
||||||
|
|
||||||
export async function getServerSideProps ({ params }) {
|
export async function getServerSideProps ({ params }) {
|
||||||
const { error, data: { item } } = await ApolloClient.query({
|
const { error, data: { item } } = await ApolloClient.query({
|
||||||
|
@ -20,6 +21,7 @@ export async function getServerSideProps ({ params }) {
|
||||||
user {
|
user {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
depth
|
||||||
sats
|
sats
|
||||||
ncomments
|
ncomments
|
||||||
}
|
}
|
||||||
|
@ -43,9 +45,7 @@ export default function FullItem ({ item }) {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
{item.parentId
|
{item.parentId
|
||||||
? (
|
? <Comment item={item} replyOpen includeParent />
|
||||||
<Comment item={item} />
|
|
||||||
)
|
|
||||||
: (
|
: (
|
||||||
<>
|
<>
|
||||||
<Item item={item}>
|
<Item item={item}>
|
||||||
|
@ -54,6 +54,7 @@ export default function FullItem ({ item }) {
|
||||||
</Item>
|
</Item>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<Comments parentId={item.id} baseDepth={item.depth} />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue