ssr me and price
This commit is contained in:
parent
996d0a9352
commit
c7ae5dc8ac
@ -7,6 +7,8 @@ import typeDefs from './typeDefs'
|
|||||||
import models from './models'
|
import models from './models'
|
||||||
import { print } from 'graphql'
|
import { print } from 'graphql'
|
||||||
import lnd from './lnd'
|
import lnd from './lnd'
|
||||||
|
import { ME } from '../fragments/users'
|
||||||
|
import { getPrice } from '../components/price'
|
||||||
|
|
||||||
export default async function getSSRApolloClient (req, me = null) {
|
export default async function getSSRApolloClient (req, me = null) {
|
||||||
const session = req && await getSession({ req })
|
const session = req && await getSession({ req })
|
||||||
@ -41,12 +43,20 @@ export function getGetServerSideProps (query, variables = null, foundField) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { data: { me } } = await client.query({
|
||||||
|
query: ME
|
||||||
|
})
|
||||||
|
|
||||||
|
const price = await getPrice()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
apollo: {
|
apollo: {
|
||||||
query: print(query),
|
query: print(query),
|
||||||
variables: { ...params, ...variables }
|
variables: { ...params, ...variables }
|
||||||
},
|
},
|
||||||
|
me,
|
||||||
|
price,
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import { Button, Container, NavDropdown, SplitButton, Dropdown } from 'react-boo
|
|||||||
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 } from 'next-auth/client'
|
||||||
import { useLightning } from './lightning'
|
import { useLightning } from './lightning'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '../lib/rand'
|
||||||
@ -30,10 +30,8 @@ export default function Header () {
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const path = router.asPath.split('?')[0]
|
const path = router.asPath.split('?')[0]
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const [session, loading] = useSession()
|
|
||||||
const [sort, setSort] = useState('recent')
|
const [sort, setSort] = useState('recent')
|
||||||
const [within, setWithin] = useState()
|
const [within, setWithin] = useState()
|
||||||
const [priceReady, setPriceReady] = useState()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSort(localStorage.getItem('sort') || 'recent')
|
setSort(localStorage.getItem('sort') || 'recent')
|
||||||
@ -127,9 +125,6 @@ export default function Header () {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (loading || session) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
const strike = useLightning()
|
const strike = useLightning()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTimeout(strike, randInRange(3000, 10000))
|
setTimeout(strike, randInRange(3000, 10000))
|
||||||
@ -138,8 +133,6 @@ export default function Header () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const visible = ((session && me) || (!session && !loading)) && priceReady ? 'visible' : 'invisible'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container className='px-sm-0'>
|
<Container className='px-sm-0'>
|
||||||
@ -154,7 +147,7 @@ export default function Header () {
|
|||||||
<Link 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>
|
||||||
</Link>
|
</Link>
|
||||||
<Nav.Item className={`d-md-flex d-none nav-dropdown-toggle ${visible}`}>
|
<Nav.Item className='d-md-flex d-none nav-dropdown-toggle'>
|
||||||
<SplitButton
|
<SplitButton
|
||||||
title={
|
title={
|
||||||
<Link href={sortLink} passHref>
|
<Link href={sortLink} passHref>
|
||||||
@ -171,7 +164,7 @@ export default function Header () {
|
|||||||
</Link>
|
</Link>
|
||||||
</SplitButton>
|
</SplitButton>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item className={`d-md-flex d-none ${visible}`}>
|
<Nav.Item className='d-md-flex d-none'>
|
||||||
{me
|
{me
|
||||||
? (
|
? (
|
||||||
<Link href='/post' passHref>
|
<Link href='/post' passHref>
|
||||||
@ -180,15 +173,13 @@ export default function Header () {
|
|||||||
)
|
)
|
||||||
: <Nav.Link className={styles.navLink} onClick={signIn}>post</Nav.Link>}
|
: <Nav.Link className={styles.navLink} onClick={signIn}>post</Nav.Link>}
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item className={`d-md-flex d-none ${visible}`}>
|
<Nav.Item className='d-md-flex d-none'>
|
||||||
<Nav.Link href='https://bitcoinerjobs.co' target='_blank' className={styles.navLink}>jobs</Nav.Link>
|
<Nav.Link href='https://bitcoinerjobs.co' target='_blank' className={styles.navLink}>jobs</Nav.Link>
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<Nav.Item className={`text-monospace ${visible}`} style={{ opacity: '.5' }}>
|
<Nav.Item className='text-monospace' style={{ opacity: '.5' }}>
|
||||||
<Price onReady={() => setPriceReady(true)} />
|
<Price />
|
||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
<div className={visible}>
|
<Corner />
|
||||||
<Corner />
|
|
||||||
</div>
|
|
||||||
</Nav>
|
</Nav>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -1,33 +1,16 @@
|
|||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { gql, useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
|
import { ME } from '../fragments/users'
|
||||||
|
|
||||||
export const MeContext = React.createContext({
|
export const MeContext = React.createContext({
|
||||||
me: null
|
me: null
|
||||||
})
|
})
|
||||||
|
|
||||||
export function MeProvider ({ children }) {
|
export function MeProvider ({ me, children }) {
|
||||||
const query = gql`
|
const { data } = useQuery(ME, { pollInterval: 1000 })
|
||||||
{
|
|
||||||
me {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
sats
|
|
||||||
stacked
|
|
||||||
freePosts
|
|
||||||
freeComments
|
|
||||||
hasNewNotes
|
|
||||||
tipDefault
|
|
||||||
bio {
|
|
||||||
id
|
|
||||||
}
|
|
||||||
hasInvites
|
|
||||||
theme
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
const { data } = useQuery(query, { pollInterval: 1000 })
|
|
||||||
|
|
||||||
const contextValue = {
|
const contextValue = {
|
||||||
me: data ? data.me : null
|
me: data ? data.me : me
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,29 +1,53 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
const fetcher = url => fetch(url).then(res => res.json())
|
const fetcher = url => fetch(url).then(res => res.json())
|
||||||
|
|
||||||
export default function Price ({ onReady }) {
|
export const PriceContext = React.createContext({
|
||||||
const [asSats, setAsSats] = useState(undefined)
|
price: null
|
||||||
useEffect(() => {
|
})
|
||||||
setAsSats(localStorage.getItem('asSats'))
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
|
const ENDPOINT = 'https://api.coinbase.com/v2/prices/BTC-USD/spot'
|
||||||
|
|
||||||
|
export async function getPrice () {
|
||||||
|
const data = await fetcher(ENDPOINT)
|
||||||
|
return data?.data?.amount
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PriceProvider ({ price, children }) {
|
||||||
const { data } = useSWR(
|
const { data } = useSWR(
|
||||||
'https://api.coinbase.com/v2/prices/BTC-USD/spot',
|
ENDPOINT,
|
||||||
fetcher,
|
fetcher,
|
||||||
{
|
{
|
||||||
refreshInterval: 30000
|
refreshInterval: 30000
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
const contextValue = {
|
||||||
if (onReady) {
|
price: data?.data?.amount || price
|
||||||
onReady()
|
}
|
||||||
}
|
|
||||||
}, [data])
|
|
||||||
|
|
||||||
if (!data || !data.data) return null
|
return (
|
||||||
|
<PriceContext.Provider value={contextValue}>
|
||||||
|
{children}
|
||||||
|
</PriceContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePrice () {
|
||||||
|
const { price } = useContext(PriceContext)
|
||||||
|
return price
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Price () {
|
||||||
|
const [asSats, setAsSats] = useState(undefined)
|
||||||
|
useEffect(() => {
|
||||||
|
setAsSats(localStorage.getItem('asSats'))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const price = usePrice()
|
||||||
|
|
||||||
|
if (!price) return null
|
||||||
|
|
||||||
const fixed = (n, f) => Number.parseFloat(n).toFixed(f)
|
const fixed = (n, f) => Number.parseFloat(n).toFixed(f)
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@ -39,14 +63,14 @@ export default function Price ({ onReady }) {
|
|||||||
if (asSats) {
|
if (asSats) {
|
||||||
return (
|
return (
|
||||||
<Button className='text-reset px-1 py-0' onClick={handleClick} variant='link'>
|
<Button className='text-reset px-1 py-0' onClick={handleClick} variant='link'>
|
||||||
{fixed(100000000 / data.data.amount, 0) + ' sats/$'}
|
{fixed(100000000 / price, 0) + ' sats/$'}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button className='text-reset px-1 py-0' onClick={handleClick} variant='link'>
|
<Button className='text-reset px-1 py-0' onClick={handleClick} variant='link'>
|
||||||
{'$' + fixed(data.data.amount, 2)}
|
{'$' + fixed(price, 2)}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,25 @@ import { gql } from '@apollo/client'
|
|||||||
import { COMMENT_FIELDS } from './comments'
|
import { COMMENT_FIELDS } from './comments'
|
||||||
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
import { ITEM_FIELDS, ITEM_WITH_COMMENTS } from './items'
|
||||||
|
|
||||||
|
export const ME = gql`
|
||||||
|
{
|
||||||
|
me {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
sats
|
||||||
|
stacked
|
||||||
|
freePosts
|
||||||
|
freeComments
|
||||||
|
hasNewNotes
|
||||||
|
tipDefault
|
||||||
|
bio {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
hasInvites
|
||||||
|
theme
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
export const USER_FIELDS = gql`
|
export const USER_FIELDS = gql`
|
||||||
${ITEM_FIELDS}
|
${ITEM_FIELDS}
|
||||||
fragment UserFields on User {
|
fragment UserFields on User {
|
||||||
|
@ -8,6 +8,7 @@ import { LightningProvider } from '../components/lightning'
|
|||||||
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
import { ItemActModal, ItemActProvider } from '../components/item-act'
|
||||||
import getApolloClient from '../lib/apollo'
|
import getApolloClient from '../lib/apollo'
|
||||||
import NextNProgress from 'nextjs-progressbar'
|
import NextNProgress from 'nextjs-progressbar'
|
||||||
|
import { PriceProvider } from '../components/price'
|
||||||
|
|
||||||
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
function MyApp ({ Component, pageProps: { session, ...props } }) {
|
||||||
const client = getApolloClient()
|
const client = getApolloClient()
|
||||||
@ -27,6 +28,8 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { me, price } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NextNProgress
|
<NextNProgress
|
||||||
@ -40,16 +43,18 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
|
|||||||
<PlausibleProvider domain='stacker.news' trackOutboundLinks>
|
<PlausibleProvider domain='stacker.news' trackOutboundLinks>
|
||||||
<Provider session={session}>
|
<Provider session={session}>
|
||||||
<ApolloProvider client={client}>
|
<ApolloProvider client={client}>
|
||||||
<MeProvider>
|
<MeProvider me={me}>
|
||||||
<LightningProvider>
|
<PriceProvider price={price}>
|
||||||
<FundErrorProvider>
|
<LightningProvider>
|
||||||
<FundErrorModal />
|
<FundErrorProvider>
|
||||||
<ItemActProvider>
|
<FundErrorModal />
|
||||||
<ItemActModal />
|
<ItemActProvider>
|
||||||
<Component {...props} />
|
<ItemActModal />
|
||||||
</ItemActProvider>
|
<Component {...props} />
|
||||||
</FundErrorProvider>
|
</ItemActProvider>
|
||||||
</LightningProvider>
|
</FundErrorProvider>
|
||||||
|
</LightningProvider>
|
||||||
|
</PriceProvider>
|
||||||
</MeProvider>
|
</MeProvider>
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
|
@ -44,8 +44,6 @@ export async function getServerSideProps ({ req, res, query: { id, error = null
|
|||||||
return { props: {} }
|
return { props: {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(process.env.PUBLIC_URL + req.url)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
providers: await providers({ req, res }),
|
providers: await providers({ req, res }),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user