lerna: split up bulk of packages

This commit is contained in:
41666 2019-04-02 23:10:45 -05:00
parent cb0b1d2410
commit 47a2e5694e
No known key found for this signature in database
GPG key ID: BC51D07640DC10AF
90 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,112 @@
// @flow
import * as React from 'react'
import App, { Container } from 'next/app'
import Head from 'next/head'
import Layout from '../components/layout'
import { withCookies } from '../config/rpc'
import { Provider } from 'react-redux'
import ErrorP, { Overlay } from './_error'
import styled from 'styled-components'
import { withRedux } from '../config/redux'
import type { UserPartial } from '../../services/discord'
type NextPage = React.Component<any> & React.StatelessFunctionalComponent<any> & {
getInitialProps: (ctx: any, ...args: any) => any
}
const MissingJS = styled.noscript`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
font-size: 1.3em;
padding: 1em;
`
class RoleypolyApp extends App {
static async getInitialProps ({ Component, ctx, router }: { Component: NextPage, router: any, ctx: {[x:string]: any}}) {
// Fix for next/error rendering instead of our error page.
// Who knows why this would ever happen.
if (Component.displayName === 'ErrorPage' || Component.constructor.name === 'ErrorPage') {
Component = ErrorP
}
// console.log({ Component })
let pageProps = {}
const rpc = withCookies(ctx)
let user: ?UserPartial
try {
user = await rpc.getCurrentUser()
ctx.user = user
} catch (e) {
if (e.code === 403) {
ctx.user = null
} else {
console.error(e)
throw e
}
}
ctx.robots = 'INDEX, FOLLOW'
ctx.layout = {
noBackground: false
}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx, rpc, router)
}
// console.log({ pageProps })
return { pageProps, user, layout: ctx.layout, robots: ctx.robots }
}
catchFOUC () {
setTimeout(() => {
if (document.documentElement) document.documentElement.className += ' force-active'
}, 700)
}
componentDidMount () {
this.catchFOUC()
}
render () {
const { Component, pageProps, router, user, layout, robots, store } = this.props
// Fix for next/error rendering instead of our error page.
// Who knows why this would ever happen.
const ErrorCaughtComponent = (Component.displayName === 'ErrorPage' || Component.constructor.name === 'ErrorPage') ? ErrorP : Component
return <Container>
<MissingJS>
<Overlay />
Hey there... Unfortunately, we require JS for this app to work. Please take this rose as retribution. 🌹
</MissingJS>
<Head>
<meta charSet='utf-8' />
<title key='title'>Roleypoly</title>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' href='/static/favicon.png' />
<meta key='robots' name='robots' content={robots} />
<script key='typekit' dangerouslySetInnerHTML={{ __html: `
(function(d) {
var config = {
kitId: 'bck0pci',
scriptTimeout: 1500,
async: true
},
h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
})(document);//
` }} />
</Head>
<Provider store={store}>
<Layout user={user} {...layout} router={router}>
<ErrorCaughtComponent {...pageProps} router={router} originalName={Component.displayName || Component.constructor.name} />
</Layout>
</Provider>
</Container>
}
}
export default withRedux(RoleypolyApp)

View file

@ -0,0 +1,24 @@
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps (ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />)
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: <>{initialProps.styles}{sheet.getStyleElement()}</>
}
} finally {
sheet.seal()
}
}
}

View file

