mostly clientside render
This commit is contained in:
parent
c626998952
commit
c82c82bb7b
|
@ -28,14 +28,6 @@ export default {
|
|||
WHERE "userId" = ${userId} AND "parentId" IS NULL
|
||||
ORDER BY created_at`)
|
||||
},
|
||||
comments: async (parent, { parentId }, { models }) => {
|
||||
const flat = await models.$queryRaw(`
|
||||
${SELECT}
|
||||
FROM "Item"
|
||||
WHERE path <@ (SELECT path FROM "Item" where id = ${parentId}) AND id != ${parentId}
|
||||
ORDER BY "path"`)
|
||||
return nestComments(flat, parentId)[0]
|
||||
},
|
||||
userComments: async (parent, { userId }, { models }) => {
|
||||
return await models.$queryRaw(`
|
||||
${SELECT}
|
||||
|
@ -119,6 +111,14 @@ export default {
|
|||
WHERE path <@ text2ltree(${item.path}) AND id != ${item.id}`
|
||||
return count
|
||||
},
|
||||
comments: async (item, args, { models }) => {
|
||||
const flat = await models.$queryRaw(`
|
||||
${SELECT}
|
||||
FROM "Item"
|
||||
WHERE path <@ (SELECT path FROM "Item" where id = ${item.id}) AND id != ${item.id}
|
||||
ORDER BY "path"`)
|
||||
return nestComments(flat, item.id)[0]
|
||||
},
|
||||
sats: async (item, args, { models }) => {
|
||||
const { sum: { sats } } = await models.vote.aggregate({
|
||||
sum: {
|
||||
|
@ -158,11 +158,6 @@ const createItem = async (parent, { title, text, url, parentId }, { me, models }
|
|||
title,
|
||||
url,
|
||||
text,
|
||||
item: {
|
||||
connect: {
|
||||
|
||||
}
|
||||
},
|
||||
user: {
|
||||
connect: {
|
||||
name: me.name
|
||||
|
|
|
@ -6,7 +6,6 @@ export default gql`
|
|||
recent: [Item!]!
|
||||
item(id: ID!): Item
|
||||
userItems(userId: ID!): [Item!]
|
||||
comments(parentId: ID!): [Item!]!
|
||||
userComments(userId: ID!): [Item!]
|
||||
root(id: ID!): Item
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ function Parent ({ item }) {
|
|||
)
|
||||
}
|
||||
|
||||
export default function Comment ({ item, children, replyOpen, includeParent, cacheId, noReply }) {
|
||||
export default function Comment ({ item, children, replyOpen, includeParent, cacheId, noComments, noReply }) {
|
||||
const [reply, setReply] = useState(replyOpen)
|
||||
|
||||
return (
|
||||
|
@ -82,7 +82,7 @@ export default function Comment ({ item, children, replyOpen, includeParent, cac
|
|||
{reply && <Reply parentId={item.id} onSuccess={() => setReply(replyOpen || false)} cacheId={cacheId} />}
|
||||
{children}
|
||||
<div className={styles.comments}>
|
||||
{item.comments
|
||||
{item.comments && !noComments
|
||||
? item.comments.map((item) => (
|
||||
<Comment key={item.id} item={item} />
|
||||
))
|
||||
|
|
|
@ -1,23 +1,31 @@
|
|||
import { useQuery } from '@apollo/client'
|
||||
import Comment, { CommentSkeleton } from './comment'
|
||||
|
||||
export default function Comments ({ query, ...props }) {
|
||||
const { loading, error, data } = useQuery(query)
|
||||
|
||||
if (error) return <div>Failed to load!</div>
|
||||
if (loading) {
|
||||
const comments = new Array(3).fill(null)
|
||||
|
||||
return comments.map((_, i) => (
|
||||
<div key={i} className='mt-2'>
|
||||
<CommentSkeleton skeletonChildren />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
return data.comments.map(item => (
|
||||
export default function Comments ({ comments, ...props }) {
|
||||
return comments.map(item => (
|
||||
<div key={item.id} className='mt-2'>
|
||||
<Comment item={item} {...props} />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
export function CommentsSkeleton () {
|
||||
const comments = new Array(3).fill(null)
|
||||
|
||||
return comments.map((_, i) => (
|
||||
<div key={i} className='mt-2'>
|
||||
<CommentSkeleton skeletonChildren />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
|
||||
export function CommentsQuery ({ query, ...props }) {
|
||||
const { loading, error, data } = useQuery(query)
|
||||
|
||||
if (error) return <div>Failed to load!</div>
|
||||
if (loading) {
|
||||
return <CommentsSkeleton />
|
||||
}
|
||||
|
||||
return <Comments comments={data.comments} {...props} />
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ export default function Item ({ item, rank, children }) {
|
|||
)
|
||||
}
|
||||
|
||||
export function ItemSkeleton ({ rank }) {
|
||||
export function ItemSkeleton ({ rank, children }) {
|
||||
return (
|
||||
<>
|
||||
{rank &&
|
||||
|
@ -66,6 +66,11 @@ export function ItemSkeleton ({ rank }) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{children && (
|
||||
<div className={styles.children}>
|
||||
{children}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ export const CommentSchema = Yup.object({
|
|||
text: Yup.string().required('required').trim()
|
||||
})
|
||||
|
||||
export default function Reply ({ parentId, onSuccess, cacheId }) {
|
||||
export default function Reply ({ parentId, onSuccess }) {
|
||||
const [createComment] = useMutation(
|
||||
gql`
|
||||
${COMMENTS}
|
||||
|
@ -22,7 +22,7 @@ export default function Reply ({ parentId, onSuccess, cacheId }) {
|
|||
}`, {
|
||||
update (cache, { data: { createComment } }) {
|
||||
cache.modify({
|
||||
id: cacheId || `Item:${parentId}`,
|
||||
id: `Item:${parentId}`,
|
||||
fields: {
|
||||
comments (existingCommentRefs = []) {
|
||||
const newCommentRef = cache.writeFragment({
|
||||
|
@ -67,3 +67,12 @@ export default function Reply ({ parentId, onSuccess, cacheId }) {
|
|||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function ReplySkeleton () {
|
||||
return (
|
||||
<div className={`${styles.reply} ${styles.skeleton}`}>
|
||||
<div className={`${styles.input} clouds`} />
|
||||
<div className={`${styles.button} clouds`} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,20 @@
|
|||
.reply {
|
||||
max-width: 600px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.skeleton .input {
|
||||
background-color: grey;
|
||||
width: 100%;
|
||||
border-radius: .4rem;
|
||||
height: 115px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.skeleton .button {
|
||||
background-color: grey;
|
||||
border-radius: .4rem;
|
||||
margin-top: .25rem;
|
||||
width: 71px;
|
||||
height: 38px;
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
import Layout from '../../components/layout'
|
||||
import Comments from '../../components/comments'
|
||||
import { CommentsQuery } from '../../components/comments'
|
||||
import { COMMENT_FIELDS } from '../../fragments/comments'
|
||||
import { gql } from '@apollo/client'
|
||||
import ApolloClient from '../../api/client'
|
||||
import UserHeader from '../../components/user-header'
|
||||
|
||||
export async function getServerSideProps ({ params }) {
|
||||
const { error, data: { user } } = await ApolloClient.query({
|
||||
export async function getServerSideProps ({ req, params }) {
|
||||
const { error, data: { user } } = await (await ApolloClient(req)).query({
|
||||
query:
|
||||
gql`{
|
||||
user(name: "${params.username}") {
|
||||
|
@ -46,7 +46,7 @@ export default function User ({ user }) {
|
|||
return (
|
||||
<Layout>
|
||||
<UserHeader user={user} />
|
||||
<Comments query={query} includeParent noReply />
|
||||
<CommentsQuery query={query} includeParent noReply />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,64 +1,72 @@
|
|||
import Item from '../../components/item'
|
||||
import Item, { ItemSkeleton } from '../../components/item'
|
||||
import Layout from '../../components/layout'
|
||||
import ApolloClient from '../../api/client'
|
||||
import Reply from '../../components/reply'
|
||||
import Reply, { ReplySkeleton } from '../../components/reply'
|
||||
import Comment from '../../components/comment'
|
||||
import Text from '../../components/text'
|
||||
import Comments from '../../components/comments'
|
||||
import Comments, { CommentsSkeleton } from '../../components/comments'
|
||||
import { COMMENTS } from '../../fragments/comments'
|
||||
import { ITEM_FIELDS } from '../../fragments/items'
|
||||
import { gql } from '@apollo/client'
|
||||
|
||||
export async function getServerSideProps ({ req, params }) {
|
||||
const { error, data: { item } } = await (await ApolloClient(req)).query({
|
||||
query:
|
||||
gql`
|
||||
${ITEM_FIELDS}
|
||||
{
|
||||
item(id: ${params.id}) {
|
||||
...ItemFields
|
||||
text
|
||||
}
|
||||
}`
|
||||
})
|
||||
|
||||
if (!item || error) {
|
||||
return {
|
||||
notFound: true
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
item: item
|
||||
}
|
||||
}
|
||||
}
|
||||
import { gql, useQuery } from '@apollo/client'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function FullItem ({ item }) {
|
||||
const commentsQuery = gql`
|
||||
const router = useRouter()
|
||||
const { id } = router.query
|
||||
|
||||
const query = gql`
|
||||
${ITEM_FIELDS}
|
||||
${COMMENTS}
|
||||
{
|
||||
comments(parentId: ${item.id}) {
|
||||
...CommentsRecursive
|
||||
}
|
||||
item(id: ${id}) {
|
||||
...ItemFields
|
||||
text
|
||||
comments {
|
||||
...CommentsRecursive
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<LoadItem query={query} />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
function LoadItem ({ query }) {
|
||||
const { loading, error, data } = useQuery(query)
|
||||
if (error) return <div>Failed to load!</div>
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div>
|
||||
<ItemSkeleton>
|
||||
<ReplySkeleton />
|
||||
</ItemSkeleton>
|
||||
<div className='mt-5'>
|
||||
<CommentsSkeleton />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const { item } = data
|
||||
|
||||
return (
|
||||
<>
|
||||
{item.parentId
|
||||
? <Comment item={item} replyOpen includeParent cacheId='ROOT_QUERY' />
|
||||
? <Comment item={item} replyOpen includeParent noComments />
|
||||
: (
|
||||
<>
|
||||
<Item item={item}>
|
||||
{item.text && <Text>{item.text}</Text>}
|
||||
<Reply parentId={item.id} cacheId='ROOT_QUERY' />
|
||||
<Reply parentId={item.id} />
|
||||
</Item>
|
||||
</>
|
||||
)}
|
||||
<div className='mt-5'>
|
||||
<Comments query={commentsQuery} />
|
||||
<Comments comments={item.comments} />
|
||||
</div>
|
||||
</Layout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -82,12 +82,12 @@ $container-max-widths: (
|
|||
}
|
||||
|
||||
@keyframes flash {
|
||||
from { filter: brightness(1); background-position: 0 0;}
|
||||
from { filter: brightness(1);}
|
||||
2% { filter: brightness(2.3); }
|
||||
4% { filter: brightness(1.4); }
|
||||
8% { filter: brightness(3); }
|
||||
16% { filter: brightness(1); }
|
||||
to { filter: brightness(1); background-position: 250px 0;}
|
||||
to { filter: brightness(1);}
|
||||
}
|
||||
|
||||
.clouds {
|
||||
|
|
Loading…
Reference in New Issue