sort by top posts
This commit is contained in:
parent
cd61263159
commit
68ddd0f86b
@ -34,9 +34,10 @@ export async function getItem (parent, { id }, { models }) {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
Query: {
|
Query: {
|
||||||
moreItems: async (parent, { sort, cursor, userId }, { me, models }) => {
|
moreItems: async (parent, { sort, cursor, userId, within }, { me, models }) => {
|
||||||
const decodedCursor = decodeCursor(cursor)
|
const decodedCursor = decodeCursor(cursor)
|
||||||
let items
|
let items
|
||||||
|
let interval = 'INTERVAL '
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case 'user':
|
case 'user':
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
@ -77,6 +78,32 @@ export default {
|
|||||||
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
case 'top':
|
||||||
|
switch (within) {
|
||||||
|
case 'day':
|
||||||
|
interval += "'1 day'"
|
||||||
|
break
|
||||||
|
case 'week':
|
||||||
|
interval += "'7 days'"
|
||||||
|
break
|
||||||
|
case 'month':
|
||||||
|
interval += "'1 month'"
|
||||||
|
break
|
||||||
|
case 'year':
|
||||||
|
interval += "'1 year'"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
items = await models.$queryRaw(`
|
||||||
|
${SELECT}
|
||||||
|
FROM "Item"
|
||||||
|
${timedLeftJoinSats(1)}
|
||||||
|
WHERE "parentId" IS NULL AND created_at <= $1
|
||||||
|
${within ? ` AND created_at >= $1 - ${interval}` : ''}
|
||||||
|
ORDER BY x.sats DESC NULLS LAST, created_at DESC
|
||||||
|
OFFSET $2
|
||||||
|
LIMIT ${LIMIT}`, decodedCursor.time, decodedCursor.offset)
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
items = await models.$queryRaw(`
|
items = await models.$queryRaw(`
|
||||||
${SELECT}
|
${SELECT}
|
||||||
|
@ -2,7 +2,7 @@ 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): Items
|
moreItems(sort: String!, cursor: String, userId: ID, within: String): Items
|
||||||
moreFlatComments(cursor: String, userId: ID): Comments
|
moreFlatComments(cursor: String, userId: ID): Comments
|
||||||
item(id: ID!): Item
|
item(id: ID!): Item
|
||||||
userComments(userId: ID!): [Item!]
|
userComments(userId: ID!): [Item!]
|
||||||
|
@ -3,13 +3,13 @@ import Nav from 'react-bootstrap/Nav'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import styles from './header.module.css'
|
import styles from './header.module.css'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { Button, Container, NavDropdown } from 'react-bootstrap'
|
import { Button, Container, NavDropdown, SplitButton, Dropdown } from 'react-bootstrap'
|
||||||
import Price from './price'
|
import Price from './price'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import { signOut, signIn, useSession } from 'next-auth/client'
|
import { signOut, signIn, useSession } from 'next-auth/client'
|
||||||
import { useLightning } from './lightning'
|
import { useLightning } from './lightning'
|
||||||
import { useEffect } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '../lib/rand'
|
||||||
|
|
||||||
function WalletSummary ({ me }) {
|
function WalletSummary ({ me }) {
|
||||||
@ -31,6 +31,17 @@ export default function Header () {
|
|||||||
const path = router.asPath.split('?')[0]
|
const path = router.asPath.split('?')[0]
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const [session, loading] = useSession()
|
const [session, loading] = useSession()
|
||||||
|
const [sort, setSort] = useState('recent')
|
||||||
|
const [within, setWithin] = useState()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSort(localStorage.getItem('sort') || 'recent')
|
||||||
|
setWithin(localStorage.getItem('topWithin'))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const otherSort = sort === 'recent' ? 'top' : 'recent'
|
||||||
|
const sortLink = `/${sort}${sort === 'top' && within ? `/${within}` : ''}`
|
||||||
|
const otherSortLink = `/${otherSort}${otherSort === 'top' && within ? `/${within}` : ''}`
|
||||||
|
|
||||||
const Corner = () => {
|
const Corner = () => {
|
||||||
if (me) {
|
if (me) {
|
||||||
@ -76,6 +87,9 @@ export default function Header () {
|
|||||||
<RefreshableLink href='/recent' passHref>
|
<RefreshableLink href='/recent' passHref>
|
||||||
<NavDropdown.Item>recent</NavDropdown.Item>
|
<NavDropdown.Item>recent</NavDropdown.Item>
|
||||||
</RefreshableLink>
|
</RefreshableLink>
|
||||||
|
<RefreshableLink href={`/top${within ? `/${within}` : ''}`} passHref>
|
||||||
|
<NavDropdown.Item>top</NavDropdown.Item>
|
||||||
|
</RefreshableLink>
|
||||||
{me
|
{me
|
||||||
? (
|
? (
|
||||||
<Link href='/post' passHref>
|
<Link href='/post' passHref>
|
||||||
@ -131,10 +145,22 @@ export default function Header () {
|
|||||||
<RefreshableLink href='/' passHref>
|
<RefreshableLink 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>
|
</RefreshableLink>
|
||||||
<Nav.Item className='d-md-flex d-none'>
|
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
||||||
<RefreshableLink href='/recent' passHref>
|
<SplitButton
|
||||||
<Nav.Link className={styles.navLink}>recent</Nav.Link>
|
title={
|
||||||
</RefreshableLink>
|
<RefreshableLink href={sortLink} passHref>
|
||||||
|
<Nav.Link className={styles.navLink}>{sort}</Nav.Link>
|
||||||
|
</RefreshableLink>
|
||||||
|
}
|
||||||
|
key={`/${sort}`}
|
||||||
|
id='recent-top-button'
|
||||||
|
variant='link'
|
||||||
|
className='p-0'
|
||||||
|
>
|
||||||
|
<Link href={otherSortLink} passHref>
|
||||||
|
<Dropdown.Item onClick={() => localStorage.setItem('sort', otherSort)}>{otherSort}</Dropdown.Item>
|
||||||
|
</Link>
|
||||||
|
</SplitButton>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item className='d-md-flex d-none'>
|
<Nav.Item className='d-md-flex d-none'>
|
||||||
{me
|
{me
|
||||||
|
@ -9,14 +9,14 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5431:5432"
|
- "5431:5432"
|
||||||
env_file:
|
env_file:
|
||||||
- .env.sample
|
- ./.env.sample
|
||||||
app:
|
app:
|
||||||
container_name: app
|
container_name: app
|
||||||
build: ./
|
build: ./
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
env_file:
|
env_file:
|
||||||
- .env.sample
|
- ./.env.sample
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -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) {
|
query MoreItems($sort: String!, $cursor: String, $userId: ID, $within: String) {
|
||||||
moreItems(sort: $sort, cursor: $cursor, userId: $userId) {
|
moreItems(sort: $sort, cursor: $cursor, userId: $userId, within: $within) {
|
||||||
cursor
|
cursor
|
||||||
items {
|
items {
|
||||||
...ItemFields
|
...ItemFields
|
||||||
|
@ -26,7 +26,7 @@ export default function getApolloClient () {
|
|||||||
Query: {
|
Query: {
|
||||||
fields: {
|
fields: {
|
||||||
moreItems: {
|
moreItems: {
|
||||||
keyArgs: ['sort', 'userId'],
|
keyArgs: ['sort', 'userId', 'within'],
|
||||||
merge (existing, incoming) {
|
merge (existing, incoming) {
|
||||||
if (isFirstPage(incoming.cursor, existing)) {
|
if (isFirstPage(incoming.cursor, existing)) {
|
||||||
return incoming
|
return incoming
|
||||||
|
11683
package-lock.json
generated
11683
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,6 @@ export async function getServerSideProps ({ req, res, query: { id, error = null
|
|||||||
}
|
}
|
||||||
|
|
||||||
function InviteHeader ({ invite }) {
|
function InviteHeader ({ invite }) {
|
||||||
console.log(invite.poor)
|
|
||||||
let Inner
|
let Inner
|
||||||
if (invite.revoked) {
|
if (invite.revoked) {
|
||||||
Inner = () => <div className='text-danger'>this invite link expired</div>
|
Inner = () => <div className='text-danger'>this invite link expired</div>
|
||||||
|
94
pages/top/[[...within]].js
Normal file
94
pages/top/[[...within]].js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import Layout from '../../components/layout'
|
||||||
|
import Items from '../../components/items'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import getSSRApolloClient from '../../api/ssrApollo'
|
||||||
|
import { MORE_ITEMS } from '../../fragments/items'
|
||||||
|
import { Nav, Navbar } from 'react-bootstrap'
|
||||||
|
import styles from '../../components/header.module.css'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export async function getServerSideProps ({ req }) {
|
||||||
|
const client = await getSSRApolloClient(req)
|
||||||
|
const { data } = await client.query({
|
||||||
|
query: MORE_ITEMS,
|
||||||
|
variables: { sort: 'top', within: req.query?.within?.pop() }
|
||||||
|
})
|
||||||
|
|
||||||
|
let items, cursor
|
||||||
|
if (data) {
|
||||||
|
({ moreItems: { items, cursor } } = data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
items,
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Index ({ items, cursor }) {
|
||||||
|
const router = useRouter()
|
||||||
|
const path = router.asPath.split('?')[0]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<Navbar className={styles.navbar}>
|
||||||
|
<Nav
|
||||||
|
className={styles.navbarNav}
|
||||||
|
activeKey={path}
|
||||||
|
>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href='/top/day' passHref>
|
||||||
|
<Nav.Link
|
||||||
|
className={styles.navLink}
|
||||||
|
onClick={() => localStorage.setItem('topWithin', 'day')}>
|
||||||
|
day
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href='/top/week' passHref>
|
||||||
|
<Nav.Link
|
||||||
|
className={styles.navLink}
|
||||||
|
onClick={() => localStorage.setItem('topWithin', 'week')}>
|
||||||
|
week
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href='/top/month' passHref>
|
||||||
|
<Nav.Link
|
||||||
|
className={styles.navLink}
|
||||||
|
onClick={() => localStorage.setItem('topWithin', 'month')}>
|
||||||
|
month
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href='/top/year' passHref>
|
||||||
|
<Nav.Link
|
||||||
|
className={styles.navLink}
|
||||||
|
onClick={() => localStorage.setItem('topWithin', 'year')}>
|
||||||
|
year
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
<Nav.Item>
|
||||||
|
<Link href='/top' passHref>
|
||||||
|
<Nav.Link
|
||||||
|
className={styles.navLink}
|
||||||
|
onClick={() => localStorage.removeItem('topWithin')}>
|
||||||
|
forever
|
||||||
|
</Nav.Link>
|
||||||
|
</Link>
|
||||||
|
</Nav.Item>
|
||||||
|
</Nav>
|
||||||
|
</Navbar>
|
||||||
|
<Items
|
||||||
|
items={items} cursor={cursor}
|
||||||
|
variables={{ sort: 'top', within: router.query?.within?.pop() }} rank key={router.query.key}
|
||||||
|
/>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
@ -129,6 +129,32 @@ footer {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .dropdown-toggle::after {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .btn-link {
|
||||||
|
color: rgba(0, 0, 0, 0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .btn-link[aria-expanded="true"] {
|
||||||
|
color: rgba(0, 0, 0, 0.9) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .dropdown .btn {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .dropdown .dropdown-toggle {
|
||||||
|
padding-left: .75rem;
|
||||||
|
padding-right: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-dropdown-toggle .nav-link {
|
||||||
|
padding-right: 0 !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown-toggle::after {
|
.dropdown-toggle::after {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user