@ -0,0 +1,110 @@
import * as React from 'react'
import styled from 'styled-components'
import MediaQuery from '../kit/media'
export const Overlay = styled.div`
opacity: 0.6;
pointer-events: none;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: -10;
background-image: radial-gradient(circle, var(--c-dark), var(--c-dark) 1px, transparent 1px, transparent);
background-size: 27px 27px;
`
const ResponsiveSplitter = styled.div`
z-index: -1;
display: flex;
align-items: center;
justify-content: center;
line-height: 1.6;
font-size: 1.3em;
flex-direction: column;
${() => MediaQuery({
md: `flex-direction: row; min-height: 100vh; position: relative; top: -50px;`
})}
& > div {
margin: 1rem;
}
& section {
text-align: center;
${() => MediaQuery({
md: `text-align: left;`
})}
}
`
const JapaneseFlair = styled.section`
color: var(--c-3);
font-size: 0.9rem;
`
const Code = styled.h1`
margin: 0;
padding: 0;
font-size: 4em;
${() => MediaQuery({
md: `font-size: 2em;`
})}
`
export default class CustomErrorPage extends React.Component {
static getInitialProps ({ res, err, robots }) {
const statusCode = res ? res.statusCode : err ? err.statusCode : null
robots = 'NOINDEX, NOFOLLOW'
return { statusCode }
}
render400 = () => this.out('400', `Your client sent me something weird...`, '((((;゜Д゜)))')
render403 = () => this.out('403', `You weren't allowed to access this.`, 'あなたはこの点に合格しないかもしれません')
render404 = () => this.out('404', 'This page is in another castle.', 'お探しのページは見つかりませんでした')
render419 = () => this.out('419', 'Something went too slowly...', 'おやすみなさい〜')
render500 = () => this.out('500', `The server doesn't like you right now. Feed it a cookie.`, 'クッキーを送ってください〜 クッキーを送ってください〜')
renderDefault = () => this.out('Oops', 'Something went bad. How could this happen?', 'おねがい?')
renderServer = () => this.out('Oops.', 'Server was unhappy about this render. Try reloading or changing page.', 'クッキーを送ってください〜')
renderAuthExpired = () => this.out('Woah.', 'That magic login link was expired.', 'What are you trying to do?')
out (code, description, flair) {
return <div>
<Overlay />
<ResponsiveSplitter>
<div>
<Code>{code}</Code>
</div>
<div>
<section>
{description}
</section>
<JapaneseFlair>{flair}</JapaneseFlair>
</div>
</ResponsiveSplitter>
</div>
}
handlers = {
400: this.render400,
403: this.render403,
404: this.render404,
419: this.render419,
500: this.render500,
1001: this.renderAuthExpired
}
render () {
// if (this.props.originalName === 'ErrorPage') {
// return this.renderServer()
// }
if (this.props.statusCode in this.handlers) {
return this.handlers[this.props.statusCode]()
}
return this.renderDefault()
}
}

View file

@ -0,0 +1,6 @@
import * as React from 'react'
import SocialCards from '../../../components/social-cards'
export default () => <>
<SocialCards title='Sign in on Roleypoly' />
</>

View file

@ -0,0 +1,6 @@
import * as React from 'react'
import SocialCards from '../../../components/social-cards'
export default () => <>
<SocialCards title='Sign in on Roleypoly' description="Click this link to log in. It's magic!" />
</>

View file

@ -0,0 +1,111 @@
// @flow
import * as React from 'react'
import Head from 'next/head'
import type { PageProps } from '../../types'
import SocialCards from '../../components/social-cards'
import redirect from '../../lib/redirect'
import { connect } from 'react-redux'
import { fetchServerIfNeed, getCurrentServerState, type ServerState } from '../../stores/currentServer'
import { renderRoles, getCategoryViewState, toggleRole, type ViewState } from '../../stores/roles'
import styled from 'styled-components'
import Role from '../../components/role'
type ServerPageProps = PageProps & {
currentServer: ServerState,
view: ViewState,
isDiscordBot: boolean
}
const mapStateToProps = (state, { router: { query: { id } } }) => {
return {
currentServer: getCurrentServerState(state, id),
view: getCategoryViewState(state)
}
}
const Category = styled.div``
const Hider = styled.div`
/* opacity: ${(props: any) => props.visible ? '1' : '0'}; */
/* opacity: 1; */
/* transition: opacity 0.15s ease-out; */
/* ${(props: any) => props.visible ? '' : 'display: none;'} */
`
const RoleHolder = styled.div`
display: flex;
flex-wrap: wrap;
`
class Server extends React.PureComponent<ServerPageProps> {
static async getInitialProps (ctx: *, rpc: *, router: *) {
const isDiscordBot = ctx.req && ctx.req.headers['user-agent'].includes('Discordbot')
if (ctx.user == null) {
if (!isDiscordBot) {
redirect(ctx, `/auth/login?r=${router.asPath}`)
}
}
ctx.robots = 'NOINDEX, NOFOLLOW'
await ctx.store.dispatch(fetchServerIfNeed(router.query.id, rpc))
if (!isDiscordBot) {
await ctx.store.dispatch(renderRoles(router.query.id))
}
return { isDiscordBot }
}
async componentDidMount () {
const { currentServer, router: { query: { id } }, dispatch } = this.props
if (currentServer == null) {
this.props.router.push('/s/add')
}
await dispatch(fetchServerIfNeed(id))
await dispatch(renderRoles(id))
}
onToggle = (role) => (nextState) => {
if (role.safe) {
this.props.dispatch(toggleRole(role.id, nextState))
}
}
renderSocial () {
const { currentServer } = this.props
return <SocialCards title={`${currentServer.server.name} on Roleypoly`} description='Manage your roles here.' />
}
render () {
const { isDiscordBot, currentServer, view } = this.props
// console.log({ currentServer })
if (currentServer == null) {
return null
}
if (isDiscordBot) {
return this.renderSocial()
}
return (
<div>
<Head>
<title key='title'>{currentServer.server.name} - Roleypoly</title>
</Head>
{ this.renderSocial() }
hello <span style={{ color: currentServer.gm?.color }}>{currentServer.gm?.nickname}</span> on {currentServer.server.name} ({ view.dirty ? 'dirty' : 'clean' })
<Hider visible={true || currentServer.id !== null}>
{ !view.invalidated && view.categories.map(c => <Category key={`cat__${c.name}__${c.id}`}>
<div>{ c.name }</div>
<RoleHolder>
{
c._roles && c._roles.map(r => <Role key={`role__${r.name}__${r.id}`} role={r} active={view.selected.includes(r.id)} onToggle={this.onToggle(r)} disabled={!r.safe} />)
}
</RoleHolder>
</Category>) }
</Hider>
</div>
)
}
}
export default connect(mapStateToProps)(Server)

