mostly clientside render

This commit is contained in:
keyan 2021-04-26 19:55:48 -05:00
parent c626998952
commit c82c82bb7b
10 changed files with 119 additions and 79 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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} />
))

View File

@ -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} />
}

View File

@ -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>
)}
</>
)
}

View File

@ -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>
)
}

View File

@ -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;
}

View File

@ -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>
)
}

View File

@ -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>
</>
)
}

View File

@ -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 {