This commit is contained in:
2026-06-24 15:34:09 +02:00
commit 65fb6816ca
442 changed files with 27246 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
'use client'
import { DeletePostDocument, DownvoteDocument, MeDocument, PostDocument, Post as PostType, RemoveDownvoteDocument, RemoveUpvoteDocument, UpvoteDocument } from '@/generated/graphql/graphql'
import { useMutation, useQuery } from '@apollo/client/react'
import { ArrowDownIcon, ArrowUpIcon, DeleteIcon, EditIcon } from '@chakra-ui/icons'
import { Box, Flex, Heading, IconButton, Text } from '@chakra-ui/react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
interface Props {
post: PostType
}
export const Post: React.FC<Props> = ({ post: p }) => {
const { data } = useQuery(MeDocument)
const router = useRouter()
const { refetch } = useQuery(PostDocument, { returnPartialData: false, variables: { id: p.id } })
const [upvote, { loading: upvoting }] = useMutation(UpvoteDocument)
const [downvote, { loading: downvoting }] = useMutation(DownvoteDocument)
const [removeUpvote, { loading: removingUpvote }] = useMutation(RemoveUpvoteDocument)
const [removeDownvote, { loading: removingDownvote }] = useMutation(RemoveDownvoteDocument)
const [deletePost, { loading: deletingPost }] = useMutation(DeletePostDocument)
return (
<Flex key={p.id} p={5} borderWidth='1px'>
<Flex flexDir='column' mr='4' justifyContent='space-between' alignItems='center'>
<IconButton
aria-label='upvote-button'
icon={<ArrowUpIcon />}
color={p.upvoted ? 'green' : ''}
isLoading={upvoting || removingUpvote}
onClick={async () => {
if (!data?.me) {
router.push('/login')
}
if (p.upvoted) {
await removeUpvote({ variables: { postID: p.id } })
// Apollo Client automatically refetches one single post and merge it with the cache of previous posts and updating the result of useQuery(PostsDocument), so we don't need to refetch every post.
await refetch()
}
else {
await upvote({ variables: { postID: p.id } })
await refetch()
}
}}
/>
<Text marginY='2'>{p.points}</Text>
<IconButton
aria-label='downvote-button'
icon={<ArrowDownIcon />}
color={p.downvoted ? 'red' : ''}
isLoading={downvoting || removingDownvote}
onClick={async () => {
if (!data?.me) {
router.push('/login')
}
if (p.downvoted) {
await removeDownvote({ variables: { postID: p.id } })
await refetch()
}
else {
await downvote({ variables: { postID: p.id } })
await refetch()
}
}}
/>
</Flex>
<Box>
<Link href={`/post/${p.id}`}>
<Heading as='h3' size='md'>{p.title}</Heading>
</Link>
<Text>Posted by {p.author.username}</Text>
<Text mt={4}>{p.snippet}</Text>
</Box>
{
p.authorID == data?.me?.id &&
<Flex flexDir='column' ml='auto' justifyContent='space-between' alignItems='center'>
<Link href={`/edit-post/${p.id}`}>
<IconButton
aria-label='edit-button'
icon={<EditIcon />}
/>
</Link>
<IconButton
aria-label='delete-button'
icon={<DeleteIcon />}
colorScheme='red'
isLoading={deletingPost}
onClick={async () => {
await deletePost({
variables: { id: p.id },
// https://stackoverflow.com/questions/63192774/apollo-client-delete-item-from-cache
// https://www.apollographql.com/docs/react/caching/garbage-collection/#cacheevict
update: cache => {
const normalizedId = cache.identify({ id: p.id, __typename: 'Post' })
cache.evict({ id: normalizedId })
cache.gc()
}
})
}}
/>
</Flex>
}
</Flex>
)
}