View file

@ -0,0 +1 @@
export default () => <h1>s/add</h1>

View file

@ -0,0 +1,2 @@
import Error from '../_error'
export default ({ router: { query: { code = 404 } } }) => <Error statusCode={code} />

View file

@ -0,0 +1,23 @@
// @flow
import * as React from 'react'
import type { PageProps } from '../../types'
export default class LandingTest extends React.Component<PageProps> {
render () {
return <div>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Suscipit accusantium quidem adipisci excepturi, delectus iure omnis, eos corrupti, ea ex iusto magnam! Incidunt accusamus repellat natus esse facilis animi aut.</p>
</div>
}
}

View file

@ -0,0 +1,3 @@
import ErrorPage from '../_error'
export default (props) => <ErrorPage {...props} statusCode={1001} />

View file

@ -0,0 +1,192 @@
// @flow
import * as React from 'react'
import styled from 'styled-components'
import MediaQuery from '../../kit/media'
import DiscordButton from '../../components/discord-button'
import RPC from '../../config/rpc'
import redirect from '../../lib/redirect'
import dynamic from 'next/dynamic'
import type { PageProps, ServerSlug } from '../../types'
import getConfig from 'next/config'
const { publicRuntimeConfig: { BOT_HANDLE } } = getConfig()
type AuthLoginState = {
humanCode: string,
waiting: boolean
}
type AuthLoginProps = PageProps & {
redirect: ?string,
redirectSlug: ?ServerSlug
}
const Wrapper = styled.div`
display: flex;
justify-content: center;
padding-top: 3em;
width: 400px;
max-width: calc(98vw - 10px);
margin: 0 auto;
text-align: center;
${() => MediaQuery({
md: `
padding-top: 0;
align-items: center;
min-height: 80vh;
`
})}
`
const Line = styled.div`
height: 1px;
background-color: var(--c-9);
margin: 1em 0.3em;
`
const SecretCode = styled.input`
background-color: transparent;
border: 0;
padding: 1em;
color: var(--c-9);
margin: 0.5rem 0;
width: 100%;
font-size: 0.9em;
appearance: none;
transition: all 0.3s ease-in-out;
&:focus, &:active, &:hover {
background-color: var(--c-3);
}
&:focus, &:active {
& ::placeholder {
color: transparent;
}
}
& ::placeholder {
transition: all 0.3s ease-in-out;
color: var(--c-7);
text-align: center;
}
`
const HiderButton = styled.button`
appearance: none;
display: block;
cursor: pointer;
width: 100%;
background-color: var(--c-3);
color: var(--c-white);
border: none;
padding: 1em;
font-size: 0.9em;
transition: all 0.3s ease-in-out;
&[disabled] {
cursor: default;
opacity: 0;
pointer-events: none;
}
`
const SlugWrapper = styled.div`
padding-bottom: 2em;
text-align: center;
`
const DiscordGuildPic = dynamic(() => import('../../components/discord-guild-pic'))
const StyledDGP = styled(DiscordGuildPic)`
border-radius: 100%;
border: 2px solid rgba(0,0,0,0.2);
height: 4em;
margin-top: 1em;
`
const ServerName = styled.span`
font-weight: bold;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
width: 370px;
display: block;
`
const Slug = (slug: ServerSlug) => <SlugWrapper>
<StyledDGP {...slug} />
<br />Hey there.<br /><ServerName>{slug.name}</ServerName> uses Roleypoly to manage its roles.
</SlugWrapper>
export default class AuthLogin extends React.Component<AuthLoginProps, AuthLoginState> {
state = {
humanCode: '',
waiting: false
}
static async getInitialProps (ctx: *, rpc: typeof RPC, router: *) {
let { r } = (router.query: { r: string })
if (ctx.user != null) {
redirect(ctx, r || '/')
}
ctx.robots = 'NOINDEX, NOFOLLOW'
if (r != null) {
let redirectSlug = null
if (r.startsWith('/s/') && r !== '/s/add') {
redirectSlug = await rpc.getServerSlug(r.replace('/s/', ''))
}
return { redirect: r, redirectSlug }
}
}
componentDidMount () {
if (this.props.redirect != null) {
this.props.router.replace(this.props.router.pathname)
}
}
onChange = (event: any) => {
this.setState({ humanCode: event.target.value })
}
onSubmit = async () => {
this.setState({ waiting: true })
try {
const result = await RPC.checkAuthChallenge(this.state.humanCode)
if (result === true) {
redirect(null, this.props.redirect || '/')
}
} catch (e) {
this.setState({ waiting: false })
}
}
get dm () {
if (BOT_HANDLE) {
const [username, discrim] = BOT_HANDLE.split('#')
return <><b>{ username }</b>#{discrim}</>
}
return <><b>roleypoly</b>#3712</>
}
render () {
return <Wrapper>
<div>
{(this.props.redirectSlug != null) ? <Slug {...this.props.redirectSlug} /> : null}
<DiscordButton href={`/api/auth/redirect?r=${this.props.redirect || '/'}`}>Sign in with Discord</DiscordButton>
<Line />
<div>
<i>Or, send a DM to {this.dm} saying: login</i>
</div>
<div>
<SecretCode placeholder='click to enter super secret code' onChange={this.onChange} value={this.state.humanCode} />
<HiderButton onClick={this.onSubmit} disabled={this.state.humanCode === ''}>{
(this.state.waiting) ? 'One sec...' : 'Submit Code →'
}</HiderButton>
</div>
</div>
</Wrapper>
}
}

