smarter use of SSR and caching
This commit is contained in:
parent
06b0424b82
commit
07b9da353b
|
@ -34,19 +34,28 @@ export async function getItem (parent, { id }, { models }) {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
moreItems: async (parent, { sort, cursor, userId, within }, { me, models }) => {
|
moreItems: async (parent, { sort, cursor, name, within }, { me, models }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
let items
|
let items; let user; let interval = 'INTERVAL '
|
||||||
let interval = 'INTERVAL '
|
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case 'user':
|
case 'user':
|
||||||
|
if (!name) {
|
||||||
|
throw new UserInputError('must supply name', { argumentName: 'name' })
|
||||||
|
}
|
||||||
|
|
||||||
|
user = await models.user.findUnique({ where: { name } })
|
||||||
|
if (!user) {
|
||||||
|
throw new UserInputError('no user has that name', { argumentName: 'name' })
|
||||||
|
}
|
||||||
|
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
WHERE "userId" = $1 AND "parentId" IS NULL AND created_at <= $2
|
WHERE "userId" = $1 AND "parentId" IS NULL AND created_at <= $2
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
LIMIT ${LIMIT}`, Number(userId), decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, user.id, decodedCursor.time, decodedCursor.offset)
|
||||||
break
|
break
|
||||||
case 'hot':
|
case 'hot':
|
||||||
// HACK we can speed hack the first hot page, by limiting our query to only
|
// HACK we can speed hack the first hot page, by limiting our query to only
|
||||||
|
@ -67,7 +76,7 @@ export default {
|
||||||
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset, new Date(new Date() - 7))
|
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset, new Date(new Date() - 7))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decodedCursor.offset !== 0 || items.length < LIMIT) {
|
if (decodedCursor.offset !== 0 || items?.length < LIMIT) {
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
FROM "Item"
|
FROM "Item"
|
||||||
|
@ -79,7 +88,7 @@ export default {
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 'top':
|
case 'top':
|
||||||
switch (within) {
|
switch (within?.pop()) {
|
||||||
case 'day':
|
case 'day':
|
||||||
interval += "'1 day'"
|
interval += "'1 day'"
|
||||||
break
|
break
|
||||||
|
@ -119,11 +128,16 @@ export default {
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
moreFlatComments: async (parent, { cursor, userId }, { me, models }) => {
|
moreFlatComments: async (parent, { cursor, name }, { me, models }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
|
|
||||||
if (!userId) {
|
if (!name) {
|
||||||
throw new UserInputError('must supply userId', { argumentName: 'userId' })
|
throw new UserInputError('must supply name', { argumentName: 'name' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await models.user.findUnique({ where: { name } })
|
||||||
|
if (!user) {
|
||||||
|
throw new UserInputError('no user has that name', { argumentName: 'name' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const comments = await models.$queryRaw(`
|
const comments = await models.$queryRaw(`
|
||||||
|
@ -133,7 +147,7 @@ export default {
|
||||||
AND created_at <= $2
|
AND created_at <= $2
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
OFFSET $3
|
OFFSET $3
|
||||||
LIMIT ${LIMIT}`, Number(userId), decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, user.id, decodedCursor.time, decodedCursor.offset)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cursor: comments.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
cursor: comments.length === LIMIT ? nextCursorEncoded(decodedCursor) : null,
|
||||||
|
@ -141,13 +155,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
item: getItem,
|
item: getItem,
|
||||||
userComments: async (parent, { userId }, { models }) => {
|
|
||||||
return await models.$queryRaw(`
|
|
||||||
${SELECT}
|
|
||||||
FROM "Item"
|
|
||||||
WHERE "userId" = $1 AND "parentId" IS NOT NULL
|
|
||||||
ORDER BY created_at DESC`, Number(userId))
|
|
||||||
},
|
|
||||||
pageTitle: async (parent, { url }, { models }) => {
|
pageTitle: async (parent, { url }, { models }) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(ensureProtocol(url), { redirect: 'follow' })
|
const response = await fetch(ensureProtocol(url), { redirect: 'follow' })
|
||||||
|
@ -524,11 +531,12 @@ const LEFT_JOIN_SATS =
|
||||||
JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
|
JOIN "ItemAct" ON i.id = "ItemAct"."itemId"
|
||||||
GROUP BY i.id) x ON "Item".id = x.id`
|
GROUP BY i.id) x ON "Item".id = x.id`
|
||||||
|
|
||||||
|
/* NOTE: because many items will have the same rank, we need to tie break with a unique field so pagination works */
|
||||||
function timedOrderBySats (num) {
|
function timedOrderBySats (num) {
|
||||||
return `ORDER BY ((x.sats-1)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 1.5) +
|
return `ORDER BY ((x.sats-1)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 1.5) +
|
||||||
(x.boost)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 5)) DESC NULLS LAST`
|
(x.boost)/POWER(EXTRACT(EPOCH FROM ($${num} - "Item".created_at))/3600+2, 5)) DESC NULLS LAST, "Item".id DESC`
|
||||||
}
|
}
|
||||||
|
|
||||||
const ORDER_BY_SATS =
|
const ORDER_BY_SATS =
|
||||||
`ORDER BY ((x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) +
|
`ORDER BY ((x.sats-1)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 1.5) +
|
||||||
(x.boost)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 5)) DESC NULLS LAST`
|
(x.boost)/POWER(EXTRACT(EPOCH FROM ((NOW() AT TIME ZONE 'UTC') - "Item".created_at))/3600+2, 5)) DESC NULLS LAST, "Item".id DESC`
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { getSession } from 'next-auth/client'
|
||||||
import resolvers from './resolvers'
|
import resolvers from './resolvers'
|
||||||
import typeDefs from './typeDefs'
|
import typeDefs from './typeDefs'
|
||||||
import models from './models'
|
import models from './models'
|
||||||
|
import { print } from 'graphql'
|
||||||
|
|
||||||
export default async function getSSRApolloClient (req) {
|
export default async function getSSRApolloClient (req) {
|
||||||
const session = req && await getSession({ req })
|
const session = req && await getSession({ req })
|
||||||
|
@ -23,3 +24,29 @@ export default async function getSSRApolloClient (req) {
|
||||||
cache: new InMemoryCache()
|
cache: new InMemoryCache()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getGetServerSideProps (query, variables = null) {
|
||||||
|
return async function ({ req, params }) {
|
||||||
|
const client = await getSSRApolloClient(req)
|
||||||
|
const { error, data } = await client.query({
|
||||||
|
query,
|
||||||
|
variables: { ...params, ...variables }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (error || !data) {
|
||||||
|
return {
|
||||||
|
notFound: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
apollo: {
|
||||||
|
query: print(query),
|
||||||
|
variables: { ...params, ...variables }
|
||||||
|
},
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,10 +2,9 @@ import { gql } from 'apollo-server-micro'
|
||||||
|
|
||||||
export default gql`
|
export default gql`
|
||||||
extend type Query {
|
extend type Query {
|
||||||
moreItems(sort: String!, cursor: String, userId: ID, within: String): Items
|
moreItems(sort: String!, cursor: String, name: String, within: [String]): Items
|
||||||
moreFlatComments(cursor: String, userId: ID): Comments
|
moreFlatComments(cursor: String, name: String!): Comments
|
||||||
item(id: ID!): Item
|
item(id: ID!): Item
|
||||||
userComments(userId: ID!): [Item!]
|
|
||||||
pageTitle(url: String!): String
|
pageTitle(url: String!): String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,7 @@ import MoreFooter from './more-footer'
|
||||||
export default function CommentsFlat ({ variables, comments, cursor, ...props }) {
|
export default function CommentsFlat ({ variables, comments, cursor, ...props }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { data, fetchMore } = useQuery(MORE_FLAT_COMMENTS, {
|
const { data, fetchMore } = useQuery(MORE_FLAT_COMMENTS, {
|
||||||
variables,
|
variables
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!data && !comments) {
|
if (!data && !comments) {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import Comment, { CommentSkeleton } from './comment'
|
import Comment, { CommentSkeleton } from './comment'
|
||||||
|
|
||||||
|
@ -22,10 +21,7 @@ export function CommentsSkeleton () {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CommentsQuery ({ query, ...props }) {
|
export function CommentsQuery ({ query, ...props }) {
|
||||||
const router = useRouter()
|
const { error, data } = useQuery(query)
|
||||||
const { error, data } = useQuery(query, {
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error) return <div>Failed to load!</div>
|
if (error) return <div>Failed to load!</div>
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|
|
@ -16,16 +16,6 @@ function WalletSummary ({ me }) {
|
||||||
return `${me?.sats} \\ ${me?.stacked}`
|
return `${me?.sats} \\ ${me?.stacked}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function RefreshableLink ({ href, children, ...props }) {
|
|
||||||
const router = useRouter()
|
|
||||||
const same = router.asPath === href
|
|
||||||
return (
|
|
||||||
<Link href={same ? `${href}?key=${Math.random()}` : href} as={href} {...props}>
|
|
||||||
{children}
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Header () {
|
export default function Header () {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const path = router.asPath.split('?')[0]
|
const path = router.asPath.split('?')[0]
|
||||||
|
@ -61,7 +51,7 @@ export default function Header () {
|
||||||
</div>}
|
</div>}
|
||||||
</NavDropdown.Item>
|
</NavDropdown.Item>
|
||||||
</Link>
|
</Link>
|
||||||
<RefreshableLink href='/notifications' passHref>
|
<Link href='/notifications' passHref>
|
||||||
<NavDropdown.Item>
|
<NavDropdown.Item>
|
||||||
notifications
|
notifications
|
||||||
{me?.hasNewNotes &&
|
{me?.hasNewNotes &&
|
||||||
|
@ -69,7 +59,7 @@ export default function Header () {
|
||||||
<span className='invisible'>{' '}</span>
|
<span className='invisible'>{' '}</span>
|
||||||
</div>}
|
</div>}
|
||||||
</NavDropdown.Item>
|
</NavDropdown.Item>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
<Link href='/wallet' passHref>
|
<Link href='/wallet' passHref>
|
||||||
<NavDropdown.Item>wallet</NavDropdown.Item>
|
<NavDropdown.Item>wallet</NavDropdown.Item>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -84,12 +74,12 @@ export default function Header () {
|
||||||
</Link>
|
</Link>
|
||||||
<div>
|
<div>
|
||||||
<NavDropdown.Divider />
|
<NavDropdown.Divider />
|
||||||
<RefreshableLink href='/recent' passHref>
|
<Link href='/recent' passHref>
|
||||||
<NavDropdown.Item>recent</NavDropdown.Item>
|
<NavDropdown.Item>recent</NavDropdown.Item>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
<RefreshableLink href={`/top${within ? `/${within}` : ''}`} passHref>
|
<Link href={`/top${within ? `/${within}` : ''}`} passHref>
|
||||||
<NavDropdown.Item>top</NavDropdown.Item>
|
<NavDropdown.Item>top</NavDropdown.Item>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
{me
|
{me
|
||||||
? (
|
? (
|
||||||
<Link href='/post' passHref>
|
<Link href='/post' passHref>
|
||||||
|
@ -139,18 +129,18 @@ export default function Header () {
|
||||||
className={styles.navbarNav}
|
className={styles.navbarNav}
|
||||||
activeKey={path}
|
activeKey={path}
|
||||||
>
|
>
|
||||||
<RefreshableLink href='/' passHref>
|
<Link href='/' passHref>
|
||||||
<Navbar.Brand className={`${styles.brand} d-none d-sm-block`}>STACKER NEWS</Navbar.Brand>
|
<Navbar.Brand className={`${styles.brand} d-none d-sm-block`}>STACKER NEWS</Navbar.Brand>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
<RefreshableLink href='/' passHref>
|
<Link href='/' passHref>
|
||||||
<Navbar.Brand className={`${styles.brand} d-block d-sm-none`}>SN</Navbar.Brand>
|
<Navbar.Brand className={`${styles.brand} d-block d-sm-none`}>SN</Navbar.Brand>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
||||||
<SplitButton
|
<SplitButton
|
||||||
title={
|
title={
|
||||||
<RefreshableLink href={sortLink} passHref>
|
<Link href={sortLink} passHref>
|
||||||
<Nav.Link className={styles.navLink}>{sort}</Nav.Link>
|
<Nav.Link className={styles.navLink}>{sort}</Nav.Link>
|
||||||
</RefreshableLink>
|
</Link>
|
||||||
}
|
}
|
||||||
key={`/${sort}`}
|
key={`/${sort}`}
|
||||||
id='recent-top-button'
|
id='recent-top-button'
|
||||||
|
|
|
@ -2,15 +2,10 @@ import { useQuery } from '@apollo/client'
|
||||||
import Item, { ItemSkeleton } from './item'
|
import Item, { ItemSkeleton } from './item'
|
||||||
import styles from './items.module.css'
|
import styles from './items.module.css'
|
||||||
import { MORE_ITEMS } from '../fragments/items'
|
import { MORE_ITEMS } from '../fragments/items'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import MoreFooter from './more-footer'
|
import MoreFooter from './more-footer'
|
||||||
|
|
||||||
export default function Items ({ variables, rank, items, cursor }) {
|
export default function Items ({ variables, rank, items, cursor }) {
|
||||||
const router = useRouter()
|
const { data, fetchMore } = useQuery(MORE_ITEMS, { variables })
|
||||||
const { data, fetchMore } = useQuery(MORE_ITEMS, {
|
|
||||||
variables,
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!data && !items) {
|
if (!data && !items) {
|
||||||
return <ItemsSkeleton rank={rank} />
|
return <ItemsSkeleton rank={rank} />
|
||||||
|
|
|
@ -44,11 +44,7 @@ function Notification ({ n }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Notifications ({ notifications, cursor, lastChecked, variables }) {
|
export default function Notifications ({ notifications, cursor, lastChecked, variables }) {
|
||||||
const router = useRouter()
|
const { data, fetchMore } = useQuery(NOTIFICATIONS, { variables })
|
||||||
const { data, fetchMore } = useQuery(NOTIFICATIONS, {
|
|
||||||
variables,
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
({ notifications: { notifications, cursor } } = data)
|
({ notifications: { notifications, cursor } } = data)
|
||||||
|
|
|
@ -71,7 +71,7 @@ export default function UserHeader ({ user }) {
|
||||||
}
|
}
|
||||||
router.replace({
|
router.replace({
|
||||||
pathname: router.pathname,
|
pathname: router.pathname,
|
||||||
query: { ...router.query, username: name }
|
query: { ...router.query, name }
|
||||||
})
|
})
|
||||||
|
|
||||||
client.writeFragment({
|
client.writeFragment({
|
||||||
|
|
|
@ -27,8 +27,8 @@ export const COMMENT_FIELDS = gql`
|
||||||
export const MORE_FLAT_COMMENTS = gql`
|
export const MORE_FLAT_COMMENTS = gql`
|
||||||
${COMMENT_FIELDS}
|
${COMMENT_FIELDS}
|
||||||
|
|
||||||
query MoreFlatComments($cursor: String, $userId: ID) {
|
query MoreFlatComments($cursor: String, $name: String!) {
|
||||||
moreFlatComments(cursor: $cursor, userId: $userId) {
|
moreFlatComments(cursor: $cursor, name: $name) {
|
||||||
cursor
|
cursor
|
||||||
comments {
|
comments {
|
||||||
...CommentFields
|
...CommentFields
|
||||||
|
|
|
@ -28,8 +28,8 @@ export const ITEM_FIELDS = gql`
|
||||||
export const MORE_ITEMS = gql`
|
export const MORE_ITEMS = gql`
|
||||||
${ITEM_FIELDS}
|
${ITEM_FIELDS}
|
||||||
|
|
||||||
query MoreItems($sort: String!, $cursor: String, $userId: ID, $within: String) {
|
query MoreItems($sort: String!, $cursor: String, $name: String, $within: [String]) {
|
||||||
moreItems(sort: $sort, cursor: $cursor, userId: $userId, within: $within) {
|
moreItems(sort: $sort, cursor: $cursor, name: $name, within: $within) {
|
||||||
cursor
|
cursor
|
||||||
items {
|
items {
|
||||||
...ItemFields
|
...ItemFields
|
||||||
|
@ -37,11 +37,21 @@ export const MORE_ITEMS = gql`
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
export const ITEM_FULL = id => gql`
|
export const ITEM = gql`
|
||||||
|
${ITEM_FIELDS}
|
||||||
|
|
||||||
|
query Item($id: ID!) {
|
||||||
|
item(id: $id) {
|
||||||
|
...ItemFields
|
||||||
|
text
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
export const ITEM_FULL = gql`
|
||||||
${ITEM_FIELDS}
|
${ITEM_FIELDS}
|
||||||
${COMMENTS}
|
${COMMENTS}
|
||||||
{
|
query Item($id: ID!) {
|
||||||
item(id: ${id}) {
|
item(id: $id) {
|
||||||
...ItemFields
|
...ItemFields
|
||||||
text
|
text
|
||||||
comments {
|
comments {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { gql } from '@apollo/client'
|
import { gql } from '@apollo/client'
|
||||||
|
import { COMMENT_FIELDS } from './comments'
|
||||||
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
||||||
|
|
||||||
export const USER_FIELDS = gql`
|
export const USER_FIELDS = gql`
|
||||||
|
@ -17,14 +18,52 @@ export const USER_FIELDS = gql`
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
export const USER_FULL = name => gql`
|
export const USER_FULL = gql`
|
||||||
${USER_FIELDS}
|
${USER_FIELDS}
|
||||||
${ITEM_WITH_COMMENTS}
|
${ITEM_WITH_COMMENTS}
|
||||||
{
|
query User($name: String!) {
|
||||||
user(name: "${name}") {
|
user(name: $name) {
|
||||||
...UserFields
|
...UserFields
|
||||||
bio {
|
bio {
|
||||||
...ItemWithComments
|
...ItemWithComments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
export const USER_WITH_COMMENTS = gql`
|
||||||
|
${USER_FIELDS}
|
||||||
|
${ITEM_WITH_COMMENTS}
|
||||||
|
${COMMENT_FIELDS}
|
||||||
|
query UserWithComments($name: String!) {
|
||||||
|
user(name: $name) {
|
||||||
|
...UserFields
|
||||||
|
bio {
|
||||||
|
...ItemWithComments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moreFlatComments(name: $name) {
|
||||||
|
cursor
|
||||||
|
comments {
|
||||||
|
...CommentFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
export const USER_WITH_POSTS = gql`
|
||||||
|
${USER_FIELDS}
|
||||||
|
${ITEM_WITH_COMMENTS}
|
||||||
|
${ITEM_FIELDS}
|
||||||
|
query UserWithPosts($name: String!, $sort: String!) {
|
||||||
|
user(name: $name) {
|
||||||
|
...UserFields
|
||||||
|
bio {
|
||||||
|
...ItemWithComments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
moreItems(sort: $sort, name: $name) {
|
||||||
|
cursor
|
||||||
|
items {
|
||||||
|
...ItemFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { gql } from '@apollo/client'
|
||||||
|
|
||||||
|
export const INVOICE = gql`
|
||||||
|
query Invoice($id: ID!) {
|
||||||
|
invoice(id: $id) {
|
||||||
|
id
|
||||||
|
bolt11
|
||||||
|
msatsReceived
|
||||||
|
cancelled
|
||||||
|
confirmedAt
|
||||||
|
expiresAt
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
export const WITHDRAWL = gql`
|
||||||
|
query Withdrawl($id: ID!) {
|
||||||
|
withdrawl(id: $id) {
|
||||||
|
id
|
||||||
|
bolt11
|
||||||
|
satsPaid
|
||||||
|
satsFeePaying
|
||||||
|
satsFeePaid
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}`
|
|
@ -7,14 +7,14 @@ const additiveLink = from([
|
||||||
new HttpLink({ uri: '/api/graphql' })
|
new HttpLink({ uri: '/api/graphql' })
|
||||||
])
|
])
|
||||||
|
|
||||||
function isFirstPage (cursor, existing) {
|
function isFirstPage (cursor, existingThings) {
|
||||||
if (cursor) {
|
if (cursor) {
|
||||||
const decursor = decodeCursor(cursor)
|
const decursor = decodeCursor(cursor)
|
||||||
return decursor.offset === LIMIT
|
return decursor.offset === LIMIT
|
||||||
} else {
|
} else {
|
||||||
// we don't have anything cached, or our existing items are less than
|
// we don't have anything cached, or our existing items are less than
|
||||||
// or equal to a full page
|
// or equal to a full page
|
||||||
return !existing || !existing.items || existing.items.length < LIMIT
|
return existingThings?.length < LIMIT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ export default function getApolloClient () {
|
||||||
Query: {
|
Query: {
|
||||||
fields: {
|
fields: {
|
||||||
moreItems: {
|
moreItems: {
|
||||||
keyArgs: ['sort', 'userId', 'within'],
|
keyArgs: ['sort', 'name', 'within'],
|
||||||
merge (existing, incoming) {
|
merge (existing, incoming) {
|
||||||
if (isFirstPage(incoming.cursor, existing)) {
|
if (isFirstPage(incoming.cursor, existing?.items)) {
|
||||||
return incoming
|
return incoming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,9 +39,9 @@ export default function getApolloClient () {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
moreFlatComments: {
|
moreFlatComments: {
|
||||||
keyArgs: ['userId'],
|
keyArgs: ['name'],
|
||||||
merge (existing, incoming) {
|
merge (existing, incoming) {
|
||||||
if (isFirstPage(incoming.cursor, existing)) {
|
if (isFirstPage(incoming.cursor, existing?.comments)) {
|
||||||
return incoming
|
return incoming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ export default function getApolloClient () {
|
||||||
notifications: {
|
notifications: {
|
||||||
keyArgs: false,
|
keyArgs: false,
|
||||||
merge (existing, incoming) {
|
merge (existing, incoming) {
|
||||||
if (isFirstPage(incoming.cursor, existing)) {
|
if (isFirstPage(incoming.cursor, existing?.notifications)) {
|
||||||
return incoming
|
return incoming
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +72,11 @@ export default function getApolloClient () {
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
// cache-and-network allows us to refresh pages on navigation
|
// cache-and-network allows us to refresh pages on navigation
|
||||||
watchQuery: {
|
watchQuery: {
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-only',
|
||||||
nextFetchPolicy: 'cache-first'
|
nextFetchPolicy: 'cache-first'
|
||||||
},
|
},
|
||||||
query: {
|
query: {
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-only',
|
||||||
nextFetchPolicy: 'cache-first'
|
nextFetchPolicy: 'cache-first'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import Layout from '../../components/layout'
|
||||||
|
import { useQuery } from '@apollo/client'
|
||||||
|
import UserHeader from '../../components/user-header'
|
||||||
|
import CommentsFlat from '../../components/comments-flat'
|
||||||
|
import Seo from '../../components/seo'
|
||||||
|
import { USER_WITH_COMMENTS } from '../../fragments/users'
|
||||||
|
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||||
|
|
||||||
|
export const getServerSideProps = getGetServerSideProps(USER_WITH_COMMENTS)
|
||||||
|
|
||||||
|
export default function UserComments (
|
||||||
|
{ data: { user, moreFlatComments: { comments, cursor } } }) {
|
||||||
|
const { data } = useQuery(
|
||||||
|
USER_WITH_COMMENTS, { variables: { name: user.name } })
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
({ user, moreFlatComments: { comments, cursor } } = data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout noSeo>
|
||||||
|
<Seo user={user} />
|
||||||
|
<UserHeader user={user} />
|
||||||
|
<CommentsFlat
|
||||||
|
comments={comments} cursor={cursor}
|
||||||
|
variables={{ name: user.name }} includeParent noReply
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -12,28 +12,10 @@ import ActionTooltip from '../../components/action-tooltip'
|
||||||
import TextareaAutosize from 'react-textarea-autosize'
|
import TextareaAutosize from 'react-textarea-autosize'
|
||||||
import { useMe } from '../../components/me'
|
import { useMe } from '../../components/me'
|
||||||
import { USER_FULL } from '../../fragments/users'
|
import { USER_FULL } from '../../fragments/users'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { ITEM_FIELDS } from '../../fragments/items'
|
import { ITEM_FIELDS } from '../../fragments/items'
|
||||||
import getSSRApolloClient from '../../api/ssrApollo'
|
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { username } }) {
|
export const getServerSideProps = getGetServerSideProps(USER_FULL)
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
const { error, data } = await client.query({
|
|
||||||
query: USER_FULL(username)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error || !data?.user) {
|
|
||||||
return {
|
|
||||||
notFound: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
user: data.user
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BioSchema = Yup.object({
|
const BioSchema = Yup.object({
|
||||||
bio: Yup.string().required('required').trim()
|
bio: Yup.string().required('required').trim()
|
||||||
|
@ -93,15 +75,12 @@ export function BioForm ({ handleSuccess, bio }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function User ({ user }) {
|
export default function User ({ data: { user } }) {
|
||||||
const [create, setCreate] = useState(false)
|
const [create, setCreate] = useState(false)
|
||||||
const [edit, setEdit] = useState(false)
|
const [edit, setEdit] = useState(false)
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { data } = useQuery(USER_FULL(user.name), {
|
const { data } = useQuery(USER_FULL, { variables: { name: user.name } })
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
({ user } = data)
|
({ user } = data)
|
|
@ -0,0 +1,29 @@
|
||||||
|
import Layout from '../../components/layout'
|
||||||
|
import { useQuery } from '@apollo/client'
|
||||||
|
import UserHeader from '../../components/user-header'
|
||||||
|
import Seo from '../../components/seo'
|
||||||
|
import Items from '../../components/items'
|
||||||
|
import { USER_WITH_POSTS } from '../../fragments/users'
|
||||||
|
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||||
|
|
||||||
|
export const getServerSideProps = getGetServerSideProps(USER_WITH_POSTS, { sort: 'user' })
|
||||||
|
|
||||||
|
export default function UserPosts ({ data: { user, moreItems: { items, cursor } } }) {
|
||||||
|
const { data } = useQuery(USER_WITH_POSTS,
|
||||||
|
{ variables: { name: user.name, sort: 'user' } })
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
({ user, moreItems: { items, cursor } } = data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout noSeo>
|
||||||
|
<Seo user={user} />
|
||||||
|
<UserHeader user={user} />
|
||||||
|
<Items
|
||||||
|
items={items} cursor={cursor}
|
||||||
|
variables={{ sort: 'user', name: user.name }}
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
|
@ -1,64 +0,0 @@
|
||||||
import Layout from '../../components/layout'
|
|
||||||
import { useQuery } from '@apollo/client'
|
|
||||||
import UserHeader from '../../components/user-header'
|
|
||||||
import CommentsFlat from '../../components/comments-flat'
|
|
||||||
import Seo from '../../components/seo'
|
|
||||||
import { USER_FULL } from '../../fragments/users'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { MORE_FLAT_COMMENTS } from '../../fragments/comments'
|
|
||||||
import { getServerSideProps as headerProps } from './index'
|
|
||||||
import getSSRApolloClient from '../../api/ssrApollo'
|
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { username } }) {
|
|
||||||
const { notFound, props } = await headerProps({ req, params: { username } })
|
|
||||||
|
|
||||||
if (notFound) {
|
|
||||||
return {
|
|
||||||
notFound
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { user } = props
|
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: MORE_FLAT_COMMENTS,
|
|
||||||
variables: { userId: user.id }
|
|
||||||
})
|
|
||||||
|
|
||||||
let comments, cursor
|
|
||||||
if (data) {
|
|
||||||
({ moreFlatComments: { comments, cursor } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
comments,
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UserComments ({ user, comments, cursor }) {
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { data } = useQuery(
|
|
||||||
USER_FULL(user.name), {
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
({ user } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout noSeo>
|
|
||||||
<Seo user={user} />
|
|
||||||
<UserHeader user={user} />
|
|
||||||
<CommentsFlat
|
|
||||||
comments={comments} cursor={cursor}
|
|
||||||
variables={{ userId: user.id }} includeParent noReply
|
|
||||||
/>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
import Layout from '../../components/layout'
|
|
||||||
import { useQuery } from '@apollo/client'
|
|
||||||
import UserHeader from '../../components/user-header'
|
|
||||||
import Seo from '../../components/seo'
|
|
||||||
import Items from '../../components/items'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { USER_FULL } from '../../fragments/users'
|
|
||||||
import { getServerSideProps as headerProps } from './index'
|
|
||||||
import getSSRApolloClient from '../../api/ssrApollo'
|
|
||||||
import { MORE_ITEMS } from '../../fragments/items'
|
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { username } }) {
|
|
||||||
const { notFound, props } = await headerProps({ req, params: { username } })
|
|
||||||
|
|
||||||
if (notFound) {
|
|
||||||
return {
|
|
||||||
notFound
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { user } = props
|
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: MORE_ITEMS,
|
|
||||||
variables: { sort: 'user', userId: user.id }
|
|
||||||
})
|
|
||||||
|
|
||||||
let items, cursor
|
|
||||||
if (data) {
|
|
||||||
({ moreItems: { items, cursor } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
items,
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function UserPosts ({ user, items, cursor }) {
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const { data } = useQuery(
|
|
||||||
USER_FULL(user.name), {
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
({ user } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout noSeo>
|
|
||||||
<Seo user={user} />
|
|
||||||
<UserHeader user={user} />
|
|
||||||
<Items
|
|
||||||
items={items} cursor={cursor}
|
|
||||||
variables={{ sort: 'user', userId: user.id }}
|
|
||||||
/>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,33 +1,34 @@
|
||||||
import '../styles/globals.scss'
|
import '../styles/globals.scss'
|
||||||
import { ApolloProvider } from '@apollo/client'
|
import { ApolloProvider, gql } from '@apollo/client'
|
||||||
import { Provider } from 'next-auth/client'
|
import { Provider } from 'next-auth/client'
|
||||||
import { FundErrorModal, FundErrorProvider } from '../components/fund-error'
|
import { FundErrorModal, FundErrorProvider } from '../components/fund-error'
|
||||||
import { MeProvider } from '../components/me'
|
import { MeProvider } from '../components/me'
|
||||||
import PlausibleProvider from 'next-plausible'
|
import PlausibleProvider from 'next-plausible'
|
||||||
import { LightningProvider } from '../components/lightning'
|
import { LightningProvider } from '../components/lightning'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import { useEffect } from 'react'
|
|
||||||
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
||||||
import getApolloClient from '../lib/apollo'
|
import getApolloClient from '../lib/apollo'
|
||||||
|
|
||||||
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
||||||
const router = useRouter()
|
const client = getApolloClient()
|
||||||
|
/*
|
||||||
useEffect(() => {
|
If we are on the client, we populate the apollo cache with the
|
||||||
router.beforePopState(({ url, as, options }) => {
|
ssr data
|
||||||
// we need to tell the next page to use a cache-first fetch policy ...
|
*/
|
||||||
// so that scroll position can be maintained
|
if (typeof window !== 'undefined') {
|
||||||
const fullurl = new URL(url, 'https://stacker.news')
|
const { apollo, data } = props
|
||||||
fullurl.searchParams.set('cache', true)
|
if (apollo) {
|
||||||
router.push(`${fullurl.pathname}${fullurl.search}`, as, options)
|
client.writeQuery({
|
||||||
return false
|
query: gql`${apollo.query}`,
|
||||||
|
data: data,
|
||||||
|
variables: apollo.variables
|
||||||
})
|
})
|
||||||
}, [])
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlausibleProvider domain='stacker.news' trackOutboundLinks>
|
<PlausibleProvider domain='stacker.news' trackOutboundLinks>
|
||||||
<Provider session={session}>
|
<Provider session={session}>
|
||||||
<ApolloProvider client={getApolloClient()}>
|
<ApolloProvider client={client}>
|
||||||
<MeProvider>
|
<MeProvider>
|
||||||
<LightningProvider>
|
<LightningProvider>
|
||||||
<FundErrorProvider>
|
<FundErrorProvider>
|
||||||
|
|
|
@ -1,36 +1,17 @@
|
||||||
import Layout from '../components/layout'
|
import Layout from '../components/layout'
|
||||||
import Items from '../components/items'
|
import Items from '../components/items'
|
||||||
import { useRouter } from 'next/router'
|
import { getGetServerSideProps } from '../api/ssrApollo'
|
||||||
import getSSRApolloClient from '../api/ssrApollo'
|
|
||||||
import { MORE_ITEMS } from '../fragments/items'
|
import { MORE_ITEMS } from '../fragments/items'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req }) {
|
const variables = { sort: 'hot' }
|
||||||
const client = await getSSRApolloClient(req)
|
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, variables)
|
||||||
const { data } = await client.query({
|
|
||||||
query: MORE_ITEMS,
|
|
||||||
variables: { sort: 'hot' }
|
|
||||||
})
|
|
||||||
|
|
||||||
let items, cursor
|
export default function Index ({ data: { moreItems: { items, cursor } } }) {
|
||||||
if (data) {
|
|
||||||
({ moreItems: { items, cursor } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
items,
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Index ({ items, cursor }) {
|
|
||||||
const router = useRouter()
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Items
|
<Items
|
||||||
items={items} cursor={cursor}
|
items={items} cursor={cursor}
|
||||||
variables={{ sort: 'hot' }} rank key={router.query.key}
|
variables={variables} rank
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
|
@ -148,7 +148,7 @@ export default function Invites () {
|
||||||
...InviteFields
|
...InviteFields
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`)
|
`, { fetchPolicy: 'cache-and-network' })
|
||||||
|
|
||||||
const [active, inactive] = data && data.invites
|
const [active, inactive] = data && data.invites
|
||||||
? data.invites.reduce((result, invite) => {
|
? data.invites.reduce((result, invite) => {
|
||||||
|
|
|
@ -1,38 +1,24 @@
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import gql from 'graphql-tag'
|
|
||||||
import { Invoice } from '../../components/invoice'
|
import { Invoice } from '../../components/invoice'
|
||||||
import { LnQRSkeleton } from '../../components/lnqr'
|
import { LnQRSkeleton } from '../../components/lnqr'
|
||||||
import LayoutCenter from '../../components/layout-center'
|
import LayoutCenter from '../../components/layout-center'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { INVOICE } from '../../fragments/wallet'
|
||||||
|
|
||||||
export async function getServerSideProps ({ params: { id } }) {
|
export default function FullInvoice () {
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FullInvoice ({ id }) {
|
|
||||||
const query = gql`
|
|
||||||
{
|
|
||||||
invoice(id: ${id}) {
|
|
||||||
id
|
|
||||||
bolt11
|
|
||||||
msatsReceived
|
|
||||||
cancelled
|
|
||||||
confirmedAt
|
|
||||||
expiresAt
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
return (
|
return (
|
||||||
<LayoutCenter>
|
<LayoutCenter>
|
||||||
<LoadInvoice query={query} />
|
<LoadInvoice />
|
||||||
</LayoutCenter>
|
</LayoutCenter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function LoadInvoice ({ query }) {
|
function LoadInvoice () {
|
||||||
const { loading, error, data } = useQuery(query, { pollInterval: 1000 })
|
const router = useRouter()
|
||||||
|
const { loading, error, data } = useQuery(INVOICE, {
|
||||||
|
pollInterval: 1000,
|
||||||
|
variables: { id: router.query.id }
|
||||||
|
})
|
||||||
if (error) return <div>error</div>
|
if (error) return <div>error</div>
|
||||||
if (!data || loading) {
|
if (!data || loading) {
|
||||||
return <LnQRSkeleton status='loading' />
|
return <LnQRSkeleton status='loading' />
|
||||||
|
|
|
@ -1,38 +1,12 @@
|
||||||
import { ITEM_FIELDS } from '../../../fragments/items'
|
import { ITEM } from '../../../fragments/items'
|
||||||
import { gql } from '@apollo/client'
|
import { getGetServerSideProps } from '../../../api/ssrApollo'
|
||||||
import getSSRApolloClient from '../../../api/ssrApollo'
|
|
||||||
import { DiscussionForm } from '../../../components/discussion-form'
|
import { DiscussionForm } from '../../../components/discussion-form'
|
||||||
import { LinkForm } from '../../../components/link-form'
|
import { LinkForm } from '../../../components/link-form'
|
||||||
import LayoutCenter from '../../../components/layout-center'
|
import LayoutCenter from '../../../components/layout-center'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { id } }) {
|
export const getServerSideProps = getGetServerSideProps(ITEM)
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
const { error, data: { item } } = await client.query({
|
|
||||||
query:
|
|
||||||
gql`
|
|
||||||
${ITEM_FIELDS}
|
|
||||||
{
|
|
||||||
item(id: ${id}) {
|
|
||||||
...ItemFields
|
|
||||||
text
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error || !item) {
|
export default function PostEdit ({ data: { item } }) {
|
||||||
return {
|
|
||||||
notFound: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PostEdit ({ item }) {
|
|
||||||
const editThreshold = new Date(item.createdAt).getTime() + 10 * 60000
|
const editThreshold = new Date(item.createdAt).getTime() + 10 * 60000
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -2,39 +2,14 @@ import Layout from '../../../components/layout'
|
||||||
import { ITEM_FULL } from '../../../fragments/items'
|
import { ITEM_FULL } from '../../../fragments/items'
|
||||||
import Seo from '../../../components/seo'
|
import Seo from '../../../components/seo'
|
||||||
import ItemFull from '../../../components/item-full'
|
import ItemFull from '../../../components/item-full'
|
||||||
import getSSRApolloClient from '../../../api/ssrApollo'
|
import { getGetServerSideProps } from '../../../api/ssrApollo'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { id } }) {
|
export const getServerSideProps = getGetServerSideProps(ITEM_FULL)
|
||||||
if (isNaN(id)) {
|
|
||||||
return {
|
|
||||||
notFound: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = await getSSRApolloClient(req)
|
export default function AnItem ({ data: { item } }) {
|
||||||
const { error, data } = await client.query({
|
const { data } = useQuery(ITEM_FULL, {
|
||||||
query: ITEM_FULL(id)
|
variables: { id: item.id }
|
||||||
})
|
|
||||||
|
|
||||||
if (error || !data?.item) {
|
|
||||||
return {
|
|
||||||
notFound: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
item: data.item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AnItem ({ item }) {
|
|
||||||
const router = useRouter()
|
|
||||||
const { data } = useQuery(ITEM_FULL(item.id), {
|
|
||||||
fetchPolicy: router.query.cache ? 'cache-first' : undefined
|
|
||||||
})
|
})
|
||||||
if (data) {
|
if (data) {
|
||||||
({ item } = data)
|
({ item } = data)
|
||||||
|
|
|
@ -1,36 +1,16 @@
|
||||||
import { useRouter } from 'next/router'
|
import { getGetServerSideProps } from '../api/ssrApollo'
|
||||||
import getSSRApolloClient from '../api/ssrApollo'
|
|
||||||
import Layout from '../components/layout'
|
import Layout from '../components/layout'
|
||||||
import Notifications from '../components/notifications'
|
import Notifications from '../components/notifications'
|
||||||
import { NOTIFICATIONS } from '../fragments/notifications'
|
import { NOTIFICATIONS } from '../fragments/notifications'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req }) {
|
export const getServerSideProps = getGetServerSideProps(NOTIFICATIONS)
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: NOTIFICATIONS
|
|
||||||
})
|
|
||||||
|
|
||||||
let notifications, cursor, lastChecked
|
export default function NotificationPage ({ data: { notifications: { notifications, cursor, lastChecked } } }) {
|
||||||
if (data) {
|
|
||||||
({ notifications: { notifications, cursor, lastChecked } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
notifications,
|
|
||||||
cursor,
|
|
||||||
lastChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function NotificationPage ({ notifications, cursor, lastChecked }) {
|
|
||||||
const router = useRouter()
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Notifications
|
<Notifications
|
||||||
notifications={notifications} cursor={cursor}
|
notifications={notifications} cursor={cursor}
|
||||||
lastChecked={lastChecked} key={router.query.key}
|
lastChecked={lastChecked}
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,12 +6,6 @@ import { useMe } from '../components/me'
|
||||||
import { DiscussionForm } from '../components/discussion-form'
|
import { DiscussionForm } from '../components/discussion-form'
|
||||||
import { LinkForm } from '../components/link-form'
|
import { LinkForm } from '../components/link-form'
|
||||||
|
|
||||||
export async function getServerSideProps () {
|
|
||||||
return {
|
|
||||||
props: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PostForm () {
|
export function PostForm () {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
|
@ -1,36 +1,17 @@
|
||||||
import Layout from '../components/layout'
|
import Layout from '../components/layout'
|
||||||
import Items from '../components/items'
|
import Items from '../components/items'
|
||||||
import { useRouter } from 'next/router'
|
import { getGetServerSideProps } from '../api/ssrApollo'
|
||||||
import getSSRApolloClient from '../api/ssrApollo'
|
|
||||||
import { MORE_ITEMS } from '../fragments/items'
|
import { MORE_ITEMS } from '../fragments/items'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req }) {
|
const variables = { sort: 'recent' }
|
||||||
const client = await getSSRApolloClient(req)
|
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, { sort: 'recent' })
|
||||||
const { data } = await client.query({
|
|
||||||
query: MORE_ITEMS,
|
|
||||||
variables: { sort: 'recent' }
|
|
||||||
})
|
|
||||||
|
|
||||||
let items, cursor
|
export default function Index ({ data: { moreItems: { items, cursor } } }) {
|
||||||
if (data) {
|
|
||||||
({ moreItems: { items, cursor } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
items,
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Index ({ items, cursor }) {
|
|
||||||
const router = useRouter()
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Items
|
<Items
|
||||||
items={items} cursor={cursor}
|
items={items} cursor={cursor}
|
||||||
variables={{ sort: 'recent' }} rank key={router.query.key}
|
variables={variables} rank
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,34 +1,15 @@
|
||||||
import Layout from '../../components/layout'
|
import Layout from '../../components/layout'
|
||||||
import Items from '../../components/items'
|
import Items from '../../components/items'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import getSSRApolloClient from '../../api/ssrApollo'
|
import { getGetServerSideProps } from '../../api/ssrApollo'
|
||||||
import { MORE_ITEMS } from '../../fragments/items'
|
import { MORE_ITEMS } from '../../fragments/items'
|
||||||
import { Nav, Navbar } from 'react-bootstrap'
|
import { Nav, Navbar } from 'react-bootstrap'
|
||||||
import styles from '../../components/header.module.css'
|
import styles from '../../components/header.module.css'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
|
||||||
export async function getServerSideProps ({ req, params: { within } }) {
|
export const getServerSideProps = getGetServerSideProps(MORE_ITEMS, { sort: 'top'})
|
||||||
const client = await getSSRApolloClient(req)
|
|
||||||
console.log('called')
|
|
||||||
const { data } = await client.query({
|
|
||||||
query: MORE_ITEMS,
|
|
||||||
variables: { sort: 'top', within: within?.pop() }
|
|
||||||
})
|
|
||||||
|
|
||||||
let items, cursor
|
export default function Index ({ data: { moreItems: { items, cursor } } }) {
|
||||||
if (data) {
|
|
||||||
({ moreItems: { items, cursor } } = data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
items,
|
|
||||||
cursor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Index ({ items, cursor }) {
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const path = router.asPath.split('?')[0]
|
const path = router.asPath.split('?')[0]
|
||||||
|
|
||||||
|
@ -88,7 +69,7 @@ export default function Index ({ items, cursor }) {
|
||||||
</Navbar>
|
</Navbar>
|
||||||
<Items
|
<Items
|
||||||
items={items} cursor={cursor}
|
items={items} cursor={cursor}
|
||||||
variables={{ sort: 'top', within: router.query?.within?.pop() }} rank key={router.query.key}
|
variables={{ sort: 'top', within: router.query?.within }} rank
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,12 +13,6 @@ import { useEffect, useState } from 'react'
|
||||||
import { requestProvider } from 'webln'
|
import { requestProvider } from 'webln'
|
||||||
import { Alert } from 'react-bootstrap'
|
import { Alert } from 'react-bootstrap'
|
||||||
|
|
||||||
export async function getServerSideProps () {
|
|
||||||
return {
|
|
||||||
props: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Wallet () {
|
export default function Wallet () {
|
||||||
return (
|
return (
|
||||||
<LayoutCenter>
|
<LayoutCenter>
|
||||||
|
|
|
@ -1,32 +1,15 @@
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import gql from 'graphql-tag'
|
|
||||||
import LayoutCenter from '../../components/layout-center'
|
import LayoutCenter from '../../components/layout-center'
|
||||||
import { CopyInput, Input, InputSkeleton } from '../../components/form'
|
import { CopyInput, Input, InputSkeleton } from '../../components/form'
|
||||||
import InputGroup from 'react-bootstrap/InputGroup'
|
import InputGroup from 'react-bootstrap/InputGroup'
|
||||||
import InvoiceStatus from '../../components/invoice-status'
|
import InvoiceStatus from '../../components/invoice-status'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { WITHDRAWL } from '../../fragments/wallet'
|
||||||
|
|
||||||
export async function getServerSideProps ({ params: { id } }) {
|
export default function Withdrawl () {
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Withdrawl ({ id }) {
|
|
||||||
const query = gql`
|
|
||||||
{
|
|
||||||
withdrawl(id: ${id}) {
|
|
||||||
bolt11
|
|
||||||
satsPaid
|
|
||||||
satsFeePaying
|
|
||||||
satsFeePaid
|
|
||||||
status
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
return (
|
return (
|
||||||
<LayoutCenter>
|
<LayoutCenter>
|
||||||
<LoadWithdrawl query={query} />
|
<LoadWithdrawl />
|
||||||
</LayoutCenter>
|
</LayoutCenter>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -45,8 +28,12 @@ export function WithdrawlSkeleton ({ status }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function LoadWithdrawl ({ query }) {
|
function LoadWithdrawl () {
|
||||||
const { loading, error, data } = useQuery(query, { pollInterval: 1000 })
|
const router = useRouter()
|
||||||
|
const { loading, error, data } = useQuery(WITHDRAWL, {
|
||||||
|
variables: { id: router.query.id },
|
||||||
|
pollInterval: 1000
|
||||||
|
})
|
||||||
if (error) return <div>error</div>
|
if (error) return <div>error</div>
|
||||||
if (!data || loading) {
|
if (!data || loading) {
|
||||||
return <WithdrawlSkeleton status='loading' />
|
return <WithdrawlSkeleton status='loading' />
|
||||||
|
|
Loading…
Reference in New Issue