diff --git a/api/client.js b/api/client.js new file mode 100644 index 00000000..7ded1ac8 --- /dev/null +++ b/api/client.js @@ -0,0 +1,28 @@ +import { ApolloClient, InMemoryCache } from '@apollo/client' +import { SchemaLink } from '@apollo/client/link/schema' +import { mergeSchemas } from 'graphql-tools' +import { getSession } from 'next-auth/client' +import resolvers from './resolvers' +import typeDefs from './typeDefs' +import models from './models' + +const client = new ApolloClient({ + ssrMode: true, + // Instead of "createHttpLink" use SchemaLink here + link: new SchemaLink({ + schema: mergeSchemas({ + schemas: typeDefs, + resolvers: resolvers + }), + context: async ({ req }) => { + const session = await getSession({ req }) + return { + models, + me: session ? session.user : null + } + } + }), + cache: new InMemoryCache() +}) + +export default client diff --git a/api/resolvers/item.js b/api/resolvers/item.js index e79fa29b..6dc160d0 100644 --- a/api/resolvers/item.js +++ b/api/resolvers/item.js @@ -30,6 +30,21 @@ const createItem = async (parent, { title, text, url, parentId }, { me, models } export default { Query: { items: async (parent, args, { models }) => { + return await models.$queryRaw(` + SELECT id, "created_at" as "createdAt", title, url, text, "userId", ltree2text("path") AS "path" + FROM "Item" + WHERE "parentId" IS NULL + ORDER BY "path"`) + }, + item: async (parent, { id }, { models }) => { + const res = await models.$queryRaw(` + SELECT id, "created_at" as "createdAt", title, url, text, "parentId", "userId", ltree2text("path") AS "path" + FROM "Item" + WHERE id = ${id} + ORDER BY "path"`) + return res.length ? res[0] : null + }, + ncomments: async (parent, { parentId }, { models }) => { return await models.$queryRaw(` SELECT id, "created_at" as "createdAt", title, url, text, "userId", ltree2text("path") AS "path" FROM "Item" @@ -62,7 +77,7 @@ export default { } if (!parentId) { - throw new UserInputError('Comment must have text', { argumentName: 'text' }) + throw new UserInputError('Comment must have parent', { argumentName: 'text' }) } return await createItem(parent, { text, parentId }, { me, models }) @@ -85,7 +100,13 @@ export default { return path.split('.').length - 1 }, - comments: () => 0, + ncomments: async (item, args, { models }) => { + const [{ count }] = await models.$queryRaw` + SELECT count(*) + FROM "Item" + WHERE path <@ text2ltree(${item.id}) AND id != ${item.id}` + return count + }, sats: () => 0 } } diff --git a/api/typeDefs/item.js b/api/typeDefs/item.js index 1380ad85..20319998 100644 --- a/api/typeDefs/item.js +++ b/api/typeDefs/item.js @@ -3,6 +3,8 @@ import { gql } from 'apollo-server-micro' export default gql` extend type Query { items: [Item!]! + item(id: ID!): Item + ncomments(id: ID!): [Item!]! } extend type Mutation { @@ -17,9 +19,10 @@ export default gql` title: String url: String text: String + parentId: Int user: User! depth: Int! sats: Int! - comments: Int! + ncomments: Int! } ` diff --git a/components/comment.js b/components/comment.js new file mode 100644 index 00000000..03418f45 --- /dev/null +++ b/components/comment.js @@ -0,0 +1,70 @@ +import itemStyles from './item.module.css' +import styles from './comment.module.css' +import UpVote from '../svgs/lightning-arrow.svg' +import Text from './text' +import Link from 'next/link' +import Reply from './reply' +import { useState } from 'react' + +function timeSince (timeStamp) { + const now = new Date() + const secondsPast = (now.getTime() - timeStamp) / 1000 + if (secondsPast < 60) { + return parseInt(secondsPast) + 's' + } + if (secondsPast < 3600) { + return parseInt(secondsPast / 60) + 'm' + } + if (secondsPast <= 86400) { + return parseInt(secondsPast / 3600) + 'h' + } + if (secondsPast > 86400) { + const day = timeStamp.getDate() + const month = timeStamp.toDateString().match(/ [a-zA-Z]*/)[0].replace(' ', '') + const year = timeStamp.getFullYear() === now.getFullYear() ? '' : ' ' + timeStamp.getFullYear() + return day + ' ' + month + year + } +} + +export default function Comment ({ item, children }) { + const [reply, setReply] = useState(false) + + return ( + <> +
+ {children} ++ ) +} diff --git a/components/text.module.css b/components/text.module.css new file mode 100644 index 00000000..4c3ede34 --- /dev/null +++ b/components/text.module.css @@ -0,0 +1,7 @@ +.text { + font-size: 90%; + white-space: pre-wrap; + word-break: break-word; + font-family: inherit; + margin: 0; +} \ No newline at end of file diff --git a/pages/[username].js b/pages/[username].js new file mode 100644 index 00000000..f0ae0b76 --- /dev/null +++ b/pages/[username].js @@ -0,0 +1,3 @@ +export default function User () { + return
{i + 1} | -