View file

@ -0,0 +1,113 @@
import * as React from 'react'
import styled from 'styled-components'
import demoRoles from '../../config/demo'
import MediaQuery from '../../kit/media'
const admin = { name: 'admin', color: '#db2828' }
const bot = { name: 'roleypoly', color: 'var(--c-5)' }
const exampleGood = [
admin,
bot,
...demoRoles
]
const exampleBad = [
admin,
...demoRoles,
bot
]
const DiscordOuter = styled.div`
background-color: var(--dark-but-not-black);
padding: 10px;
text-align: left;
color: var(--c-white);
border: 1px solid rgba(0,0,0,0.25);
width: 250px;
margin: 0 auto;
user-select: none;
`
const Collapser = styled.div`
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
${() => MediaQuery({
md: `flex-direction: row;`
})}
`
const DiscordRole = styled.div`
color: ${({ role: { color } }) => color};
position: relative;
padding: 0.3em 0.6em;
border-radius: 3px;
cursor: pointer;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
transition: opacity 0.02s ease-in-out;
opacity: 0;
background-color: ${({ role: { color } }) => color};
border-radius: 3px;
}
&:hover::before {
opacity: 0.1;
}
${
({ role }) => (role.name === 'roleypoly')
? `
background-color: ${role.color};
color: var(--c-white);
`
: ``
}
`
const MicroHeader = styled.div`
font-size: 0.7em;
font-weight: bold;
color: #72767d;
padding: 0.3rem 0.6rem;
`
const Center = styled.div`
text-align: center;
margin: 2em;
`
const Example = ({ data }) => (
<DiscordOuter>
<MicroHeader>
ROLES
</MicroHeader>
{
data.map(role => <DiscordRole role={role} key={role.name}>{role.name}</DiscordRole>)
}
</DiscordOuter>
)
export default () => <div>
<h3>How come I can't see any of my roles?!</h3>
<p>Discord doesn't let us act upon roles that are "higher" than Roleypoly's in the list. You must keep it's role higher than any role you may want to assign.</p>
<Collapser>
<Center>
<h4 style={{ color: 'var(--c-red)' }}>Bad </h4>
<Example data={exampleBad} />
</Center>
<Center>
<h4 style={{ color: 'var(--c-green)' }}>Good </h4>
<Example data={exampleGood} />
</Center>
</Collapser>
</div>

