---
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
node_modules
|
||||
npm-debug.log
|
||||
README.md
|
||||
.env
|
||||
.next
|
||||
.git
|
||||
@@ -0,0 +1,2 @@
|
||||
PORT=
|
||||
NEXT_PUBLIC_BACKEND_URI=
|
||||
@@ -0,0 +1,37 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM node:24.4.1-alpine3.22
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm ci
|
||||
RUN npx next telemetry disable
|
||||
RUN npm run build
|
||||
RUN adduser -D appuser && chown -R appuser /app
|
||||
USER appuser
|
||||
CMD npm run start
|
||||
@@ -0,0 +1,14 @@
|
||||
'use client'
|
||||
import { apollo } from '@/lib'
|
||||
import { ApolloProvider } from '@apollo/client/react'
|
||||
import { ChakraProvider } from '@chakra-ui/react'
|
||||
|
||||
export const Providers = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<ApolloProvider client={apollo}>
|
||||
<ChakraProvider>
|
||||
{children}
|
||||
</ChakraProvider>
|
||||
</ApolloProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
# Frontend for LitReddit 🔥
|
||||
@@ -0,0 +1,64 @@
|
||||
'use client'
|
||||
import { LogoutDocument, MeDocument, PostsDocument } from '@/generated/graphql/graphql'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Link } from '@chakra-ui/next-js'
|
||||
import { Box, Button, Flex, Text } from '@chakra-ui/react'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
|
||||
const NavBar: React.FC = () => {
|
||||
const { data, loading, refetch } = useQuery(MeDocument)
|
||||
const { refetch: refetchPosts } = useQuery(PostsDocument)
|
||||
const [logout] = useMutation(LogoutDocument)
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
|
||||
return (
|
||||
<Flex bgColor='tan' paddingY={4} paddingX={6} ml='auto' minH='72px' alignItems='center'>
|
||||
<Box mr='auto'>
|
||||
<Link href='/'>
|
||||
<Button>Home</Button>
|
||||
</Link>
|
||||
</Box>
|
||||
<Box ml='auto'>
|
||||
{
|
||||
loading &&
|
||||
<Text>Loading...</Text>
|
||||
}
|
||||
{
|
||||
!loading && !data?.me &&
|
||||
<>
|
||||
<Link href='/login' mr={4}>
|
||||
<Button>Login</Button>
|
||||
</Link>
|
||||
<Link href='/register' mr={4}>
|
||||
<Button>Register</Button>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
{
|
||||
data?.me &&
|
||||
<Flex alignItems='center'>
|
||||
<Text mr={4}>Logged in as {data.me.username}!</Text>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await logout()
|
||||
await refetch() // Calling refetch will also refetch the data for any other components using useQuery(MeDocument)
|
||||
await refetchPosts()
|
||||
if (pathname == '/') {
|
||||
router.refresh()
|
||||
}
|
||||
else {
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
}}
|
||||
>
|
||||
Log out
|
||||
</Button>
|
||||
</Flex>
|
||||
}
|
||||
</Box>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
export default NavBar
|
||||
@@ -0,0 +1,49 @@
|
||||
'use client'
|
||||
import { InputField, TextareaField, Wrapper } from '@/components'
|
||||
import { CreatePostDocument, PostInput, PostsDocument } from '@/generated/graphql/graphql'
|
||||
import { useAuthenticate } from '@/hooks'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Box, Button, Flex } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
|
||||
const CreatePostPage: React.FC = () => {
|
||||
useAuthenticate()
|
||||
const router = useRouter()
|
||||
const [createPost] = useMutation(CreatePostDocument)
|
||||
const { refetch } = useQuery(PostsDocument)
|
||||
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ title: '', content: '' } as PostInput}
|
||||
onSubmit={async (values, { setErrors }) => {
|
||||
const response = await createPost({ variables: { input: values } })
|
||||
const errors = response.data?.createPost.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.createPost.post) {
|
||||
refetch()
|
||||
router.push(`/post/${response.data.createPost.post.id}`)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<Flex flexDir='column' justifyContent='center'>
|
||||
<InputField name='title' label='Title' placeholder='title' />
|
||||
<Box mt={4}>
|
||||
<TextareaField name='content' label='Content' placeholder='content' />
|
||||
</Box>
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting} alignSelf='center'>Create</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
export default CreatePostPage
|
||||
@@ -0,0 +1,65 @@
|
||||
'use client'
|
||||
import { FormSuccessMessage, InputField, TextareaField, Wrapper } from '@/components'
|
||||
import { PostDocument, PostInput, UpdatePostDocument } from '@/generated/graphql/graphql'
|
||||
import { useAuthenticate } from '@/hooks'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Box, Button, Flex, Text } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { use, useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
params: Promise<{
|
||||
id: string
|
||||
}>
|
||||
}
|
||||
|
||||
|
||||
const EditPostPage: React.FC<Props> = ({ params }) => {
|
||||
const { id } = use(params)
|
||||
useAuthenticate()
|
||||
const { data, loading, refetch } = useQuery(PostDocument, { variables: { id } })
|
||||
const [updatePost] = useMutation(UpdatePostDocument)
|
||||
const [showSuccessMessage, setShowSuccessMessage] = useState(false)
|
||||
|
||||
if (loading) {
|
||||
return <Text>Loading...</Text>
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ title: data?.post?.title || '', content: data?.post?.content || '' } as PostInput}
|
||||
onSubmit={async ({ title, content }, { setErrors }) => {
|
||||
const response = await updatePost({ variables: { id, title: title as string, content } })
|
||||
const errors = response.data?.updatePost.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.updatePost.post) {
|
||||
refetch()
|
||||
setShowSuccessMessage(true)
|
||||
setTimeout(() => {
|
||||
setShowSuccessMessage(false)
|
||||
}, 10000)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<Flex flexDir='column' justifyContent='center'>
|
||||
<InputField name='title' label='Title' placeholder='title' />
|
||||
<Box mt={4}>
|
||||
<TextareaField name='content' label='Content' placeholder='content' />
|
||||
</Box>
|
||||
{showSuccessMessage && <FormSuccessMessage message='Post successfully updated!' />}
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting} alignSelf='center'>Update</Button>
|
||||
</Flex>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditPostPage
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,52 @@
|
||||
'use client'
|
||||
import { FormErrorMessage, FormSuccessMessage, InputField, Wrapper } from '@/components'
|
||||
import { ForgotPasswordDocument } from '@/generated/graphql/graphql'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation } from '@apollo/client/react'
|
||||
import { Button } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { useState } from 'react'
|
||||
|
||||
const ForgotPasswordPage: React.FC = () => {
|
||||
const [forgotPassword] = useMutation(ForgotPasswordDocument)
|
||||
const [message, setMessage] = useState('')
|
||||
const [messageType, setMessageType] = useState<'success' | 'error' | ''>('')
|
||||
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ email: '' }}
|
||||
onSubmit={async ({ email }, { setErrors }) => {
|
||||
setMessage('')
|
||||
setMessageType('')
|
||||
const response = await forgotPassword({ variables: { email } })
|
||||
const errors = response.data?.forgotPassword.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.forgotPassword.message) {
|
||||
setMessage(response.data.forgotPassword.message)
|
||||
setMessageType(response.data.forgotPassword.messageType as any)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<InputField name='email' label="Enter your account's email to reset your password:" placeholder='email' />
|
||||
{
|
||||
(message && messageType == 'success') &&
|
||||
<FormSuccessMessage message={message}/>
|
||||
}
|
||||
{
|
||||
(message && messageType == 'error') &&
|
||||
<FormErrorMessage message={message}/>
|
||||
}
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting}>Submit</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
export default ForgotPasswordPage
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Providers } from '@/Providers'
|
||||
import { Flex } from '@chakra-ui/react'
|
||||
import type { Metadata } from 'next'
|
||||
import './globals.css'
|
||||
import NavBar from './NavBar'
|
||||
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'LitReddit 🔥'
|
||||
}
|
||||
|
||||
const RootLayout = ({ children, }: Readonly<{ children: React.ReactNode }>) => {
|
||||
return (
|
||||
<html lang='en'>
|
||||
<body>
|
||||
<Providers>
|
||||
<NavBar />
|
||||
<Flex justifyContent='center' width='100%' padding={4} minH='calc(100vh - 72px)'>
|
||||
{children}
|
||||
</Flex>
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
export default RootLayout
|
||||
@@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
import { InputField, Wrapper } from '@/components'
|
||||
import { LoginDocument, MeDocument, PostsDocument } from '@/generated/graphql/graphql'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Link } from '@chakra-ui/next-js'
|
||||
import { Box, Button } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { Suspense } from 'react'
|
||||
|
||||
|
||||
const Page: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const { refetch } = useQuery(MeDocument)
|
||||
const { refetch: refetchPosts } = useQuery(PostsDocument)
|
||||
const [login] = useMutation(LoginDocument)
|
||||
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ username: '', password: '' }}
|
||||
onSubmit={async (values, { setErrors }) => {
|
||||
const response = await login({ variables: { input: values } })
|
||||
const errors = response.data?.login.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.login.user) {
|
||||
// Successful login
|
||||
await refetch() // Refetch client-side
|
||||
await refetchPosts()
|
||||
const destination = searchParams.get('redirect')
|
||||
if (destination) {
|
||||
router.push(destination)
|
||||
}
|
||||
else {
|
||||
router.push('/')
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<InputField name='username' label='Username' placeholder='username' />
|
||||
<Box mt={4}>
|
||||
<InputField name='password' label='Password' placeholder='password' type='password' />
|
||||
</Box>
|
||||
<Box mt={4}>
|
||||
<Link href='/forgot-password'>Forgot password?</Link>
|
||||
</Box>
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting}>Login</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const LoginPage = () => {
|
||||
return (
|
||||
<Suspense>
|
||||
<Page />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginPage
|
||||
@@ -0,0 +1,58 @@
|
||||
'use client'
|
||||
import { Post, Wrapper } from '@/components'
|
||||
import { PostsDocument } from '@/generated/graphql/graphql'
|
||||
import { useQuery } from '@apollo/client/react'
|
||||
import { Link } from '@chakra-ui/next-js'
|
||||
import { Box, Button, Flex, Heading, Stack, Text } from '@chakra-ui/react'
|
||||
import { useState } from 'react'
|
||||
|
||||
|
||||
const Home = (): React.ReactNode => {
|
||||
// https://www.apollographql.com/docs/react/pagination/core-api/
|
||||
const { data, loading, fetchMore } = useQuery(PostsDocument)
|
||||
const [doesntHaveMore, setDoesntHaveMore] = useState(false)
|
||||
|
||||
return (
|
||||
<Box w='100%'>
|
||||
<Wrapper>
|
||||
<Flex w='100%'>
|
||||
<Heading as='h3' size='lg'>LitReddit 🔥</Heading>
|
||||
<Link href='/create-post' ml='auto'>
|
||||
<Button>Create Post</Button>
|
||||
</Link>
|
||||
</Flex>
|
||||
<Flex flexDir='column' alignItems='center'>
|
||||
{
|
||||
loading && !data?.posts &&
|
||||
<Text>Loading...</Text>
|
||||
}
|
||||
<Stack spacing={4} mt={8} w='100%'>
|
||||
{
|
||||
data?.posts.map((p, idx) => <Post post={p} key={idx} />)
|
||||
}
|
||||
</Stack>
|
||||
|
||||
<Flex w='100%' mt={4}>
|
||||
{
|
||||
(data?.posts?.length && !doesntHaveMore) ?
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const result = await fetchMore({ variables: { cursor: data.posts[data.posts.length - 1].createdAt } })
|
||||
if (result.data?.posts.length == 0) {
|
||||
setDoesntHaveMore(true)
|
||||
}
|
||||
}}
|
||||
m='auto'
|
||||
>
|
||||
More
|
||||
</Button>
|
||||
: <></>
|
||||
}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Wrapper>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
||||
@@ -0,0 +1,79 @@
|
||||
'use client'
|
||||
import { DeletePostDocument, PostQuery } from '@/generated/graphql/graphql'
|
||||
import { useMutation } from '@apollo/client/react'
|
||||
import { DeleteIcon, EditIcon } from '@chakra-ui/icons'
|
||||
import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button, Flex, IconButton, useDisclosure } from '@chakra-ui/react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useRef } from 'react'
|
||||
|
||||
interface Props {
|
||||
data: PostQuery
|
||||
}
|
||||
|
||||
export const ClientSection: React.FC<Props> = ({ data }) => {
|
||||
const router = useRouter()
|
||||
const { isOpen, onOpen, onClose } = useDisclosure()
|
||||
const cancelRef: any = useRef(null)
|
||||
const [deletePost] = useMutation(DeletePostDocument)
|
||||
|
||||
return (
|
||||
<Flex mr='auto' alignItems='center' mt={4}>
|
||||
<Link href={`/edit-post/${data?.post?.id}`}>
|
||||
<IconButton
|
||||
aria-label='edit-button'
|
||||
icon={<EditIcon />}
|
||||
mr={4}
|
||||
/>
|
||||
</Link>
|
||||
<IconButton
|
||||
aria-label='delete-button'
|
||||
icon={<DeleteIcon />}
|
||||
colorScheme='red'
|
||||
onClick={onOpen}
|
||||
/>
|
||||
<AlertDialog
|
||||
isOpen={isOpen}
|
||||
leastDestructiveRef={cancelRef}
|
||||
onClose={onClose}
|
||||
>
|
||||
<AlertDialogOverlay>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader fontSize='lg' fontWeight='bold'>
|
||||
Delete Post
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>
|
||||
Are you sure? You can't undo this action afterwards.
|
||||
</AlertDialogBody>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<Button ref={cancelRef} onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
colorScheme='red'
|
||||
onClick={async () => {
|
||||
await deletePost({
|
||||
variables: { id: data.post?.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: data.post?.id!, __typename: 'Post' })
|
||||
cache.evict({ id: normalizedId })
|
||||
cache.gc()
|
||||
}
|
||||
})
|
||||
router.refresh()
|
||||
}}
|
||||
ml={3}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialogOverlay>
|
||||
</AlertDialog>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Text } from '@chakra-ui/react'
|
||||
|
||||
const Loading: React.FC = () => {
|
||||
return (
|
||||
<Text>Loading...</Text>
|
||||
)
|
||||
}
|
||||
export default Loading
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Wrapper } from '@/components'
|
||||
import { SESSION_COOKIE_NAME } from '@/constants'
|
||||
import { MeDocument, PostDocument } from '@/generated/graphql/graphql'
|
||||
import { createApolloClient } from '@/lib'
|
||||
import { Heading, Text } from '@chakra-ui/react'
|
||||
import { cookies } from 'next/headers'
|
||||
import { ClientSection } from './ClientSection'
|
||||
|
||||
interface Props {
|
||||
params: Promise<{
|
||||
id: string
|
||||
}>
|
||||
}
|
||||
|
||||
const PostPage: React.FC<Props> = async ({ params }) => {
|
||||
const { id } = await params
|
||||
const cookieStore = await cookies()
|
||||
const cookie = cookieStore.get(SESSION_COOKIE_NAME)?.value
|
||||
const apollo = await createApolloClient(cookie)
|
||||
const { data } = await apollo.query({ query: PostDocument, variables: { id } })
|
||||
const { data: meData } = await apollo.query({ query: MeDocument })
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{
|
||||
data?.post ?
|
||||
<>
|
||||
<Heading as='h3' size='md'>{data.post.title}</Heading>
|
||||
<Text>Posted by {data.post.author.username}</Text>
|
||||
<Text mt={4}>{data.post.content}</Text>
|
||||
{
|
||||
data?.post?.authorID == meData?.me?.id &&
|
||||
<ClientSection data={data} />
|
||||
}
|
||||
</>
|
||||
:
|
||||
<>Post not found!</>
|
||||
}
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
export default PostPage
|
||||
@@ -0,0 +1,48 @@
|
||||
'use client'
|
||||
import { InputField, Wrapper } from '@/components'
|
||||
import { MeDocument, RegisterDocument } from '@/generated/graphql/graphql'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Box, Button } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
|
||||
const RegisterPage: React.FC = () => {
|
||||
const router = useRouter()
|
||||
const { refetch } = useQuery(MeDocument)
|
||||
const [register] = useMutation(RegisterDocument)
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ username: '', password: '' }}
|
||||
onSubmit={async (values, { setErrors }) => {
|
||||
const response = await register({ variables: { input: values } })
|
||||
const errors = response.data?.register.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.register.user) {
|
||||
// Successful register
|
||||
await refetch()
|
||||
router.push('/')
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<InputField name='email' label='Email' placeholder='email' />
|
||||
<Box mt={4}>
|
||||
<InputField name='username' label='Username' placeholder='username' />
|
||||
</Box>
|
||||
<Box mt={4}>
|
||||
<InputField name='password' label='Password' placeholder='password' type='password' />
|
||||
</Box>
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting}>Register</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
export default RegisterPage
|
||||
@@ -0,0 +1,36 @@
|
||||
import { PasswordResetForm } from '@/components'
|
||||
import { SESSION_COOKIE_NAME } from '@/constants'
|
||||
import { CheckResetPasswordTokenDocument } from '@/generated/graphql/graphql'
|
||||
import { createApolloClient } from '@/lib'
|
||||
import { Text } from '@chakra-ui/react'
|
||||
import { cookies } from 'next/headers'
|
||||
|
||||
interface Props {
|
||||
params: Promise<{
|
||||
token: string
|
||||
}>
|
||||
}
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const ResetPasswordPage: React.FC<Props> = async ({ params }) => {
|
||||
const { token } = await params
|
||||
const cookieStore = await cookies()
|
||||
const cookie = cookieStore.get(SESSION_COOKIE_NAME)?.value
|
||||
const apollo = await createApolloClient(cookie)
|
||||
const { data, error } = await apollo.query({ query: CheckResetPasswordTokenDocument, variables: { token } })
|
||||
|
||||
if (error || data === undefined) {
|
||||
console.log(error)
|
||||
return <Text>An error has occured. Please try again later.</Text>
|
||||
}
|
||||
|
||||
else if (!data.checkResetPasswordToken) {
|
||||
return <Text>Invalid token!</Text>
|
||||
}
|
||||
|
||||
else {
|
||||
return <PasswordResetForm token={token}/>
|
||||
}
|
||||
}
|
||||
export default ResetPasswordPage
|
||||
@@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
import { CloseIcon } from '@chakra-ui/icons'
|
||||
import { Flex, Text } from '@chakra-ui/react'
|
||||
|
||||
interface Props {
|
||||
message: string
|
||||
}
|
||||
|
||||
export const FormErrorMessage: React.FC<Props> = (props) => {
|
||||
const { message } = props
|
||||
return (
|
||||
<Flex alignItems='center' color='red' mt={4} fontSize='0.875rem' >
|
||||
<CloseIcon color='red' mr={2.5} fontSize='0.725rem'/>
|
||||
<Text color='red'>{message}</Text>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
'use client'
|
||||
import { CheckIcon } from '@chakra-ui/icons'
|
||||
import { Flex, Text } from '@chakra-ui/react'
|
||||
|
||||
interface Props {
|
||||
message: string
|
||||
}
|
||||
|
||||
export const FormSuccessMessage: React.FC<Props> = (props) => {
|
||||
const { message } = props
|
||||
return (
|
||||
<Flex alignItems='center' color='green-500' mt={4} fontSize='0.875rem'>
|
||||
<CheckIcon color='green.700' fontSize='0.875rem' mr={2} />
|
||||
<Text color='green'>{message}</Text>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
'use client'
|
||||
import { FormControl, FormErrorMessage, FormLabel, Input } from '@chakra-ui/react'
|
||||
import { useField } from 'formik'
|
||||
|
||||
type Props = React.InputHTMLAttributes<HTMLInputElement> & { name: string, label: string, isTextArea?: boolean }
|
||||
|
||||
export const InputField: React.FC<Props> = ({size: _, isTextArea=false, ...props}) => {
|
||||
const [field, { error }] = useField(props)
|
||||
const { label, placeholder } = props
|
||||
|
||||
return (
|
||||
<FormControl isInvalid={!!error}>
|
||||
<FormLabel htmlFor={field.name}>{label}</FormLabel>
|
||||
<Input {...field} {...props} id={field.name} placeholder={placeholder} />
|
||||
{error ? <FormErrorMessage>{error}</FormErrorMessage> : null}
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
'use client'
|
||||
import { FormErrorMessage, FormSuccessMessage, InputField, Wrapper } from '@/components'
|
||||
import { MeDocument, ResetPasswordDocument } from '@/generated/graphql/graphql'
|
||||
import { errorMapper } from '@/utils'
|
||||
import { useMutation, useQuery } from '@apollo/client/react'
|
||||
import { Button } from '@chakra-ui/react'
|
||||
import { Form, Formik } from 'formik'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
token: string
|
||||
}
|
||||
|
||||
export const PasswordResetForm: React.FC<Props> = ({ token }) => {
|
||||
const router = useRouter()
|
||||
const [resetPassword] = useMutation(ResetPasswordDocument)
|
||||
const { refetch } = useQuery(MeDocument)
|
||||
const [message, setMessage] = useState('')
|
||||
const [messageType, setMessageType] = useState<'success' | 'error' | ''>('')
|
||||
|
||||
return (
|
||||
<Wrapper variant='small'>
|
||||
<Formik
|
||||
initialValues={{ newPassword: '' }}
|
||||
onSubmit={async ({ newPassword }, { setErrors }) => {
|
||||
const response = await resetPassword({ variables: { newPassword, token } })
|
||||
const errors = response.data?.resetPassword.errors
|
||||
if (errors) {
|
||||
setErrors(errorMapper(errors))
|
||||
}
|
||||
else if (response.data?.resetPassword.message) {
|
||||
setMessage(response.data.resetPassword.message)
|
||||
setMessageType(response.data.resetPassword.messageType as any)
|
||||
if (response.data.resetPassword.messageType == 'success') {
|
||||
await refetch()
|
||||
setTimeout(() => { router.push('/login') }, 1500)
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{({ isSubmitting }) => (
|
||||
<Form>
|
||||
<InputField name='newPassword' label='Enter your new password:' placeholder='password' type='password' />
|
||||
{
|
||||
(message && messageType == 'success') &&
|
||||
<FormSuccessMessage message={message}/>
|
||||
}
|
||||
{
|
||||
(message && messageType == 'error') &&
|
||||
<FormErrorMessage message={message}/>
|
||||
}
|
||||
<Button type='submit' colorScheme='teal' mt={4} isLoading={isSubmitting}>Submit</Button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
'use client'
|
||||
import { Button, PropsOf } from '@chakra-ui/react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
export const RefetchButton: React.FC<PropsOf<typeof Button>> = (props) => {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<Button onClick={() => { router.refresh() }} {...props}>Refetch</Button>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
'use client'
|
||||
import { FormControl, FormErrorMessage, FormLabel, Textarea } from '@chakra-ui/react'
|
||||
import autosize from 'autosize'
|
||||
import { useField } from 'formik'
|
||||
import { useRef, useEffect } from 'react'
|
||||
|
||||
type Props = React.TextareaHTMLAttributes<HTMLTextAreaElement> & { name: string, label: string }
|
||||
|
||||
export const TextareaField: React.FC<Props> = (props) => {
|
||||
const [field, { error }] = useField(props)
|
||||
const { label, placeholder } = props
|
||||
|
||||
// https://github.com/chakra-ui/chakra-ui/issues/670
|
||||
const ref: any = useRef(null)
|
||||
useEffect(() => {
|
||||
const current = ref.current
|
||||
autosize(current)
|
||||
return () => {
|
||||
autosize.destroy(current)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<FormControl isInvalid={!!error}>
|
||||
<FormLabel htmlFor={field.name}>{label}</FormLabel>
|
||||
<Textarea
|
||||
{...field}
|
||||
{...props}
|
||||
ref={ref}
|
||||
id={field.name}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
{error ? <FormErrorMessage>{error}</FormErrorMessage> : null}
|
||||
</FormControl>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Box } from '@chakra-ui/react'
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode
|
||||
variant?: 'small' | 'regular'
|
||||
}
|
||||
|
||||
export const Wrapper: React.FC<Props> = ({ children, variant = 'regular' }) => {
|
||||
return (
|
||||
<Box w='100%' maxW={variant == 'small' ? 400 : 800} mt={8} mx='auto'>
|
||||
{children}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export * from './Wrapper'
|
||||
export * from './InputField'
|
||||
export * from './PasswordResetForm'
|
||||
export * from './TextareaField'
|
||||
export * from './RefetchButton'
|
||||
export * from './Post'
|
||||
export * from './FormSuccessMessage'
|
||||
export * from './FormErrorMessage'
|
||||
@@ -0,0 +1,2 @@
|
||||
export const __prod__ = process.env.NODE_ENV ==='production'
|
||||
export const SESSION_COOKIE_NAME = 'qid'
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NEXT_PUBLIC_BACKEND_URI: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
@@ -0,0 +1,87 @@
|
||||
/* eslint-disable */
|
||||
import { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
|
||||
import { FragmentDefinitionNode } from 'graphql';
|
||||
import { Incremental } from './graphql';
|
||||
|
||||
|
||||
export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
|
||||
infer TType,
|
||||
any
|
||||
>
|
||||
? [TType] extends [{ ' $fragmentName'?: infer TKey }]
|
||||
? TKey extends string
|
||||
? { ' $fragmentRefs'?: { [key in TKey]: TType } }
|
||||
: never
|
||||
: never
|
||||
: never;
|
||||
|
||||
// return non-nullable if `fragmentType` is non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
|
||||
): TType;
|
||||
// return nullable if `fragmentType` is undefined
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined
|
||||
): TType | undefined;
|
||||
// return nullable if `fragmentType` is nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null
|
||||
): TType | null;
|
||||
// return nullable if `fragmentType` is nullable or undefined
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
|
||||
): TType | null | undefined;
|
||||
// return array of non-nullable if `fragmentType` is array of non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>
|
||||
): Array<TType>;
|
||||
// return array of nullable if `fragmentType` is array of nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||
): Array<TType> | null | undefined;
|
||||
// return readonly array of non-nullable if `fragmentType` is array of non-nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
|
||||
): ReadonlyArray<TType>;
|
||||
// return readonly array of nullable if `fragmentType` is array of nullable
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||
): ReadonlyArray<TType> | null | undefined;
|
||||
export function useFragment<TType>(
|
||||
_documentNode: DocumentTypeDecoration<TType, any>,
|
||||
fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | Array<FragmentType<DocumentTypeDecoration<TType, any>>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
|
||||
): TType | Array<TType> | ReadonlyArray<TType> | null | undefined {
|
||||
return fragmentType as any;
|
||||
}
|
||||
|
||||
|
||||
export function makeFragmentData<
|
||||
F extends DocumentTypeDecoration<any, any>,
|
||||
FT extends ResultOf<F>
|
||||
>(data: FT, _fragment: F): FragmentType<F> {
|
||||
return data as FragmentType<F>;
|
||||
}
|
||||
export function isFragmentReady<TQuery, TFrag>(
|
||||
queryNode: DocumentTypeDecoration<TQuery, any>,
|
||||
fragmentNode: TypedDocumentNode<TFrag>,
|
||||
data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
|
||||
): data is FragmentType<typeof fragmentNode> {
|
||||
const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
|
||||
?.deferredFields;
|
||||
|
||||
if (!deferredFields) return true;
|
||||
|
||||
const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
|
||||
const fragName = fragDef?.name?.value;
|
||||
|
||||
const fields = (fragName && deferredFields[fragName]) || [];
|
||||
return fields.length > 0 && fields.every(field => data && field in data);
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/* eslint-disable */
|
||||
import * as types from './graphql';
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
|
||||
/**
|
||||
* Map of all GraphQL operations in the project.
|
||||
*
|
||||
* This map has several performance disadvantages:
|
||||
* 1. It is not tree-shakeable, so it will include all operations in the project.
|
||||
* 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
|
||||
* 3. It does not support dead code elimination, so it will add unused operations.
|
||||
*
|
||||
* Therefore it is highly recommended to use the babel or swc plugin for production.
|
||||
*/
|
||||
const documents = {
|
||||
"fragment RegularError on FieldError {\n field\n message\n}": types.RegularErrorFragmentDoc,
|
||||
"fragment RegularPost on Post {\n id\n authorID\n title\n content\n createdAt\n updatedAt\n snippet\n points\n upvoted\n downvoted\n author {\n ...RegularUser\n }\n}": types.RegularPostFragmentDoc,
|
||||
"fragment RegularPostResponse on PostResponse {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n}": types.RegularPostResponseFragmentDoc,
|
||||
"fragment RegularUser on User {\n id\n email\n username\n createdAt\n updatedAt\n}": types.RegularUserFragmentDoc,
|
||||
"fragment RegularUserResponse on UserResponse {\n errors {\n ...RegularError\n }\n user {\n ...RegularUser\n }\n}": types.RegularUserResponseFragmentDoc,
|
||||
"mutation CreatePost($input: PostInput!) {\n createPost(input: $input) {\n ...RegularPostResponse\n }\n}": types.CreatePostDocument,
|
||||
"mutation DeletePost($id: String!) {\n deletePost(id: $id)\n}": types.DeletePostDocument,
|
||||
"mutation Downvote($postID: String!) {\n downvote(postID: $postID) {\n ...RegularPost\n }\n}": types.DownvoteDocument,
|
||||
"mutation ForgotPassword($email: String!) {\n forgotPassword(email: $email) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}": types.ForgotPasswordDocument,
|
||||
"mutation Login($input: UsernamePasswordInput!) {\n login(input: $input) {\n ...RegularUserResponse\n }\n}": types.LoginDocument,
|
||||
"mutation Logout {\n logout\n}": types.LogoutDocument,
|
||||
"mutation Register($input: UsernamePasswordInput!) {\n register(input: $input) {\n ...RegularUserResponse\n }\n}": types.RegisterDocument,
|
||||
"mutation RemoveDownvote($postID: String!) {\n removeDownvote(postID: $postID) {\n ...RegularPost\n }\n}": types.RemoveDownvoteDocument,
|
||||
"mutation RemoveUpvote($postID: String!) {\n removeUpvote(postID: $postID) {\n ...RegularPost\n }\n}": types.RemoveUpvoteDocument,
|
||||
"mutation ResetPassword($newPassword: String!, $token: String!) {\n resetPassword(newPassword: $newPassword, token: $token) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}": types.ResetPasswordDocument,
|
||||
"mutation UpdatePost($id: String!, $title: String!, $content: String!) {\n updatePost(id: $id, title: $title, content: $content) {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n }\n}": types.UpdatePostDocument,
|
||||
"mutation Upvote($postID: String!) {\n upvote(postID: $postID) {\n ...RegularPost\n }\n}": types.UpvoteDocument,
|
||||
"query CheckResetPasswordToken($token: String!) {\n checkResetPasswordToken(token: $token)\n}": types.CheckResetPasswordTokenDocument,
|
||||
"query Me {\n me {\n ...RegularUser\n }\n}": types.MeDocument,
|
||||
"query Post($id: String!) {\n post(id: $id) {\n ...RegularPost\n }\n}": types.PostDocument,
|
||||
"query Posts($limit: Int, $cursor: Timestamp) {\n posts(limit: $limit, cursor: $cursor) {\n ...RegularPost\n }\n}": types.PostsDocument,
|
||||
};
|
||||
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
|
||||
* ```
|
||||
*
|
||||
* The query argument is unknown!
|
||||
* Please regenerate the types.
|
||||
*/
|
||||
export function graphql(source: string): unknown;
|
||||
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "fragment RegularError on FieldError {\n field\n message\n}"): (typeof documents)["fragment RegularError on FieldError {\n field\n message\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "fragment RegularPost on Post {\n id\n authorID\n title\n content\n createdAt\n updatedAt\n snippet\n points\n upvoted\n downvoted\n author {\n ...RegularUser\n }\n}"): (typeof documents)["fragment RegularPost on Post {\n id\n authorID\n title\n content\n createdAt\n updatedAt\n snippet\n points\n upvoted\n downvoted\n author {\n ...RegularUser\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "fragment RegularPostResponse on PostResponse {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n}"): (typeof documents)["fragment RegularPostResponse on PostResponse {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "fragment RegularUser on User {\n id\n email\n username\n createdAt\n updatedAt\n}"): (typeof documents)["fragment RegularUser on User {\n id\n email\n username\n createdAt\n updatedAt\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "fragment RegularUserResponse on UserResponse {\n errors {\n ...RegularError\n }\n user {\n ...RegularUser\n }\n}"): (typeof documents)["fragment RegularUserResponse on UserResponse {\n errors {\n ...RegularError\n }\n user {\n ...RegularUser\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation CreatePost($input: PostInput!) {\n createPost(input: $input) {\n ...RegularPostResponse\n }\n}"): (typeof documents)["mutation CreatePost($input: PostInput!) {\n createPost(input: $input) {\n ...RegularPostResponse\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation DeletePost($id: String!) {\n deletePost(id: $id)\n}"): (typeof documents)["mutation DeletePost($id: String!) {\n deletePost(id: $id)\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation Downvote($postID: String!) {\n downvote(postID: $postID) {\n ...RegularPost\n }\n}"): (typeof documents)["mutation Downvote($postID: String!) {\n downvote(postID: $postID) {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation ForgotPassword($email: String!) {\n forgotPassword(email: $email) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}"): (typeof documents)["mutation ForgotPassword($email: String!) {\n forgotPassword(email: $email) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation Login($input: UsernamePasswordInput!) {\n login(input: $input) {\n ...RegularUserResponse\n }\n}"): (typeof documents)["mutation Login($input: UsernamePasswordInput!) {\n login(input: $input) {\n ...RegularUserResponse\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation Logout {\n logout\n}"): (typeof documents)["mutation Logout {\n logout\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation Register($input: UsernamePasswordInput!) {\n register(input: $input) {\n ...RegularUserResponse\n }\n}"): (typeof documents)["mutation Register($input: UsernamePasswordInput!) {\n register(input: $input) {\n ...RegularUserResponse\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation RemoveDownvote($postID: String!) {\n removeDownvote(postID: $postID) {\n ...RegularPost\n }\n}"): (typeof documents)["mutation RemoveDownvote($postID: String!) {\n removeDownvote(postID: $postID) {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation RemoveUpvote($postID: String!) {\n removeUpvote(postID: $postID) {\n ...RegularPost\n }\n}"): (typeof documents)["mutation RemoveUpvote($postID: String!) {\n removeUpvote(postID: $postID) {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation ResetPassword($newPassword: String!, $token: String!) {\n resetPassword(newPassword: $newPassword, token: $token) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}"): (typeof documents)["mutation ResetPassword($newPassword: String!, $token: String!) {\n resetPassword(newPassword: $newPassword, token: $token) {\n errors {\n ...RegularError\n }\n message\n messageType\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation UpdatePost($id: String!, $title: String!, $content: String!) {\n updatePost(id: $id, title: $title, content: $content) {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n }\n}"): (typeof documents)["mutation UpdatePost($id: String!, $title: String!, $content: String!) {\n updatePost(id: $id, title: $title, content: $content) {\n errors {\n ...RegularError\n }\n post {\n ...RegularPost\n }\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "mutation Upvote($postID: String!) {\n upvote(postID: $postID) {\n ...RegularPost\n }\n}"): (typeof documents)["mutation Upvote($postID: String!) {\n upvote(postID: $postID) {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "query CheckResetPasswordToken($token: String!) {\n checkResetPasswordToken(token: $token)\n}"): (typeof documents)["query CheckResetPasswordToken($token: String!) {\n checkResetPasswordToken(token: $token)\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "query Me {\n me {\n ...RegularUser\n }\n}"): (typeof documents)["query Me {\n me {\n ...RegularUser\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "query Post($id: String!) {\n post(id: $id) {\n ...RegularPost\n }\n}"): (typeof documents)["query Post($id: String!) {\n post(id: $id) {\n ...RegularPost\n }\n}"];
|
||||
/**
|
||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||
*/
|
||||
export function graphql(source: "query Posts($limit: Int, $cursor: Timestamp) {\n posts(limit: $limit, cursor: $cursor) {\n ...RegularPost\n }\n}"): (typeof documents)["query Posts($limit: Int, $cursor: Timestamp) {\n posts(limit: $limit, cursor: $cursor) {\n ...RegularPost\n }\n}"];
|
||||
|
||||
export function graphql(source: string) {
|
||||
return (documents as any)[source] ?? {};
|
||||
}
|
||||
|
||||
export type DocumentType<TDocumentNode extends DocumentNode<any, any>> = TDocumentNode extends DocumentNode< infer TType, any> ? TType : never;
|
||||
@@ -0,0 +1,479 @@
|
||||
/* eslint-disable */
|
||||
import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
|
||||
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
ID: { input: string; output: string; }
|
||||
String: { input: string; output: string; }
|
||||
Boolean: { input: boolean; output: boolean; }
|
||||
Int: { input: number; output: number; }
|
||||
Float: { input: number; output: number; }
|
||||
/** A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.This scalar is serialized to a string in ISO 8601 format and parsed from a string in ISO 8601 format. */
|
||||
DateTimeISO: { input: any; output: any; }
|
||||
/** The javascript `Date` as integer. Type represents date and time as number of milliseconds from start of UNIX epoch. */
|
||||
Timestamp: { input: any; output: any; }
|
||||
};
|
||||
|
||||
export type DateTimeFilter = {
|
||||
equals?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
gt?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
gte?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['DateTimeISO']['input']>>;
|
||||
lt?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
lte?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
not?: InputMaybe<NestedDateTimeFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['DateTimeISO']['input']>>;
|
||||
};
|
||||
|
||||
export type FieldError = {
|
||||
__typename?: 'FieldError';
|
||||
field?: Maybe<Scalars['String']['output']>;
|
||||
message: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type IntFilter = {
|
||||
equals?: InputMaybe<Scalars['Int']['input']>;
|
||||
gt?: InputMaybe<Scalars['Int']['input']>;
|
||||
gte?: InputMaybe<Scalars['Int']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||
lt?: InputMaybe<Scalars['Int']['input']>;
|
||||
lte?: InputMaybe<Scalars['Int']['input']>;
|
||||
not?: InputMaybe<NestedIntFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
createPost: PostResponse;
|
||||
deletePost: Scalars['Boolean']['output'];
|
||||
downvote?: Maybe<Post>;
|
||||
forgotPassword: ResetPasswordResponse;
|
||||
login: UserResponse;
|
||||
logout: Scalars['Boolean']['output'];
|
||||
register: UserResponse;
|
||||
removeDownvote?: Maybe<Post>;
|
||||
removeUpvote?: Maybe<Post>;
|
||||
resetPassword: ResetPasswordResponse;
|
||||
updatePost: PostResponse;
|
||||
upvote?: Maybe<Post>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreatePostArgs = {
|
||||
input: PostInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeletePostArgs = {
|
||||
id: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationDownvoteArgs = {
|
||||
postID: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationForgotPasswordArgs = {
|
||||
email: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationLoginArgs = {
|
||||
input: UsernamePasswordInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRegisterArgs = {
|
||||
input: UsernamePasswordInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveDownvoteArgs = {
|
||||
postID: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveUpvoteArgs = {
|
||||
postID: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationResetPasswordArgs = {
|
||||
newPassword: Scalars['String']['input'];
|
||||
token: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdatePostArgs = {
|
||||
content?: InputMaybe<Scalars['String']['input']>;
|
||||
id: Scalars['String']['input'];
|
||||
title?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpvoteArgs = {
|
||||
postID: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type NestedDateTimeFilter = {
|
||||
equals?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
gt?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
gte?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['DateTimeISO']['input']>>;
|
||||
lt?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
lte?: InputMaybe<Scalars['DateTimeISO']['input']>;
|
||||
not?: InputMaybe<NestedDateTimeFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['DateTimeISO']['input']>>;
|
||||
};
|
||||
|
||||
export type NestedIntFilter = {
|
||||
equals?: InputMaybe<Scalars['Int']['input']>;
|
||||
gt?: InputMaybe<Scalars['Int']['input']>;
|
||||
gte?: InputMaybe<Scalars['Int']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||
lt?: InputMaybe<Scalars['Int']['input']>;
|
||||
lte?: InputMaybe<Scalars['Int']['input']>;
|
||||
not?: InputMaybe<NestedIntFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||
};
|
||||
|
||||
export type NestedStringFilter = {
|
||||
contains?: InputMaybe<Scalars['String']['input']>;
|
||||
endsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
equals?: InputMaybe<Scalars['String']['input']>;
|
||||
gt?: InputMaybe<Scalars['String']['input']>;
|
||||
gte?: InputMaybe<Scalars['String']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
lt?: InputMaybe<Scalars['String']['input']>;
|
||||
lte?: InputMaybe<Scalars['String']['input']>;
|
||||
not?: InputMaybe<NestedStringFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type NestedStringNullableFilter = {
|
||||
contains?: InputMaybe<Scalars['String']['input']>;
|
||||
endsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
equals?: InputMaybe<Scalars['String']['input']>;
|
||||
gt?: InputMaybe<Scalars['String']['input']>;
|
||||
gte?: InputMaybe<Scalars['String']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
lt?: InputMaybe<Scalars['String']['input']>;
|
||||
lte?: InputMaybe<Scalars['String']['input']>;
|
||||
not?: InputMaybe<NestedStringNullableFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type Post = {
|
||||
__typename?: 'Post';
|
||||
author: User;
|
||||
authorID: Scalars['String']['output'];
|
||||
content: Scalars['String']['output'];
|
||||
createdAt: Scalars['DateTimeISO']['output'];
|
||||
downvoted?: Maybe<Scalars['Boolean']['output']>;
|
||||
id: Scalars['String']['output'];
|
||||
points: Scalars['Int']['output'];
|
||||
snippet: Scalars['String']['output'];
|
||||
title?: Maybe<Scalars['String']['output']>;
|
||||
updatedAt: Scalars['DateTimeISO']['output'];
|
||||
upvoted?: Maybe<Scalars['Boolean']['output']>;
|
||||
};
|
||||
|
||||
export type PostInput = {
|
||||
content: Scalars['String']['input'];
|
||||
title?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type PostListRelationFilter = {
|
||||
every?: InputMaybe<PostWhereInput>;
|
||||
none?: InputMaybe<PostWhereInput>;
|
||||
some?: InputMaybe<PostWhereInput>;
|
||||
};
|
||||
|
||||
export type PostResponse = {
|
||||
__typename?: 'PostResponse';
|
||||
errors?: Maybe<Array<FieldError>>;
|
||||
post?: Maybe<Post>;
|
||||
};
|
||||
|
||||
export type PostWhereInput = {
|
||||
AND?: InputMaybe<Array<PostWhereInput>>;
|
||||
NOT?: InputMaybe<Array<PostWhereInput>>;
|
||||
OR?: InputMaybe<Array<PostWhereInput>>;
|
||||
author?: InputMaybe<UserRelationFilter>;
|
||||
authorID?: InputMaybe<StringFilter>;
|
||||
content?: InputMaybe<StringFilter>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
id?: InputMaybe<StringFilter>;
|
||||
points?: InputMaybe<IntFilter>;
|
||||
title?: InputMaybe<StringNullableFilter>;
|
||||
updatedAt?: InputMaybe<DateTimeFilter>;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
checkResetPasswordToken: Scalars['Boolean']['output'];
|
||||
me?: Maybe<User>;
|
||||
post?: Maybe<Post>;
|
||||
posts: Array<Post>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryCheckResetPasswordTokenArgs = {
|
||||
token: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryPostArgs = {
|
||||
id: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryPostsArgs = {
|
||||
cursor?: InputMaybe<Scalars['Timestamp']['input']>;
|
||||
limit?: InputMaybe<Scalars['Int']['input']>;
|
||||
};
|
||||
|
||||
export enum QueryMode {
|
||||
Default = 'default',
|
||||
Insensitive = 'insensitive'
|
||||
}
|
||||
|
||||
export type ResetPasswordResponse = {
|
||||
__typename?: 'ResetPasswordResponse';
|
||||
errors?: Maybe<Array<FieldError>>;
|
||||
message?: Maybe<Scalars['String']['output']>;
|
||||
messageType?: Maybe<Scalars['String']['output']>;
|
||||
};
|
||||
|
||||
export type StringFilter = {
|
||||
contains?: InputMaybe<Scalars['String']['input']>;
|
||||
endsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
equals?: InputMaybe<Scalars['String']['input']>;
|
||||
gt?: InputMaybe<Scalars['String']['input']>;
|
||||
gte?: InputMaybe<Scalars['String']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
lt?: InputMaybe<Scalars['String']['input']>;
|
||||
lte?: InputMaybe<Scalars['String']['input']>;
|
||||
mode?: InputMaybe<QueryMode>;
|
||||
not?: InputMaybe<NestedStringFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type StringNullableFilter = {
|
||||
contains?: InputMaybe<Scalars['String']['input']>;
|
||||
endsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
equals?: InputMaybe<Scalars['String']['input']>;
|
||||
gt?: InputMaybe<Scalars['String']['input']>;
|
||||
gte?: InputMaybe<Scalars['String']['input']>;
|
||||
in?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
lt?: InputMaybe<Scalars['String']['input']>;
|
||||
lte?: InputMaybe<Scalars['String']['input']>;
|
||||
mode?: InputMaybe<QueryMode>;
|
||||
not?: InputMaybe<NestedStringNullableFilter>;
|
||||
notIn?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||
startsWith?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type User = {
|
||||
__typename?: 'User';
|
||||
_count?: Maybe<UserCount>;
|
||||
createdAt: Scalars['DateTimeISO']['output'];
|
||||
email?: Maybe<Scalars['String']['output']>;
|
||||
id: Scalars['String']['output'];
|
||||
updatedAt: Scalars['DateTimeISO']['output'];
|
||||
username: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type UserCount = {
|
||||
__typename?: 'UserCount';
|
||||
Post: Scalars['Int']['output'];
|
||||
};
|
||||
|
||||
|
||||
export type UserCountPostArgs = {
|
||||
where?: InputMaybe<PostWhereInput>;
|
||||
};
|
||||
|
||||
export type UserRelationFilter = {
|
||||
is?: InputMaybe<UserWhereInput>;
|
||||
isNot?: InputMaybe<UserWhereInput>;
|
||||
};
|
||||
|
||||
export type UserResponse = {
|
||||
__typename?: 'UserResponse';
|
||||
errors?: Maybe<Array<FieldError>>;
|
||||
user?: Maybe<User>;
|
||||
};
|
||||
|
||||
export type UserWhereInput = {
|
||||
AND?: InputMaybe<Array<UserWhereInput>>;
|
||||
NOT?: InputMaybe<Array<UserWhereInput>>;
|
||||
OR?: InputMaybe<Array<UserWhereInput>>;
|
||||
Post?: InputMaybe<PostListRelationFilter>;
|
||||
createdAt?: InputMaybe<DateTimeFilter>;
|
||||
email?: InputMaybe<StringNullableFilter>;
|
||||
id?: InputMaybe<StringFilter>;
|
||||
password?: InputMaybe<StringFilter>;
|
||||
updatedAt?: InputMaybe<DateTimeFilter>;
|
||||
username?: InputMaybe<StringFilter>;
|
||||
};
|
||||
|
||||
export type UsernamePasswordInput = {
|
||||
email?: InputMaybe<Scalars['String']['input']>;
|
||||
password: Scalars['String']['input'];
|
||||
username: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type RegularErrorFragment = { __typename?: 'FieldError', field?: string | null, message: string };
|
||||
|
||||
export type RegularPostFragment = { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } };
|
||||
|
||||
export type RegularPostResponseFragment = { __typename?: 'PostResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, post?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type RegularUserFragment = { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any };
|
||||
|
||||
export type RegularUserResponseFragment = { __typename?: 'UserResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, user?: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } | null };
|
||||
|
||||
export type CreatePostMutationVariables = Exact<{
|
||||
input: PostInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreatePostMutation = { __typename?: 'Mutation', createPost: { __typename?: 'PostResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, post?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null } };
|
||||
|
||||
export type DeletePostMutationVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DeletePostMutation = { __typename?: 'Mutation', deletePost: boolean };
|
||||
|
||||
export type DownvoteMutationVariables = Exact<{
|
||||
postID: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type DownvoteMutation = { __typename?: 'Mutation', downvote?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type ForgotPasswordMutationVariables = Exact<{
|
||||
email: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ForgotPasswordMutation = { __typename?: 'Mutation', forgotPassword: { __typename?: 'ResetPasswordResponse', message?: string | null, messageType?: string | null, errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null } };
|
||||
|
||||
export type LoginMutationVariables = Exact<{
|
||||
input: UsernamePasswordInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type LoginMutation = { __typename?: 'Mutation', login: { __typename?: 'UserResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, user?: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } | null } };
|
||||
|
||||
export type LogoutMutationVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type LogoutMutation = { __typename?: 'Mutation', logout: boolean };
|
||||
|
||||
export type RegisterMutationVariables = Exact<{
|
||||
input: UsernamePasswordInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type RegisterMutation = { __typename?: 'Mutation', register: { __typename?: 'UserResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, user?: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } | null } };
|
||||
|
||||
export type RemoveDownvoteMutationVariables = Exact<{
|
||||
postID: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type RemoveDownvoteMutation = { __typename?: 'Mutation', removeDownvote?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type RemoveUpvoteMutationVariables = Exact<{
|
||||
postID: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type RemoveUpvoteMutation = { __typename?: 'Mutation', removeUpvote?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type ResetPasswordMutationVariables = Exact<{
|
||||
newPassword: Scalars['String']['input'];
|
||||
token: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ResetPasswordMutation = { __typename?: 'Mutation', resetPassword: { __typename?: 'ResetPasswordResponse', message?: string | null, messageType?: string | null, errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null } };
|
||||
|
||||
export type UpdatePostMutationVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
title: Scalars['String']['input'];
|
||||
content: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdatePostMutation = { __typename?: 'Mutation', updatePost: { __typename?: 'PostResponse', errors?: Array<{ __typename?: 'FieldError', field?: string | null, message: string }> | null, post?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null } };
|
||||
|
||||
export type UpvoteMutationVariables = Exact<{
|
||||
postID: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type UpvoteMutation = { __typename?: 'Mutation', upvote?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type CheckResetPasswordTokenQueryVariables = Exact<{
|
||||
token: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type CheckResetPasswordTokenQuery = { __typename?: 'Query', checkResetPasswordToken: boolean };
|
||||
|
||||
export type MeQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MeQuery = { __typename?: 'Query', me?: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } | null };
|
||||
|
||||
export type PostQueryVariables = Exact<{
|
||||
id: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type PostQuery = { __typename?: 'Query', post?: { __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } } | null };
|
||||
|
||||
export type PostsQueryVariables = Exact<{
|
||||
limit?: InputMaybe<Scalars['Int']['input']>;
|
||||
cursor?: InputMaybe<Scalars['Timestamp']['input']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type PostsQuery = { __typename?: 'Query', posts: Array<{ __typename?: 'Post', id: string, authorID: string, title?: string | null, content: string, createdAt: any, updatedAt: any, snippet: string, points: number, upvoted?: boolean | null, downvoted?: boolean | null, author: { __typename?: 'User', id: string, email?: string | null, username: string, createdAt: any, updatedAt: any } }> };
|
||||
|
||||
export const RegularErrorFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]} as unknown as DocumentNode<RegularErrorFragment, unknown>;
|
||||
export const RegularUserFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<RegularUserFragment, unknown>;
|
||||
export const RegularPostFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<RegularPostFragment, unknown>;
|
||||
export const RegularPostResponseFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPostResponse"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PostResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"post"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<RegularPostResponseFragment, unknown>;
|
||||
export const RegularUserResponseFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUserResponse"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<RegularUserResponseFragment, unknown>;
|
||||
export const CreatePostDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreatePost"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PostInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createPost"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPostResponse"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPostResponse"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PostResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"post"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}}]} as unknown as DocumentNode<CreatePostMutation, CreatePostMutationVariables>;
|
||||
export const DeletePostDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeletePost"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletePost"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode<DeletePostMutation, DeletePostMutationVariables>;
|
||||
export const DownvoteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Downvote"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"postID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"downvote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"postID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"postID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<DownvoteMutation, DownvoteMutationVariables>;
|
||||
export const ForgotPasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ForgotPassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"forgotPassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"messageType"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]} as unknown as DocumentNode<ForgotPasswordMutation, ForgotPasswordMutationVariables>;
|
||||
export const LoginDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Login"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UsernamePasswordInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"login"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUserResponse"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUserResponse"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<LoginMutation, LoginMutationVariables>;
|
||||
export const LogoutDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Logout"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"logout"}}]}}]} as unknown as DocumentNode<LogoutMutation, LogoutMutationVariables>;
|
||||
export const RegisterDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Register"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UsernamePasswordInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"register"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUserResponse"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUserResponse"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserResponse"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<RegisterMutation, RegisterMutationVariables>;
|
||||
export const RemoveDownvoteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemoveDownvote"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"postID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeDownvote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"postID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"postID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<RemoveDownvoteMutation, RemoveDownvoteMutationVariables>;
|
||||
export const RemoveUpvoteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemoveUpvote"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"postID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeUpvote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"postID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"postID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<RemoveUpvoteMutation, RemoveUpvoteMutationVariables>;
|
||||
export const ResetPasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResetPassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resetPassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"newPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}}},{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"message"}},{"kind":"Field","name":{"kind":"Name","value":"messageType"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}}]} as unknown as DocumentNode<ResetPasswordMutation, ResetPasswordMutationVariables>;
|
||||
export const UpdatePostDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdatePost"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"title"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"content"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updatePost"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"title"},"value":{"kind":"Variable","name":{"kind":"Name","value":"title"}}},{"kind":"Argument","name":{"kind":"Name","value":"content"},"value":{"kind":"Variable","name":{"kind":"Name","value":"content"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"errors"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularError"}}]}},{"kind":"Field","name":{"kind":"Name","value":"post"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularError"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FieldError"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field"}},{"kind":"Field","name":{"kind":"Name","value":"message"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<UpdatePostMutation, UpdatePostMutationVariables>;
|
||||
export const UpvoteDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"Upvote"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"postID"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upvote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"postID"},"value":{"kind":"Variable","name":{"kind":"Name","value":"postID"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<UpvoteMutation, UpvoteMutationVariables>;
|
||||
export const CheckResetPasswordTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CheckResetPasswordToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"checkResetPasswordToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}]}]}}]} as unknown as DocumentNode<CheckResetPasswordTokenQuery, CheckResetPasswordTokenQueryVariables>;
|
||||
export const MeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"me"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<MeQuery, MeQueryVariables>;
|
||||
export const PostDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Post"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"post"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<PostQuery, PostQueryVariables>;
|
||||
export const PostsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Posts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Timestamp"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"posts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"cursor"},"value":{"kind":"Variable","name":{"kind":"Name","value":"cursor"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularPost"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularUser"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"User"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RegularPost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Post"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"authorID"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"snippet"}},{"kind":"Field","name":{"kind":"Name","value":"points"}},{"kind":"Field","name":{"kind":"Name","value":"upvoted"}},{"kind":"Field","name":{"kind":"Name","value":"downvoted"}},{"kind":"Field","name":{"kind":"Name","value":"author"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RegularUser"}}]}}]}}]} as unknown as DocumentNode<PostsQuery, PostsQueryVariables>;
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./gql";
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli'
|
||||
|
||||
const config: CodegenConfig = {
|
||||
overwrite: true,
|
||||
schema: 'http://localhost:4000/graphql',
|
||||
documents: 'graphql/**/*.graphql',
|
||||
generates: {
|
||||
'generated/graphql/': {
|
||||
preset: 'client',
|
||||
presetConfig: {
|
||||
fragmentMasking: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
||||
@@ -0,0 +1,4 @@
|
||||
fragment RegularError on FieldError {
|
||||
field
|
||||
message
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
fragment RegularPost on Post {
|
||||
id
|
||||
authorID
|
||||
title
|
||||
content
|
||||
createdAt
|
||||
updatedAt
|
||||
snippet
|
||||
points
|
||||
upvoted
|
||||
downvoted
|
||||
author {
|
||||
...RegularUser
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fragment RegularPostResponse on PostResponse {
|
||||
errors {
|
||||
...RegularError
|
||||
}
|
||||
post {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fragment RegularUser on User {
|
||||
id
|
||||
email
|
||||
username
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fragment RegularUserResponse on UserResponse {
|
||||
errors {
|
||||
...RegularError
|
||||
}
|
||||
user {
|
||||
...RegularUser
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation CreatePost($input: PostInput!) {
|
||||
createPost(input: $input) {
|
||||
...RegularPostResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
mutation DeletePost($id: String!) {
|
||||
deletePost(id: $id)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation Downvote($postID: String!) {
|
||||
downvote(postID: $postID) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
mutation ForgotPassword($email: String!) {
|
||||
forgotPassword(email: $email) {
|
||||
errors {
|
||||
...RegularError
|
||||
}
|
||||
message
|
||||
messageType
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation Login($input: UsernamePasswordInput!) {
|
||||
login(input: $input) {
|
||||
...RegularUserResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
mutation Logout {
|
||||
logout
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation Register($input: UsernamePasswordInput!) {
|
||||
register(input: $input) {
|
||||
...RegularUserResponse
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation RemoveDownvote($postID: String!) {
|
||||
removeDownvote(postID: $postID) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation RemoveUpvote($postID: String!) {
|
||||
removeUpvote(postID: $postID) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
mutation ResetPassword($newPassword: String!, $token: String!) {
|
||||
resetPassword(newPassword: $newPassword, token: $token) {
|
||||
errors {
|
||||
...RegularError
|
||||
}
|
||||
message
|
||||
messageType
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
mutation UpdatePost($id: String!, $title: String!, $content: String!) {
|
||||
updatePost(id: $id, title: $title, content: $content) {
|
||||
errors {
|
||||
...RegularError
|
||||
}
|
||||
post {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
mutation Upvote($postID: String!) {
|
||||
upvote(postID: $postID) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
query CheckResetPasswordToken($token: String!) {
|
||||
checkResetPasswordToken(token: $token)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
query Me {
|
||||
me {
|
||||
...RegularUser
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
query Post($id: String!) {
|
||||
post(id: $id) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
query Posts($limit: Int, $cursor: Timestamp) {
|
||||
posts(limit: $limit, cursor: $cursor) {
|
||||
...RegularPost
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './useAuthenticate'
|
||||
@@ -0,0 +1,15 @@
|
||||
import { MeDocument } from '@/generated/graphql/graphql'
|
||||
import { useQuery } from '@apollo/client/react'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
export const useAuthenticate = () => {
|
||||
const router = useRouter()
|
||||
const { data, loading } = useQuery(MeDocument)
|
||||
const pathname = usePathname()
|
||||
useEffect(() => {
|
||||
if (!loading && !data?.me) {
|
||||
router.replace(`/login?redirect=${pathname}`)
|
||||
}
|
||||
}, [router, data, loading])
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { HttpLink } from '@apollo/client'
|
||||
import { ApolloClient, InMemoryCache } from '@apollo/client'
|
||||
|
||||
// This is the client-side client
|
||||
export const apollo = new ApolloClient({
|
||||
link: new HttpLink({
|
||||
uri: process.env.NODE_ENV == 'production' ? 'https://litreddit-backend.elliot-at-zuri.ch/graphql' : process.env.NEXT_PUBLIC_BACKEND_URI,
|
||||
credentials: 'include', // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
}),
|
||||
cache: new InMemoryCache({
|
||||
typePolicies: {
|
||||
Query: {
|
||||
fields: {
|
||||
// https://www.apollographql.com/docs/react/pagination/core-api/
|
||||
posts: {
|
||||
// Don't cache separate results based on
|
||||
// any of this field's arguments.
|
||||
keyArgs: false,
|
||||
|
||||
// Concatenate the incoming list items with
|
||||
// the existing list items.
|
||||
merge: (existing: { __ref: string }[] = [], incoming: { __ref: string }[]) => {
|
||||
const cacheItems: typeof existing = JSON.parse(JSON.stringify(existing))
|
||||
const refs = existing.map(e => e.__ref)
|
||||
for (let i = 0;i < incoming.length;i++) {
|
||||
if (!refs.includes(incoming[i].__ref)) {
|
||||
cacheItems.push(incoming[i])
|
||||
refs.push(incoming[i].__ref)
|
||||
}
|
||||
}
|
||||
return cacheItems
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './client'
|
||||
export * from './server'
|
||||
@@ -0,0 +1,18 @@
|
||||
'use server'
|
||||
import { SESSION_COOKIE_NAME } from '@/constants'
|
||||
import { HttpLink } from '@apollo/client'
|
||||
import { ApolloClient, InMemoryCache, registerApolloClient } from '@apollo/client-integration-nextjs'
|
||||
|
||||
// This is the server-side client
|
||||
export const createApolloClient = async (cookie?: string) => registerApolloClient(() => {
|
||||
return new ApolloClient({
|
||||
link: new HttpLink({
|
||||
uri: process.env.NODE_ENV == 'production' ? 'https://litreddit-backend.elliot-at-zuri.ch/graphql' : process.env.NEXT_PUBLIC_BACKEND_URI,
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
cookie: cookie ? `${SESSION_COOKIE_NAME}=${cookie}` : ''
|
||||
}
|
||||
}),
|
||||
cache: new InMemoryCache()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1 @@
|
||||
export * from './apollo'
|
||||
@@ -0,0 +1,4 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
|
||||
export default nextConfig
|
||||
@@ -0,0 +1,221 @@
|
||||
All pages are **server components** by default. Only pages with `'use-client'` on top are **client components**.
|
||||
|
||||
**Server components fetch data on the server and pre-render the HTML.** For example, in the following page:
|
||||
|
||||
```tsx
|
||||
import LikeButton from '@/app/ui/like-button'
|
||||
import { getPost } from '@/lib/data'
|
||||
|
||||
export default async function Page({ params }: { params: { id: string } }) {
|
||||
const post = await getPost(params.id)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<main>
|
||||
<h1>{post.title}</h1>
|
||||
{/* ... */}
|
||||
<LikeButton likes={post.likes} />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function LikeButton({ likes }: { likes: number }) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The `getPost` function is run server-side to get the data and render the whole `div` tag except for the `LikeButton` which is rendered client-side.
|
||||
|
||||
Using any hooks e.g. `useQuery` or `useMutation` requires us to do so inside a `client component`.
|
||||
|
||||
We can also have `Next.js` fetches data and pre-renders HTML **at build time and on periodical revalidations** using [**Incremental Static Regeneration (ISR)**](https://nextjs.org/docs/app/guides/incremental-static-regeneration) as follows:
|
||||
|
||||
```tsx
|
||||
interface Post {
|
||||
id: string
|
||||
title: string
|
||||
content: string
|
||||
}
|
||||
|
||||
// Next.js will invalidate the cache when a
|
||||
// request comes in, at most once every 60 seconds.
|
||||
export const revalidate = 60
|
||||
|
||||
// For each `post` in the array returned by `generateStaticParams`,
|
||||
// we will pre-render and cache a corresponding page at build time and on later revalidations.
|
||||
// If a request comes in for a path that hasn't been generated,
|
||||
// i.e. if there is a request for a post not retrieved when `generateStaticParams` was last run,
|
||||
// Next.js will server-render the page on-demand.
|
||||
export const dynamicParams = true // or false, to 404 on unknown paths
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
|
||||
res.json()
|
||||
)
|
||||
return posts.map((post) => ({
|
||||
id: String(post.id),
|
||||
}))
|
||||
}
|
||||
|
||||
export default async function Page({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>
|
||||
}) {
|
||||
const { id } = await params
|
||||
const post: Post = await fetch(`https://api.vercel.app/blog/${id}`).then(
|
||||
(res) => res.json()
|
||||
)
|
||||
return (
|
||||
<main>
|
||||
<h1>{post.title}</h1>
|
||||
<p>{post.content}</p>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
SSR with `@apollo/client`:
|
||||
|
||||
```tsx
|
||||
import { Wrapper } from '@/components'
|
||||
import { SESSION_COOKIE_NAME } from '@/constants'
|
||||
import { MeDocument, PostDocument } from '@/generated/graphql/graphql'
|
||||
import { createApolloClient } from '@/lib'
|
||||
import { Heading, Text } from '@chakra-ui/react'
|
||||
import { cookies } from 'next/headers'
|
||||
import { ClientSection } from './ClientSection'
|
||||
|
||||
interface Props {
|
||||
params: {
|
||||
id: string
|
||||
}
|
||||
}
|
||||
|
||||
const PostPage: React.FC<Props> = async ({ params: { id } }) => {
|
||||
const cookieStore = cookies()
|
||||
const cookie = cookieStore.get(SESSION_COOKIE_NAME)?.value
|
||||
const apollo = await createApolloClient(cookie)
|
||||
const { data } = await apollo.query({ query: PostDocument, variables: { id } })
|
||||
const { data: meData } = await apollo.query({ query: MeDocument })
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{
|
||||
data?.post ?
|
||||
<>
|
||||
<Heading as='h3' size='md'>{data.post.title}</Heading>
|
||||
<Text>Posted by {data.post.author.username}</Text>
|
||||
<Text mt={4}>{data.post.content}</Text>
|
||||
{
|
||||
data?.post?.authorID == meData?.me?.id &&
|
||||
<ClientSection data={data} />
|
||||
}
|
||||
</>
|
||||
:
|
||||
<>Post not found!</>
|
||||
}
|
||||
</Wrapper>
|
||||
)
|
||||
}
|
||||
export default PostPage
|
||||
```
|
||||
|
||||
where `createApolloClient` is:
|
||||
|
||||
```tsx
|
||||
'use server'
|
||||
import { SESSION_COOKIE_NAME } from '@/constants'
|
||||
import { from, HttpLink, NormalizedCacheObject } from '@apollo/client'
|
||||
import { onError } from '@apollo/client/link/error'
|
||||
import { ApolloClient, InMemoryCache, registerApolloClient } from '@apollo/experimental-nextjs-app-support'
|
||||
|
||||
|
||||
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||
graphQLErrors?.forEach(({ message, locations, path }) => {
|
||||
console.log(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
||||
)
|
||||
})
|
||||
if (networkError) console.error(`[Network error]: ${networkError}`)
|
||||
})
|
||||
|
||||
|
||||
// This is the server-side client
|
||||
export const createApolloClient = async (cookie?: string) => registerApolloClient<ApolloClient<NormalizedCacheObject>>(() => {
|
||||
const httpLink = new HttpLink({
|
||||
uri: process.env.NEXT_PUBLIC_BACKEND_URI,
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
cookie: cookie ? `${SESSION_COOKIE_NAME}=${cookie}` : ''
|
||||
}
|
||||
})
|
||||
return new ApolloClient({
|
||||
ssrMode: true,
|
||||
link: from([errorLink, httpLink]),
|
||||
cache: new InMemoryCache()
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
If we use `react-query`, we can combine the initial server-side data fetching and subsequent `useQuery` calls as follows:
|
||||
|
||||
```tsx
|
||||
// app/posts/page.tsx
|
||||
import {
|
||||
dehydrate,
|
||||
HydrationBoundary,
|
||||
QueryClient,
|
||||
} from '@tanstack/react-query'
|
||||
import Posts from './posts'
|
||||
|
||||
export default async function PostsPage() {
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
|
||||
await queryClient.prefetchQuery({
|
||||
queryKey: ['posts'],
|
||||
queryFn: getPosts,
|
||||
})
|
||||
|
||||
return (
|
||||
// Hydration is when React converts the pre-rendered HTML from the server into a fully interactive application by attaching event handlers.
|
||||
// Dehydration, on the other hand, is when an interactive JavaScript object is converted into HTML.
|
||||
// Here we are converting the queryClient which contains data fetched server-side into HTML and passing that HTML into HydrationBoundary, which is a Client component.
|
||||
// When HydrationBoundary is rendered client-side, the HTML will be hydrated, i.e. the data fetched server-side will be integrated with useQuery seamlessly.
|
||||
<HydrationBoundary state={dehydrate(queryClient)}>
|
||||
<Posts />
|
||||
</HydrationBoundary>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// app/posts/posts.tsx
|
||||
'use client'
|
||||
|
||||
export default function Posts() {
|
||||
// This useQuery could just as well happen in some deeper
|
||||
// child to <Posts>, data will be available immediately either way
|
||||
const { data } = useQuery({
|
||||
queryKey: ['posts'],
|
||||
queryFn: () => getPosts(),
|
||||
})
|
||||
|
||||
// This query was not prefetched on the server and will not start
|
||||
// fetching until on the client, both patterns are fine to mix.
|
||||
const { data: commentsData } = useQuery({
|
||||
queryKey: ['posts-comments'],
|
||||
queryFn: getComments,
|
||||
})
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
Generated
+6481
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "litreddit-frontend",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"env:generate": "gen-env-types .env -o env.d.ts -e .",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"graphql:generate": "graphql-codegen --config graphql-codegen.ts",
|
||||
"deploy": "vercel --prod"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^4.0.4",
|
||||
"@apollo/client-integration-nextjs": "^0.13.1",
|
||||
"@chakra-ui/icons": "^2.1.1",
|
||||
"@chakra-ui/next-js": "^2.2.0",
|
||||
"@chakra-ui/react": "^2.8.2",
|
||||
"@emotion/react": "^11.11.4",
|
||||
"@emotion/styled": "^11.11.5",
|
||||
"@types/autosize": "^4.0.3",
|
||||
"autosize": "^6.0.1",
|
||||
"formik": "^2.4.6",
|
||||
"framer-motion": "^11.3.4",
|
||||
"graphql": "^16.9.0",
|
||||
"next": "^15.5.3",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "5.0.2",
|
||||
"@graphql-codegen/client-preset": "^4.3.2",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^24.3.1",
|
||||
"@types/react": "^19.1.12",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@types/ws": "^8.5.11",
|
||||
"gen-env-types": "^1.3.4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
|
||||
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./*"
|
||||
]
|
||||
},
|
||||
"target": "ES2017"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { FieldError } from '@/generated/graphql/graphql'
|
||||
|
||||
type Result = Record<string, string>
|
||||
|
||||
export const errorMapper = (errors: FieldError[]): Result => {
|
||||
const result: Result = {}
|
||||
errors.forEach(({ field, message }) => {
|
||||
if (field) {
|
||||
result[field] = message
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './errorMapper'
|
||||
Reference in New Issue
Block a user