maintage pagination and other state on back button
This commit is contained in:
parent
1a0803a594
commit
7efc86427d
|
@ -169,9 +169,7 @@ export default {
|
|||
throw new AuthenticationError('you must be logged in')
|
||||
}
|
||||
|
||||
await models.user.update({ where: { id: me.id }, data })
|
||||
|
||||
return true
|
||||
return await models.user.update({ where: { id: me.id }, data })
|
||||
},
|
||||
setWalkthrough: async (parent, { upvotePopover, tipPopover }, { me, models }) => {
|
||||
if (!me) {
|
||||
|
|
|
@ -35,8 +35,20 @@ export default async function getSSRApolloClient (req, me = null) {
|
|||
|
||||
export function getGetServerSideProps (query, variables = null, notFoundFunc, requireVar) {
|
||||
return async function ({ req, query: params }) {
|
||||
const client = await getSSRApolloClient(req)
|
||||
const vars = { ...params, ...variables }
|
||||
const { nodata, ...realParams } = params
|
||||
const vars = { ...realParams, ...variables }
|
||||
|
||||
// we want to use client-side cache
|
||||
if (nodata && query) {
|
||||
return {
|
||||
props: {
|
||||
apollo: {
|
||||
query: print(query),
|
||||
variables: vars
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requireVar && !vars[requireVar]) {
|
||||
return {
|
||||
|
@ -44,6 +56,7 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re
|
|||
}
|
||||
}
|
||||
|
||||
const client = await getSSRApolloClient(req)
|
||||
let error = null; let data = null; let props = {}
|
||||
if (query) {
|
||||
({ error, data } = await client.query({
|
||||
|
@ -60,7 +73,7 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re
|
|||
props = {
|
||||
apollo: {
|
||||
query: print(query),
|
||||
variables: { ...params, ...variables }
|
||||
variables: vars
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export default gql`
|
|||
setName(name: String!): Boolean
|
||||
setSettings(tipDefault: Int!, noteItemSats: Boolean!, noteEarning: Boolean!,
|
||||
noteAllDescendants: Boolean!, noteMentions: Boolean!, noteDeposits: Boolean!,
|
||||
noteInvites: Boolean!, noteJobIndicator: Boolean!, hideInvoiceDesc: Boolean!): Boolean
|
||||
noteInvites: Boolean!, noteJobIndicator: Boolean!, hideInvoiceDesc: Boolean!): User
|
||||
setPhoto(photoId: ID!): Int!
|
||||
upsertBio(bio: String!): User!
|
||||
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
|
||||
|
|
|
@ -96,9 +96,11 @@ export default function UserHeader ({ user }) {
|
|||
if (error) {
|
||||
throw new Error({ message: error.toString() })
|
||||
}
|
||||
|
||||
const { nodata, ...query } = router.query
|
||||
router.replace({
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, name }
|
||||
query: { ...query, name }
|
||||
})
|
||||
|
||||
client.writeFragment({
|
||||
|
|
|
@ -54,9 +54,8 @@ export const ME_SSR = gql`
|
|||
}
|
||||
}`
|
||||
|
||||
export const SETTINGS = gql`
|
||||
{
|
||||
settings {
|
||||
export const SETTINGS_FIELDS = gql`
|
||||
fragment SettingsFields on User {
|
||||
tipDefault
|
||||
noteItemSats
|
||||
noteEarning
|
||||
|
@ -72,9 +71,31 @@ export const SETTINGS = gql`
|
|||
twitter
|
||||
github
|
||||
}
|
||||
}`
|
||||
|
||||
export const SETTINGS = gql`
|
||||
${SETTINGS_FIELDS}
|
||||
{
|
||||
settings {
|
||||
...SettingsFields
|
||||
}
|
||||
}`
|
||||
|
||||
export const SET_SETTINGS =
|
||||
gql`
|
||||
${SETTINGS_FIELDS}
|
||||
mutation setSettings($tipDefault: Int!, $noteItemSats: Boolean!, $noteEarning: Boolean!,
|
||||
$noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!,
|
||||
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $hideInvoiceDesc: Boolean!) {
|
||||
setSettings(tipDefault: $tipDefault, noteItemSats: $noteItemSats,
|
||||
noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
|
||||
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
|
||||
noteJobIndicator: $noteJobIndicator, hideInvoiceDesc: $hideInvoiceDesc) {
|
||||
...SettingsFields
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const NAME_QUERY =
|
||||
gql`
|
||||
query nameAvailable($name: String!) {
|
||||
|
@ -164,6 +185,11 @@ export const USER_WITH_POSTS = gql`
|
|||
cursor
|
||||
items {
|
||||
...ItemFields
|
||||
position
|
||||
}
|
||||
pins {
|
||||
...ItemFields
|
||||
position
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
|
|
@ -79,7 +79,7 @@ export default function getApolloClient () {
|
|||
}
|
||||
},
|
||||
notifications: {
|
||||
keyArgs: false,
|
||||
keyArgs: ['inc'],
|
||||
merge (existing, incoming) {
|
||||
if (isFirstPage(incoming.cursor, existing?.notifications)) {
|
||||
return incoming
|
||||
|
|
|
@ -10,7 +10,7 @@ export const getServerSideProps = getGetServerSideProps(USER_WITH_POSTS)
|
|||
|
||||
export default function UserPosts ({ data: { user, items: { items, cursor } } }) {
|
||||
const { data } = useQuery(USER_WITH_POSTS,
|
||||
{ variables: { name: user.name } })
|
||||
{ variables: { name: user.name, sort: 'user' } })
|
||||
|
||||
if (data) {
|
||||
({ user, items: { items, cursor } } = data)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import '../styles/globals.scss'
|
||||
import { ApolloProvider, gql } from '@apollo/client'
|
||||
import { ApolloProvider, gql, useQuery } from '@apollo/client'
|
||||
import { Provider } from 'next-auth/client'
|
||||
import { FundErrorModal, FundErrorProvider } from '../components/fund-error'
|
||||
import { MeProvider } from '../components/me'
|
||||
|
@ -10,27 +10,64 @@ import getApolloClient from '../lib/apollo'
|
|||
import NextNProgress from 'nextjs-progressbar'
|
||||
import { PriceProvider } from '../components/price'
|
||||
import Head from 'next/head'
|
||||
import { useRouter } from 'next/dist/client/router'
|
||||
import { useEffect } from 'react'
|
||||
import Moon from '../svgs/moon-fill.svg'
|
||||
import Layout from '../components/layout'
|
||||
|
||||
function CSRWrapper ({ Component, apollo, ...props }) {
|
||||
const { data, error } = useQuery(gql`${apollo.query}`, { variables: apollo.variables, fetchPolicy: 'cache-first' })
|
||||
if (error) {
|
||||
return (
|
||||
<div className='d-flex font-weight-bold justify-content-center mt-3 mb-1'>
|
||||
{error.toString()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<Layout>
|
||||
<div className='d-flex justify-content-center mt-3 mb-1'>
|
||||
<Moon className='spin fill-grey' />
|
||||
</div>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
return <Component {...props} data={data} />
|
||||
}
|
||||
|
||||
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
||||
const client = getApolloClient()
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(async () => {
|
||||
// HACK: 'cause there's no way to tell Next to skip SSR
|
||||
// So every page load, we modify the route in browser history
|
||||
// to point to the same page but without SSR, ie ?nodata=true
|
||||
// this nodata var will get passed to the server on back/foward and
|
||||
// 1. prevent data from reloading and 2. perserve scroll
|
||||
// (2) is not possible while intercepting nav with beforePopState
|
||||
router.replace({
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, nodata: true }
|
||||
}, router.asPath, { ...router.options, scroll: false })
|
||||
}, [router.asPath])
|
||||
|
||||
/*
|
||||
If we are on the client, we populate the apollo cache with the
|
||||
ssr data
|
||||
*/
|
||||
if (typeof window !== 'undefined') {
|
||||
const { apollo, data } = props
|
||||
if (apollo) {
|
||||
client.writeQuery({
|
||||
query: gql`${apollo.query}`,
|
||||
data: data,
|
||||
variables: apollo.variables
|
||||
})
|
||||
}
|
||||
const { apollo, data, me, price } = props
|
||||
if (typeof window !== 'undefined' && apollo && data) {
|
||||
client.writeQuery({
|
||||
query: gql`${apollo.query}`,
|
||||
data: data,
|
||||
variables: apollo.variables
|
||||
})
|
||||
}
|
||||
|
||||
const { me, price } = props
|
||||
|
||||
return (
|
||||
<>
|
||||
<NextNProgress
|
||||
|
@ -54,7 +91,9 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
|
|||
<FundErrorModal />
|
||||
<ItemActProvider>
|
||||
<ItemActModal />
|
||||
<Component {...props} />
|
||||
{data || !apollo?.query
|
||||
? <Component {...props} />
|
||||
: <CSRWrapper Component={Component} {...props} />}
|
||||
</ItemActProvider>
|
||||
</FundErrorProvider>
|
||||
</LightningProvider>
|
||||
|
|
|
@ -9,7 +9,7 @@ import LoginButton from '../components/login-button'
|
|||
import { signIn } from 'next-auth/client'
|
||||
import ModalButton from '../components/modal-button'
|
||||
import { LightningAuth } from '../components/lightning-auth'
|
||||
import { SETTINGS } from '../fragments/users'
|
||||
import { SETTINGS, SET_SETTINGS } from '../fragments/users'
|
||||
import { useRouter } from 'next/router'
|
||||
import Info from '../components/info'
|
||||
|
||||
|
@ -28,16 +28,18 @@ export const WarningSchema = Yup.object({
|
|||
|
||||
export default function Settings ({ data: { settings } }) {
|
||||
const [success, setSuccess] = useState()
|
||||
const [setSettings] = useMutation(
|
||||
gql`
|
||||
mutation setSettings($tipDefault: Int!, $noteItemSats: Boolean!, $noteEarning: Boolean!,
|
||||
$noteAllDescendants: Boolean!, $noteMentions: Boolean!, $noteDeposits: Boolean!,
|
||||
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $hideInvoiceDesc: Boolean!) {
|
||||
setSettings(tipDefault: $tipDefault, noteItemSats: $noteItemSats,
|
||||
noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
|
||||
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
|
||||
noteJobIndicator: $noteJobIndicator, hideInvoiceDesc: $hideInvoiceDesc)
|
||||
}`
|
||||
const [setSettings] = useMutation(SET_SETTINGS, {
|
||||
update (cache, { data: { setSettings } }) {
|
||||
cache.modify({
|
||||
id: 'ROOT_QUERY',
|
||||
fields: {
|
||||
settings () {
|
||||
return setSettings
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const { data } = useQuery(SETTINGS)
|
||||
|
|
Loading…
Reference in New Issue