View file

@ -0,0 +1,119 @@
import * as React from 'react'
import redirect from '../lib/redirect'
// import Link from 'next/link'
// import Head from '../components/head'
// import Nav from '../components/nav'
import TypingDemo from '../components/demos/typing'
import TapDemo from '../components/demos/tap'
import styled from 'styled-components'
import MediaQuery from '../kit/media'
const HeroBig = styled.h1`
color: var(--c-7);
font-size: 1.8em;
`
const HeroSmol = styled.h1`
color: var(--c-5);
font-size: 1.1em;
`
const Hero = styled.div`
padding: 2em 0;
text-align: center;
`
const Footer = styled.p`
text-align: center;
font-size: 0.7em;
opacity: 0.3;
transition: opacity 0.3s ease-in-out;
&:hover {
opacity: 1;
}
&:active {
opacity: 1;
}
`
const FooterLink = styled.a`
font-style: none;
color: var(--c-7);
text-decoration: none;
transition: color 0.3s ease-in-out;
&:hover {
color: var(--c-5);
}
`
const DemoArea = styled.div`
display: flex;
flex-direction: column;
${() => MediaQuery({ md: `flex-direction: row;` })}
& > div {
flex: 1;
padding: 10px;
}
& > div > p {
text-align: center;
}
`
const Wrapper = styled.div`
flex-wrap: wrap;
${() => MediaQuery({
md: `
display: flex;
justify-content: center;
align-items: center;
height: 80vh;
min-height: 500px;
`
})}
`
export default class Home extends React.Component {
static async getInitialProps (ctx, rpc) {
if (ctx.user != null) {
redirect(ctx, '/s/add')
}
ctx.layout.noBackground = true
}
render () {
return <div>
<Wrapper>
<div>
<Hero>
<HeroBig>Discord roles for humans.</HeroBig>
<HeroSmol>Ditch bot commands once and for all.</HeroSmol>
</Hero>
<DemoArea>
<div>
<TypingDemo />
<p>What is this? 2005?</p>
</div>
<div>
<TapDemo />
<p>Just click or tap.</p>
</div>
</DemoArea>
</div>
</Wrapper>
<Footer>
© {new Date().getFullYear()}<br />
Made with &nbsp;
<img src='/static/flags.svg' style={{ height: '1em', opacity: 0.5 }} /><br />
<FooterLink target='_blank' href='https://ko-fi.com/roleypoly'>Ko-Fi</FooterLink>&nbsp;-&nbsp;
<FooterLink target='_blank' href='https://github.com/kayteh/roleypoly'>GitHub</FooterLink>&nbsp;-&nbsp;
<FooterLink target='_blank' href='https://discord.gg/PWQUVsd'>Discord</FooterLink>
</Footer>
</div>
}
}

View file

@ -0,0 +1,31 @@
import * as React from 'react'
import RPC, { withCookies } from '../config/rpc'
export default class TestRPC extends React.Component {
static async getInitialProps (ctx) {
const user = await withCookies(ctx).getCurrentUser()
console.log(user)
return {
user
}
}
async componentDidMount () {
window.$RPC = RPC
}
componentDidCatch (error, errorInfo) {
if (error) {
console.log(error, errorInfo)
}
}
render () {
if (this.props.user == null) {
return <div>hello stranger OwO</div>
}
const { username, avatar, discriminator } = this.props.user
return <div>hello, {username}#{discriminator} <img src={avatar} width={50} height={50} /></div>
}
}