mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-06-16 10:19:10 +00:00
absolutely massive typescript porting time
This commit is contained in:
parent
01f238f515
commit
30d08a630f
159 changed files with 2563 additions and 3861 deletions
|
@ -1,14 +1,12 @@
|
|||
{
|
||||
"presets": [
|
||||
"next/babel", "@babel/preset-flow"
|
||||
"next/babel",
|
||||
"@zeit/next-typescript/babel"
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
["@babel/plugin-transform-runtime",
|
||||
{ "helpers": false }],
|
||||
[ "styled-components", { "ssr": true } ],
|
||||
"@babel/plugin-proposal-optional-chaining"
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
|
|
14
packages/roleypoly-ui/.lintstagedrc.yml
Normal file
14
packages/roleypoly-ui/.lintstagedrc.yml
Normal file
|
@ -0,0 +1,14 @@
|
|||
linters:
|
||||
lib/*.{js,jsx}:
|
||||
- standard --fix
|
||||
- git add
|
||||
lib/*.d.ts:
|
||||
- tslint --fix
|
||||
- git add
|
||||
src/*.{ts,tsx}:
|
||||
- tslint --fix
|
||||
- stylelint --fix
|
||||
- jest --bail --findRelatedTests
|
||||
- git add
|
||||
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DiscordButton /> renders correctly 1`] = `
|
||||
<discord-button__Button>
|
||||
<discord-button__ButtonIcon
|
||||
<styled.a>
|
||||
<styled.img
|
||||
src="/static/discord-logo.svg"
|
||||
/>
|
||||
|
||||
Hello!
|
||||
</discord-button__Button>
|
||||
</styled.a>
|
||||
`;
|
|
@ -22,7 +22,7 @@ exports[`<DiscordGuildPic /> falls-back to a default when things go bad. 1`] = `
|
|||
id="0000"
|
||||
name="Mock"
|
||||
>
|
||||
<discord-guild-pic__Fallback
|
||||
<styled.div
|
||||
serverName="Mock"
|
||||
style={
|
||||
Object {
|
||||
|
@ -36,17 +36,22 @@ exports[`<DiscordGuildPic /> falls-back to a default when things go bad. 1`] = `
|
|||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "discord-guild-pic__Fallback-sc-93euug-0",
|
||||
"componentId": "sc-bdVaJa",
|
||||
"isStatic": true,
|
||||
"lastClassName": "c0",
|
||||
"rules": Array [
|
||||
"display:flex;justify-content:center;align-items:center;background-color:var(--fallback-color);",
|
||||
"
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: var(--fallback-color);
|
||||
",
|
||||
],
|
||||
},
|
||||
"displayName": "discord-guild-pic__Fallback",
|
||||
"displayName": "styled.div",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "discord-guild-pic__Fallback-sc-93euug-0",
|
||||
"styledComponentId": "sc-bdVaJa",
|
||||
"target": "div",
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
|
@ -72,7 +77,7 @@ exports[`<DiscordGuildPic /> falls-back to a default when things go bad. 1`] = `
|
|||
M
|
||||
</div>
|
||||
</StyledComponent>
|
||||
</discord-guild-pic__Fallback>
|
||||
</styled.div>
|
||||
</DiscordGuildPic>
|
||||
`;
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
import * as React from 'react'
|
||||
// import renderer from 'react-test-renderer'
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
import * as React from 'react'
|
||||
// import renderer from 'react-test-renderer'
|
||||
|
@ -24,8 +27,10 @@ describe('<DiscordGuildPic />', () => {
|
|||
})
|
||||
|
||||
it('falls-back to a default when things go bad.', () => {
|
||||
const pic = mount(<DiscordGuildPic {...mockServer} />)
|
||||
pic.find('img').simulate('error')
|
||||
const el = <DiscordGuildPic { ...mockServer } />
|
||||
const pic = mount<typeof el>(el)
|
||||
pic.setState({ ok: false })
|
||||
|
||||
expect(pic).toMatchSnapshot()
|
||||
|
||||
expect(pic.text()).toEqual(mockServer.name[0])
|
|
@ -1,4 +1,3 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Role from '../role/demo'
|
|
@ -1,4 +1,3 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import moment from 'moment'
|
||||
import Typist from 'react-typist'
|
|
@ -3,7 +3,8 @@ import * as React from 'react'
|
|||
import styled from 'styled-components'
|
||||
|
||||
export type ButtonProps = {
|
||||
children: React.Node
|
||||
children: React.ReactChild
|
||||
href: string
|
||||
}
|
||||
|
||||
const Button = styled.a`
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
// export default ({ id, icon, ...rest }) => <img src={`https://cdn.discordapp.com/icons/${id}/${icon}.png`} {...rest} />
|
||||
import * as React from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
|
@ -10,7 +8,7 @@ export type GuildPicProps = {
|
|||
}
|
||||
|
||||
export type GuildPicState = {
|
||||
src: ?string,
|
||||
src: string | undefined,
|
||||
ok: boolean
|
||||
}
|
||||
|
||||
|
@ -22,24 +20,36 @@ const Fallback = styled.div`
|
|||
`
|
||||
|
||||
export default class DiscordGuildPic extends React.Component<GuildPicProps, GuildPicState> {
|
||||
state = {
|
||||
src: this.src,
|
||||
ok: false
|
||||
state: GuildPicState = {
|
||||
src: undefined,
|
||||
ok: true
|
||||
}
|
||||
|
||||
get src () {
|
||||
return `https://cdn.discordapp.com/icons/${this.props.id}/${this.props.icon}.png`
|
||||
static getDerivedStateFromProps (nextProps: GuildPicProps, prevState: GuildPicState): GuildPicState {
|
||||
return {
|
||||
...prevState,
|
||||
src: `https://cdn.discordapp.com/icons/${nextProps.id}/${nextProps.icon}.png`
|
||||
}
|
||||
}
|
||||
|
||||
renderFallback () {
|
||||
const { name, id, icon, ...rest } = this.props
|
||||
return <Fallback serverName={name} style={{ '--fallback-color': `hsl(${(name.codePointAt(0) % 360)},50%,50%)` }} {...rest}>{name[0]}</Fallback>
|
||||
// @ts-ignore
|
||||
return <Fallback
|
||||
serverName={name}
|
||||
style={{
|
||||
['--fallback-color' as any]: `hsl(${(name.codePointAt(0) || 0 % 360)},50%,50%)`
|
||||
}}
|
||||
{...rest}
|
||||
>
|
||||
{name[0]}
|
||||
</Fallback>
|
||||
}
|
||||
|
||||
onError = () => {
|
||||
// console.log('onError')
|
||||
this.setState({
|
||||
src: null
|
||||
ok: false
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -55,6 +65,7 @@ export default class DiscordGuildPic extends React.Component<GuildPicProps, Guil
|
|||
}
|
||||
|
||||
render () {
|
||||
return (this.state.src === null) ? this.renderFallback() : this.renderImg()
|
||||
return (this.state.ok === false) ? this.renderFallback() : this.renderImg()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// @flow
|
||||
// import * as React from 'react'
|
||||
import { createGlobalStyle } from 'styled-components'
|
||||
|
||||
export const colors = {
|
|
@ -1,10 +1,10 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import GlobalColors from './global-colors'
|
||||
import SocialCards from './social-cards'
|
||||
import HeaderBar from '../containers/header-bar'
|
||||
import { type User } from '../stores/user'
|
||||
import { User } from '../stores/user'
|
||||
import styled from 'styled-components'
|
||||
import Router from 'next/router'
|
||||
|
||||
const LayoutWrapper = styled.div`
|
||||
transition: opacity 0.1s ease-out;
|
||||
|
@ -24,7 +24,7 @@ const ContentBox = styled.div`
|
|||
padding-top: 50px;
|
||||
`
|
||||
|
||||
const Layout = ({ children, user, noBackground, router }: {children: React.Element<any>, user: User, noBackground: boolean, router: * }) => <>
|
||||
const Layout = ({ children, user, noBackground, router }: {children: React.ReactElement<any>, user: User, noBackground: boolean, router: typeof Router }) => <>
|
||||
<GlobalColors />
|
||||
<SocialCards />
|
||||
<LayoutWrapper>
|
|
@ -1,7 +1,17 @@
|
|||
import * as React from 'react'
|
||||
|
||||
const Logotype = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)', typeFill, style, className }) => (
|
||||
<svg style={style} className={className} viewBox='0 0 1566 298' version='1.1'>
|
||||
export type LogoProps = {
|
||||
fill: string
|
||||
width: number
|
||||
height: number
|
||||
circleFill: string
|
||||
typeFill: string
|
||||
style: object
|
||||
className: string
|
||||
}
|
||||
|
||||
export const Logotype = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)', typeFill, style, className }: Partial<LogoProps> = {}) => (
|
||||
<svg style={style} className={className} width={width} height={height} viewBox='0 0 1566 298' version='1.1'>
|
||||
<defs>
|
||||
<path d='M86.5351562,318.050781 C171.587008,318.050781 240.535156,249.102633 240.535156,164.050781 C240.535156,78.9989298 163.535156,10.0507812 86.5351562,10.0507812 L86.5351562,318.050781 Z M86.5351563,280.050781 C150.600187,280.050781 202.535156,227.668097 202.535156,163.050781 C202.535156,98.4334655 144.535156,46.0507812 86.5351563,46.0507812 C86.5351562,96.9058949 86.5351563,230.260095 86.5351563,280.050781 Z' id='path-1' />
|
||||
</defs>
|
||||
|
@ -15,8 +25,8 @@ const Logotype = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)
|
|||
</svg>
|
||||
)
|
||||
|
||||
const Logomark = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)', typeFill, style, className }) => (
|
||||
<svg style={style} className={className} viewBox='0 0 350 350' version='1.1' xmlns='http://www.w3.org/2000/svg'>
|
||||
export const Logomark = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)', typeFill, style, className }: Partial<LogoProps>) => (
|
||||
<svg style={style} className={className} width={width} height={height} viewBox='0 0 350 350' version='1.1' xmlns='http://www.w3.org/2000/svg'>
|
||||
<defs />
|
||||
<g id='Logomark' stroke='none' strokeWidth='1' fill='none' fillRule='evenodd'>
|
||||
<g id='Group' transform='translate(35.000000, -46.000000)'>
|
||||
|
@ -29,6 +39,3 @@ const Logomark = ({ fill = 'var(--c-7)', width, height, circleFill = 'var(--c-3)
|
|||
</g>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default Logotype
|
||||
export { Logotype, Logomark }
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
|
||||
import * as React from 'react'
|
||||
|
@ -36,7 +39,7 @@ describe('<Role />', () => {
|
|||
})
|
||||
|
||||
it('fixes colors when they are not set', () => {
|
||||
const role = shallow(<Role role={{ name: 'Test Role', color: 0 }} />)
|
||||
const role = shallow(<Role role={{ name: 'Test Role', color: '0' }} />)
|
||||
expect(role.props().style['--role-color-base']).toEqual('hsl(0, 0%, 93.7%)')
|
||||
})
|
||||
|
||||
|
@ -47,12 +50,14 @@ describe('<Role />', () => {
|
|||
|
||||
describe('when disabled,', () => {
|
||||
it('handles touch hover events', () => {
|
||||
const role = shallow(<Role role={{ name: 'unsafe role', color: '#ffffff' }} disabled />)
|
||||
const el = <Role role={{ name: 'unsafe role', color: '#ffffff' }} disabled={true} />
|
||||
const role = shallow<typeof el>(el)
|
||||
|
||||
role.simulate('touchstart')
|
||||
expect(role.state().hovering).toEqual(true)
|
||||
|
||||
expect(role).toMatchSnapshot() // expecting tooltip
|
||||
expect(role.exists('tooltip')).toEqual(true)
|
||||
expect(role.text().endsWith('This role has unsafe permissions.')).toBe(true)
|
||||
|
||||
role.simulate('touchend')
|
||||
expect(role.state().hovering).toEqual(false)
|
|
@ -1,10 +1,8 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Role /> renders correctly 1`] = `
|
||||
<rolestyled
|
||||
<styled.div
|
||||
onClick={[Function]}
|
||||
onTouchEnd={null}
|
||||
onTouchStart={null}
|
||||
style={
|
||||
Object {
|
||||
"--role-color-active": "hsl(0, 0%, 100%)",
|
||||
|
@ -13,17 +11,15 @@ exports[`<Role /> renders correctly 1`] = `
|
|||
"--role-color-outline-alt": "hsla(0, 0%, 100%, 0.4)",
|
||||
}
|
||||
}
|
||||
title={null}
|
||||
>
|
||||
Test Role
|
||||
</rolestyled>
|
||||
</styled.div>
|
||||
`;
|
||||
|
||||
exports[`<Role /> when disabled, does not trigger onToggle on click 1`] = `
|
||||
<rolestyled
|
||||
<styled.div
|
||||
active={false}
|
||||
disabled={true}
|
||||
onClick={null}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
style={
|
||||
|
@ -37,13 +33,12 @@ exports[`<Role /> when disabled, does not trigger onToggle on click 1`] = `
|
|||
title="This role has unsafe permissions."
|
||||
>
|
||||
Test Role
|
||||
</rolestyled>
|
||||
</styled.div>
|
||||
`;
|
||||
|
||||
exports[`<Role /> when disabled, handles touch hover events 1`] = `
|
||||
<rolestyled
|
||||
<styled.div
|
||||
disabled={true}
|
||||
onClick={null}
|
||||
onTouchEnd={[Function]}
|
||||
onTouchStart={[Function]}
|
||||
style={
|
||||
|
@ -57,8 +52,8 @@ exports[`<Role /> when disabled, handles touch hover events 1`] = `
|
|||
title="This role has unsafe permissions."
|
||||
>
|
||||
unsafe role
|
||||
<tooltip>
|
||||
<styled.div>
|
||||
This role has unsafe permissions.
|
||||
</tooltip>
|
||||
</rolestyled>
|
||||
</styled.div>
|
||||
</styled.div>
|
||||
`;
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
import * as React from 'react'
|
||||
import { shallow } from 'enzyme'
|
||||
|
@ -11,7 +14,8 @@ describe('<RoleDemo />', () => {
|
|||
})
|
||||
|
||||
it('changes state when clicked', () => {
|
||||
const demo = shallow(<RoleDemo role={{ name: 'test demo role', color: '#ffffff' }} />)
|
||||
const el = <RoleDemo role={{ name: 'test demo role', color: '#ffffff' }} />
|
||||
const demo = shallow<typeof el>(el)
|
||||
expect(demo.state().active).toEqual(false)
|
||||
demo.dive().simulate('click')
|
||||
expect(demo.state().active).toEqual(true)
|
|
@ -1,6 +1,5 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import Role, { type RoleData } from './index'
|
||||
import Role, { RoleData } from './index'
|
||||
|
||||
export type DemoRoleProps = {
|
||||
role: RoleData
|
|
@ -1,19 +1,30 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import { colors } from '../global-colors'
|
||||
import Color from 'color'
|
||||
// import Color from 'color'
|
||||
import * as cc from '@roleypoly/design/lib/helpers/colors'
|
||||
import RoleStyled from './role.styled'
|
||||
import Tooltip from '../tooltip'
|
||||
// import logger from '../../../logger'
|
||||
// const log = logger(__filename)
|
||||
|
||||
const fromColors = (colors) => Object.entries(colors).reduce(
|
||||
(acc, [v, val]) => ({ ...acc, [`--role-color-${v}`]: val })
|
||||
, {})
|
||||
type RoleColors = {
|
||||
'outline': string
|
||||
'outline-alt': string
|
||||
'active': string
|
||||
'base': string
|
||||
}
|
||||
|
||||
function fromColors (c: RoleColors) {
|
||||
return Object.entries(c).reduce((acc, [v, val]) => ({
|
||||
...acc,
|
||||
[`--role-color-${v}` as any]: val
|
||||
}), {})
|
||||
}
|
||||
|
||||
export type RoleData = {
|
||||
color: string,
|
||||
name: string,
|
||||
name: string
|
||||
}
|
||||
|
||||
export type RoleProps = {
|
||||
|
@ -23,18 +34,39 @@ export type RoleProps = {
|
|||
role: RoleData,
|
||||
isDragging?: boolean,
|
||||
onToggle?: (nextState: boolean, lastState: boolean) => void,
|
||||
connectDragSource?: (component: React.Node) => void
|
||||
connectDragSource?: (component: React.ReactNode) => void
|
||||
}
|
||||
|
||||
// const tooltip = ({ show = true, text, ...rest }) => <div {...rest}>{text}</div>
|
||||
|
||||
type RoleState = {
|
||||
hovering: boolean
|
||||
roleColors: RoleColors
|
||||
}
|
||||
|
||||
export default class Role extends React.Component<RoleProps, RoleState> {
|
||||
state = {
|
||||
hovering: false
|
||||
hovering: false,
|
||||
roleColors: {
|
||||
'outline': '#fff',
|
||||
'outline-alt': '#fff',
|
||||
'active': '#fff',
|
||||
'base': '#fff'
|
||||
}
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps (props: RoleProps, prevState: RoleState): RoleState {
|
||||
const c = (props.role.color === '0') ? colors.white : props.role.color
|
||||
const CC = cc.color(c)
|
||||
return {
|
||||
...prevState,
|
||||
roleColors: {
|
||||
'outline': CC.alpha(0.7).hsl().string(),
|
||||
'outline-alt': CC.alpha(0.4).hsl().string(),
|
||||
'active': CC.lighten(0.1).hsl().string(),
|
||||
'base': CC.hsl().string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onToggle = () => {
|
||||
|
@ -58,31 +90,21 @@ export default class Role extends React.Component<RoleProps, RoleState> {
|
|||
}
|
||||
|
||||
render () {
|
||||
let color = Color(this.props.role.color)
|
||||
if (this.props.role.color === 0) {
|
||||
color = colors.white
|
||||
}
|
||||
|
||||
const roleColors = {
|
||||
'outline': Color(color).alpha(0.7).hsl().string(),
|
||||
'outline-alt': Color(color).alpha(0.4).hsl().string(),
|
||||
'active': Color(color).lighten(0.1).hsl().string(),
|
||||
'base': Color(color).hsl().string()
|
||||
}
|
||||
|
||||
const name = (this.props.role.name !== '') ? this.props.role.name : ' '
|
||||
|
||||
return <RoleStyled
|
||||
active={this.props.active}
|
||||
disabled={this.props.disabled}
|
||||
onClick={(this.props.disabled) ? null : this.onToggle}
|
||||
onTouchStart={(this.props.disabled) ? this.onMouseOver : null}
|
||||
onTouchEnd={(this.props.disabled) ? this.onMouseOut : null}
|
||||
style={fromColors(roleColors)}
|
||||
title={(this.props.disabled) ? 'This role has unsafe permissions.' : null}
|
||||
>
|
||||
{name}
|
||||
{ (this.props.disabled && this.state.hovering) && <Tooltip>This role has unsafe permissions.</Tooltip> }
|
||||
onClick={(this.props.disabled) ? undefined : this.onToggle}
|
||||
onTouchStart={(this.props.disabled) ? this.onMouseOver : undefined}
|
||||
onTouchEnd={(this.props.disabled) ? this.onMouseOut : undefined}
|
||||
style={fromColors(this.state.roleColors)}
|
||||
title={(this.props.disabled) ? 'This role has unsafe permissions.' : undefined}
|
||||
>
|
||||
{name}
|
||||
{
|
||||
(this.props.disabled && this.state.hovering) && <Tooltip>This role has unsafe permissions.</Tooltip>
|
||||
}
|
||||
</RoleStyled>
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
import styled from 'styled-components'
|
||||
import { md } from '../../kit/media'
|
||||
|
||||
export default styled.div`
|
||||
export type SBProps = {
|
||||
active?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default styled.div<SBProps>`
|
||||
border: solid 1px var(--role-color-outline);
|
||||
border-radius: 1.2em;
|
||||
box-sizing: border-box;
|
|
@ -1,4 +1,3 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import NextHead from 'next/head'
|
||||
|
||||
|
@ -28,8 +27,8 @@ const SocialCards = (props: SocialCardProps) => {
|
|||
<meta key='twitter:card' name='twitter:card' content='summary_large_image' />
|
||||
<meta key='twitter:image' name='twitter:image' content={props.image} />
|
||||
<meta key='og:image' property='og:image' content={props.image} />
|
||||
<meta key='og:image:width' property='og:image:width' content={props.imageSize} />
|
||||
<meta key='og:image:height' property='og:image:height' content={props.imageSize} />
|
||||
<meta key='og:image:width' property='og:image:width' content={'' + props.imageSize} />
|
||||
<meta key='og:image:height' property='og:image:height' content={'' + props.imageSize} />
|
||||
</NextHead>
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// @flow
|
||||
import RPCClient from '@roleypoly/rpc-client'
|
||||
|
||||
const client = new RPCClient({ forceDev: false })
|
||||
|
||||
export default client.rpc
|
||||
export const withCookies = (ctx: any) => {
|
||||
if (ctx.req != null) {
|
||||
return client.withCookies(ctx.req.headers.cookie)
|
||||
} else {
|
||||
return client.rpc
|
||||
}
|
||||
}
|
23
packages/roleypoly-ui/config/rpc.ts
Normal file
23
packages/roleypoly-ui/config/rpc.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// @flow
|
||||
// import RPCClient from '@roleypoly/rpc-client'
|
||||
|
||||
// const client = new RPCClient({ forceDev: false })
|
||||
|
||||
// export default client.rpc
|
||||
// export const withCookies = (ctx: any) => {
|
||||
// if (ctx.req != null) {
|
||||
// return client.withCookies(ctx.req.headers.cookie)
|
||||
// } else {
|
||||
// return client.rpc
|
||||
// }
|
||||
// }
|
||||
const o = {
|
||||
getCurrentUser: async (..._: any) => null,
|
||||
getServerSlug: async (..._: any) => null,
|
||||
checkAuthChallenge: async (..._: any) => false
|
||||
}
|
||||
|
||||
export default o
|
||||
export function withCookies () {
|
||||
return o
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
const next = require('next')
|
||||
|
||||
const connector = ({ dev }) => {
|
||||
return next({ dev, dir: __dirname })
|
||||
}
|
||||
|
||||
module.exports = connector
|
|
@ -1,21 +0,0 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { type User } from '../stores/user'
|
||||
|
||||
type Props = {
|
||||
user: ?User
|
||||
}
|
||||
|
||||
const HeaderBarAuth = dynamic(() => import('../components/header/auth'))
|
||||
const HeaderBarUnauth = dynamic(() => import('../components/header/unauth'))
|
||||
|
||||
const HeaderBar = (props: Props) => {
|
||||
if (props.user == null) {
|
||||
return <HeaderBarUnauth {...props} />
|
||||
} else {
|
||||
return <HeaderBarAuth {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
export default HeaderBar
|
21
packages/roleypoly-ui/containers/header-bar.tsx
Normal file
21
packages/roleypoly-ui/containers/header-bar.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import * as React from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { User } from '../stores/user'
|
||||
import HeaderBarAuthT from '../components/header/auth'
|
||||
import HeaderBarUnauthT from '../components/header/unauth'
|
||||
type Props = {
|
||||
user?: User
|
||||
}
|
||||
|
||||
const HeaderBarAuth = dynamic<typeof HeaderBarAuthT>(() => import('../components/header/auth'))
|
||||
const HeaderBarUnauth = dynamic<typeof HeaderBarUnauthT>(() => import('../components/header/unauth'))
|
||||
|
||||
const HeaderBar = (props: Props) => {
|
||||
if (props.user === undefined) {
|
||||
return <HeaderBarUnauth {...props} />
|
||||
} else {
|
||||
return <HeaderBarAuth {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
export default HeaderBar
|
|
@ -1,3 +1,6 @@
|
|||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
/* eslint-env jest */
|
||||
import MediaQuery, { xs, sm, md, lg, xl } from '../media'
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import MediaQuery, { breakpoints } from './media'
|
||||
|
@ -13,13 +12,18 @@ const BreakpointDebugFloat = styled.div`
|
|||
font-family: monospace;
|
||||
`
|
||||
|
||||
const Breakpoint = styled.div`
|
||||
type BPProps = {
|
||||
hue: number
|
||||
bp: string
|
||||
}
|
||||
|
||||
const Breakpoint = styled.div<BPProps>`
|
||||
padding: 0.1em;
|
||||
display: none;
|
||||
width: 1.5em;
|
||||
text-align: center;
|
||||
background-color: hsl(${(props: any) => props.hue}, 50%, 50%);
|
||||
${(props: any) => MediaQuery({ [props.bp]: `display: inline-block` })}
|
||||
background-color: hsl(${(props) => props.hue}, 50%, 50%);
|
||||
${(props) => MediaQuery({ [props.bp]: `display: inline-block` })}
|
||||
`
|
||||
|
||||
const DebugFloater = () => {
|
|
@ -1,7 +1,6 @@
|
|||
// @flow
|
||||
import styled from 'styled-components'
|
||||
|
||||
export type MediaQueryConfig = $Shape<{
|
||||
export type MediaQueryConfig = Partial<{
|
||||
xs: string,
|
||||
sm: string,
|
||||
md: string,
|
||||
|
@ -17,7 +16,7 @@ export const breakpoints = {
|
|||
xl: 1280
|
||||
}
|
||||
|
||||
const mediaTemplateLiteral = (size: number, ...stuff: mixed[]): string =>
|
||||
const mediaTemplateLiteral = (size: number, ...stuff: any[]): string =>
|
||||
`@media screen and (min-width: ${size}px) {\n${stuff.join()}\n};`
|
||||
|
||||
export const xs = mediaTemplateLiteral.bind(null, breakpoints.xs)
|
||||
|
@ -27,7 +26,7 @@ export const lg = mediaTemplateLiteral.bind(null, breakpoints.lg)
|
|||
export const xl = mediaTemplateLiteral.bind(null, breakpoints.xl)
|
||||
|
||||
const MediaQuery = (mq: MediaQueryConfig) => {
|
||||
const out = []
|
||||
const out: string[] = []
|
||||
|
||||
for (const size in mq) {
|
||||
if (breakpoints[size] == null) {
|
|
@ -1,5 +1,6 @@
|
|||
require('dotenv').config({ quiet: true })
|
||||
module.exports = {
|
||||
const withTypescript = require('@zeit/next-typescript')
|
||||
module.exports = withTypescript({
|
||||
publicRuntimeConfig: {
|
||||
BOT_HANDLE: process.env.BOT_HANDLE
|
||||
},
|
||||
|
@ -11,4 +12,4 @@ module.exports = {
|
|||
|
||||
return config
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,46 +3,42 @@
|
|||
"private": true,
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"build": "next build"
|
||||
"build": "next build",
|
||||
"precommit": "lint-staged"
|
||||
},
|
||||
"dependencies": {
|
||||
"@roleypoly/types": "^2.0.0",
|
||||
"@roleypoly/rpc-client": "^2.0.0",
|
||||
"color": "^3.1.0",
|
||||
"eventemitter3": "^3.1.0",
|
||||
"@roleypoly/rpc": "^2.0.0",
|
||||
"@roleypoly/design": "^2.0.0",
|
||||
"color": "^3.1.1",
|
||||
"eventemitter3": "^3.1.2",
|
||||
"fast-redux": "^0.7.1",
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"moment": "^2.24.0",
|
||||
"next": "^8.0.4",
|
||||
"next": "^8.1.0",
|
||||
"next-redux-wrapper": "^3.0.0-alpha.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-redux": "^7.0.2",
|
||||
"react-redux": "^7.0.3",
|
||||
"react-typist": "^2.0.5",
|
||||
"redux": "^4.0.1",
|
||||
"redux-devtools-extension": "^2.13.8",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"styled-components": "^4.2.0",
|
||||
"superagent": "^5.0.2"
|
||||
"styled-components": "^4.2.1",
|
||||
"superagent": "^5.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.4.3",
|
||||
"@babel/core": "^7.4.3",
|
||||
"@babel/node": "^7.2.2",
|
||||
"@babel/plugin-proposal-class-properties": "^7.4.0",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.2.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||
"@babel/plugin-transform-runtime": "^7.4.3",
|
||||
"@babel/preset-env": "^7.4.3",
|
||||
"@babel/preset-flow": "^7.0.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"@zeit/next-typescript": "^1.1.1",
|
||||
"@roleypoly/types": "^2.0.0",
|
||||
"@babel/plugin-transform-runtime": "^7.4.4",
|
||||
"@types/next": "^8.0.5",
|
||||
"babel-plugin-styled-components": "^1.10.0",
|
||||
"babel-plugin-transform-flow-strip-types": "^6.22.0",
|
||||
"enzyme": "^3.9.0",
|
||||
"enzyme-adapter-react-16": "^1.12.1",
|
||||
"enzyme-adapter-react-16": "^1.13.2",
|
||||
"enzyme-to-json": "^3.3.5",
|
||||
"eslint-plugin-flowtype": "^3.6.1",
|
||||
"lint-staged": "^8.1.7",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"standard": "12.0.1"
|
||||
"standard": "12.0.1",
|
||||
"tslint": "^5.17.0",
|
||||
"typescript": "^3.5.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@ import { Provider } from 'react-redux'
|
|||
import ErrorP, { Overlay } from './_error'
|
||||
import styled from 'styled-components'
|
||||
import { withRedux } from '../config/redux'
|
||||
import type { UserPartial } from '@roleypoly/types'
|
||||
import { UserPartial } from '@roleypoly/types'
|
||||
|
||||
type NextPage = React.Component<any> & React.StatelessFunctionalComponent<any> & {
|
||||
getInitialProps: (ctx: any, ...args: any) => any
|
||||
}
|
||||
// type NextPage = React.Component<any> | React.FunctionComponent<any> & {
|
||||
// getInitialProps: (ctx: any, ...args: any) => any
|
||||
// }
|
||||
|
||||
const MissingJS = styled.noscript`
|
||||
display: flex;
|
||||
|
@ -25,18 +25,18 @@ const MissingJS = styled.noscript`
|
|||
`
|
||||
|
||||
class RoleypolyApp extends App {
|
||||
static async getInitialProps ({ Component, ctx, router }: { Component: NextPage, router: any, ctx: {[x:string]: any}}) {
|
||||
static async getInitialProps ({ Component, ctx, router }: 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') {
|
||||
if (Component.constructor.name === 'ErrorPage') {
|
||||
Component = ErrorP
|
||||
}
|
||||
|
||||
// console.log({ Component })
|
||||
|
||||
let pageProps = {}
|
||||
const rpc = withCookies(ctx)
|
||||
let user: ?UserPartial
|
||||
const rpc = withCookies()
|
||||
let user: UserPartial | null = null
|
||||
try {
|
||||
user = await rpc.getCurrentUser()
|
||||
ctx.user = user
|
||||
|
@ -75,7 +75,7 @@ class RoleypolyApp extends App {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { Component, pageProps, router, user, layout, robots, store } = this.props
|
||||
const { Component, pageProps, router, user, layout, robots, store } = this.props as any
|
||||
// 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
|
|
@ -24,9 +24,9 @@ const ResponsiveSplitter = styled.div`
|
|||
font-size: 1.3em;
|
||||
flex-direction: column;
|
||||
${md`
|
||||
flex-direction: row;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
flex-direction: row;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
top: -50px;
|
||||
`}
|
||||
|
||||
|
@ -52,10 +52,14 @@ const Code = styled.h1`
|
|||
${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'
|
||||
type CEPProps = {
|
||||
statusCode: number
|
||||
}
|
||||
|
||||
export default class CustomErrorPage extends React.Component<CEPProps> {
|
||||
static getInitialProps ({ res, err }): CEPProps {
|
||||
const statusCode = res ? res.statusCode : err ? err.statusCode : 0
|
||||
// const robots = 'NOINDEX, NOFOLLOW'
|
||||
return { statusCode }
|
||||
}
|
||||
|
||||
|
@ -68,7 +72,7 @@ export default class CustomErrorPage extends React.Component {
|
|||
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) {
|
||||
out (code: string, description: string, flair: string) {
|
||||
return <div>
|
||||
<Overlay />
|
||||
<ResponsiveSplitter>
|
|
@ -1,37 +1,33 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import Head from 'next/head'
|
||||
import type { PageProps } from '../../types'
|
||||
import { PageProps } from '../../types'
|
||||
import SocialCards from '../../components/social-cards'
|
||||
import redirect from '../../util/redirect'
|
||||
import { connect } from 'react-redux'
|
||||
import { fetchServerIfNeed, getCurrentServerState, type ServerState } from '../../stores/currentServer'
|
||||
import { renderRoles, getCategoryViewState, toggleRole, type ViewState } from '../../stores/roles'
|
||||
// import { connect } from 'react-redux'
|
||||
import styled from 'styled-components'
|
||||
import Role from '../../components/role'
|
||||
|
||||
type ServerPageProps = PageProps & {
|
||||
currentServer: ServerState,
|
||||
view: ViewState,
|
||||
currentServer: any,
|
||||
view: any,
|
||||
isDiscordBot: boolean
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, { router: { query: { id } } }) => {
|
||||
return {
|
||||
currentServer: getCurrentServerState(state, id),
|
||||
view: getCategoryViewState(state)
|
||||
}
|
||||
}
|
||||
|
||||
const Category = styled.div``
|
||||
const Hider = styled.div``
|
||||
|
||||
type HiderProps = {
|
||||
visible: boolean
|
||||
children?: any
|
||||
}
|
||||
const Hider = styled.div<HiderProps>``
|
||||
|
||||
const RoleHolder = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
`
|
||||
class Server extends React.PureComponent<ServerPageProps> {
|
||||
static async getInitialProps (ctx: *, rpc: *, router: *) {
|
||||
static async getInitialProps (ctx: any, rpc: any, router: any) {
|
||||
const isDiscordBot = ctx.req && ctx.req.headers['user-agent'].includes('Discordbot')
|
||||
if (ctx.user == null) {
|
||||
if (!isDiscordBot) {
|
||||
|
@ -40,10 +36,10 @@ class Server extends React.PureComponent<ServerPageProps> {
|
|||
}
|
||||
|
||||
ctx.robots = 'NOINDEX, NOFOLLOW'
|
||||
await ctx.store.dispatch(fetchServerIfNeed(router.query.id, rpc))
|
||||
// await ctx.store.dispatch(fetchServerIfNeed(router.query.id, rpc))
|
||||
|
||||
if (!isDiscordBot) {
|
||||
await ctx.store.dispatch(renderRoles(router.query.id))
|
||||
// await ctx.store.dispatch(renderRoles(router.query.id))
|
||||
}
|
||||
return { isDiscordBot }
|
||||
}
|
||||
|
@ -54,13 +50,13 @@ class Server extends React.PureComponent<ServerPageProps> {
|
|||
this.props.router.push('/s/add')
|
||||
}
|
||||
|
||||
await dispatch(fetchServerIfNeed(id))
|
||||
await dispatch(renderRoles(id))
|
||||
// await dispatch(fetchServerIfNeed(id))
|
||||
// await dispatch(renderRoles(id))
|
||||
}
|
||||
|
||||
onToggle = (role) => (nextState) => {
|
||||
onToggle = (role) => (/*nextState*/) => {
|
||||
if (role.safe) {
|
||||
this.props.dispatch(toggleRole(role.id, nextState))
|
||||
// this.props.dispatch(toggleRole(role.id, nextState))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +82,7 @@ class Server extends React.PureComponent<ServerPageProps> {
|
|||
<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' })
|
||||
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>
|
||||
|
@ -102,4 +98,4 @@ class Server extends React.PureComponent<ServerPageProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Server)
|
||||
export default Server
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import type { PageProps } from '../../types'
|
||||
import { PageProps } from '../../types'
|
||||
|
||||
export default class LandingTest extends React.Component<PageProps> {
|
||||
render () {
|
|
@ -6,8 +6,8 @@ import DiscordButton from '../../components/discord-button'
|
|||
import RPC from '../../config/rpc'
|
||||
import redirect from '../../util/redirect'
|
||||
import dynamic from 'next/dynamic'
|
||||
import type { PageProps } from '../../types'
|
||||
import type { ServerSlug } from '@roleypoly/types'
|
||||
import { PageProps } from '../../types'
|
||||
import { ServerSlug } from '@roleypoly/types'
|
||||
import getConfig from 'next/config'
|
||||
const { publicRuntimeConfig: { BOT_HANDLE } } = getConfig()
|
||||
|
||||
|
@ -17,8 +17,8 @@ type AuthLoginState = {
|
|||
}
|
||||
|
||||
type AuthLoginProps = PageProps & {
|
||||
redirect: ?string,
|
||||
redirectSlug: ?ServerSlug
|
||||
redirect?: string,
|
||||
redirectSlug?: ServerSlug
|
||||
}
|
||||
|
||||
const Wrapper = styled.div`
|
||||
|
@ -124,8 +124,8 @@ export default class AuthLogin extends React.Component<AuthLoginProps, AuthLogin
|
|||
waiting: false
|
||||
}
|
||||
|
||||
static async getInitialProps (ctx: *, rpc: typeof RPC, router: *) {
|
||||
let { r } = (router.query: { r: string })
|
||||
static async getInitialProps (ctx: any, rpc: typeof RPC, router: any) {
|
||||
let { r } = (router.query as { r?: string })
|
||||
|
||||
if (ctx.user != null) {
|
||||
redirect(ctx, r || '/')
|
||||
|
@ -133,17 +133,19 @@ export default class AuthLogin extends React.Component<AuthLoginProps, AuthLogin
|
|||
|
||||
ctx.robots = 'NOINDEX, NOFOLLOW'
|
||||
|
||||
if (r != null) {
|
||||
let redirectSlug = null
|
||||
if (r !== undefined) {
|
||||
let redirectSlug: ServerSlug | null = null
|
||||
if (r.startsWith('/s/') && r !== '/s/add') {
|
||||
redirectSlug = await rpc.getServerSlug(r.replace('/s/', ''))
|
||||
}
|
||||
return { redirect: r, redirectSlug }
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.props.redirect != null) {
|
||||
if (this.props.redirect !== undefined) {
|
||||
this.props.router.replace(this.props.router.pathname)
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +178,7 @@ export default class AuthLogin extends React.Component<AuthLoginProps, AuthLogin
|
|||
render () {
|
||||
return <Wrapper>
|
||||
<div>
|
||||
{(this.props.redirectSlug != null) ? <Slug {...this.props.redirectSlug} /> : null}
|
||||
{(this.props.redirectSlug !== undefined) ? <Slug {...this.props.redirectSlug} /> : null}
|
||||
<DiscordButton href={`/api/auth/redirect?r=${this.props.redirect || '/'}`}>Sign in with Discord</DiscordButton>
|
||||
<Line />
|
||||
<div>
|
|
@ -3,8 +3,13 @@ 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)' }
|
||||
type Role = {
|
||||
name: string
|
||||
color: string
|
||||
}
|
||||
|
||||
const admin: Role = { name: 'admin', color: '#db2828' }
|
||||
const bot: Role = { name: 'roleypoly', color: 'var(--c-5)' }
|
||||
|
||||
const exampleGood = [
|
||||
admin,
|
||||
|
@ -39,7 +44,7 @@ const Collapser = styled.div`
|
|||
})}
|
||||
`
|
||||
|
||||
const DiscordRole = styled.div`
|
||||
const DiscordRole = styled.div<{role: Role}>`
|
||||
color: ${({ role: { color } }) => color};
|
||||
position: relative;
|
||||
padding: 0.3em 0.6em;
|
File diff suppressed because one or more lines are too long
|
@ -1,107 +0,0 @@
|
|||
// @flow
|
||||
// import { action } from './servers'
|
||||
import { namespaceConfig } from 'fast-redux'
|
||||
// $FlowFixMe
|
||||
import { OrderedMap, OrderedSet, Set } from 'immutable'
|
||||
import { getCurrentServerState, type ServerState } from './currentServer'
|
||||
|
||||
type RenderedRole = {
|
||||
id: string,
|
||||
name: string,
|
||||
color: string
|
||||
}
|
||||
|
||||
type RenderedCategory = {
|
||||
id: string,
|
||||
name: string,
|
||||
_roles?: RenderedRole[],
|
||||
roles: string[],
|
||||
type: 'single' | 'multi',
|
||||
hidden: boolean,
|
||||
position?: number,
|
||||
}
|
||||
|
||||
const MOCK_DATA: RenderedCategory = {
|
||||
id: '00000',
|
||||
name: 'Placeholder Category',
|
||||
hidden: false,
|
||||
type: 'multi',
|
||||
roles: [ '00000' ],
|
||||
_roles: OrderedSet([
|
||||
{ id: '00000', name: 'Placeholder Role', color: '#ff00ff' }
|
||||
])
|
||||
}
|
||||
|
||||
const DEFAULT_VIEW_STATE = { server: '000', invalidated: true, categories: [ MOCK_DATA ], selected: Set<string>([]), originalSelected: Set<string>([]), dirty: false }
|
||||
export type ViewState = typeof DEFAULT_VIEW_STATE
|
||||
|
||||
export const { action, getState: getCategoryViewState } = namespaceConfig('currentCategoryView', DEFAULT_VIEW_STATE)
|
||||
|
||||
export const toggleRole = action('toggleRole', (state: ViewState, role: string, nextState: boolean) => {
|
||||
let selected = state.selected
|
||||
|
||||
if (nextState === true) {
|
||||
selected = selected.add(role)
|
||||
} else {
|
||||
selected = selected.delete(role)
|
||||
}
|
||||
|
||||
const dirty = !selected.equals(state.originalSelected)
|
||||
|
||||
return {
|
||||
...state,
|
||||
selected,
|
||||
dirty
|
||||
}
|
||||
})
|
||||
|
||||
const getUncategorized = (roleMap: OrderedMap<RenderedRole>, allCategories: Set): RenderedCategory => {
|
||||
const roles = roleMap.keySeq().toSet()
|
||||
const knownRoles = allCategories.map(v => v.roles).flatMap(v => v)
|
||||
const rolesLeft = roles.subtract(knownRoles)
|
||||
|
||||
// console.log(Map({ roles, knownRoles, rolesLeft }).toJS())
|
||||
return {
|
||||
id: 'Uncategorized',
|
||||
name: 'Uncategorized',
|
||||
position: -1,
|
||||
roles: rolesLeft,
|
||||
_roles: rolesLeft.map(v => roleMap.get(v)).filter(v => v != null).sortBy(v => -v.position),
|
||||
hidden: true,
|
||||
type: 'multi'
|
||||
}
|
||||
}
|
||||
|
||||
export const updateCurrentView = action('updateCurrentView', (state, data) => ({ ...state, ...data }))
|
||||
export const invalidateView = action('invalidateView', (state, data) => ({ ...state, invalidated: true }))
|
||||
|
||||
export const renderRoles = (id: string) => (dispatch: *, getState: *) => {
|
||||
const active = getCategoryViewState(getState())
|
||||
const current: ServerState = getCurrentServerState(getState(), id)
|
||||
if (!active.invalidated && current.id === active.id && active.id === id) {
|
||||
return
|
||||
}
|
||||
|
||||
const { roles, categories } = current
|
||||
if (roles == null) {
|
||||
return
|
||||
}
|
||||
|
||||
// console.log({ roles, categories })
|
||||
|
||||
const roleMap: OrderedMap<RenderedRole> = roles.reduce((acc: OrderedMap<RenderedRole>, r) => acc.set(r.id, r), OrderedMap())
|
||||
|
||||
let render = OrderedSet()
|
||||
for (let catId in categories) {
|
||||
const category = categories[catId]
|
||||
category._roles = OrderedSet(
|
||||
category.roles.map(r => roleMap.get(r))
|
||||
).filter(role => role != null).sortBy(role => role ? -(role.position || 0) : 0)
|
||||
render = render.add(category)
|
||||
}
|
||||
// console.log({id})
|
||||
render = render.add(getUncategorized(roleMap, render.toSet()))
|
||||
render = render.sortBy(h => (h.position) ? h.position : h.name)
|
||||
|
||||
dispatch(updateCurrentView({ server: id, categories: render, invalidated: false, selected: Set(current.gm?.roles), originalSelected: Set(current.gm?.roles) }))
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// @flow
|
||||
import { namespaceConfig } from 'fast-redux'
|
||||
import RPC from '../config/rpc'
|
||||
// import { Map } from 'immutable'
|
||||
import type { PresentableServer as Server } from '@roleypoly/types'
|
||||
|
||||
export type ServersState = {
|
||||
[id: string]: Server
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: ServersState = {}
|
||||
|
||||
export const { action, getState: getServerState } = namespaceConfig('servers', DEFAULT_STATE)
|
||||
|
||||
export const updateServers = action('updateServers', (state: ServersState, serverData: Server[]) => ({
|
||||
...state,
|
||||
...serverData.reduce((acc, s) => ({ ...acc, [s.id]: s }), {})
|
||||
}))
|
||||
|
||||
export const updateSingleServer = action('updateSingleServer', (state, data, server) => ({ ...state, [server]: data }))
|
||||
|
||||
export const fetchServerList = (rpc?: typeof RPC) => async (dispatch: *) => {
|
||||
if (rpc == null) {
|
||||
rpc = RPC
|
||||
}
|
||||
|
||||
const servers: Server[] = await rpc.listOwnServers()
|
||||
dispatch(updateServers(servers))
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// @flow
|
||||
import { namespaceConfig } from 'fast-redux'
|
||||
|
||||
export type User = {
|
||||
id: string,
|
||||
username: string,
|
||||
discriminator: string,
|
||||
avatar: string,
|
||||
nicknameCache: {
|
||||
[server: string]: string
|
||||
}
|
||||
}
|
||||
|
||||
export type UserState = {
|
||||
currentUser: User | null,
|
||||
userCache: {
|
||||
[id: string]: User
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_STATE: UserState = {
|
||||
currentUser: null,
|
||||
userCache: {}
|
||||
}
|
||||
|
||||
export const {
|
||||
action, getState: getUserStore
|
||||
} = namespaceConfig('userStore', DEFAULT_STATE)
|
||||
|
||||
export const getCurrentUser = () => async (dispatch: Function) => {
|
||||
|
||||
}
|
23
packages/roleypoly-ui/tsconfig.json
Normal file
23
packages/roleypoly-ui/tsconfig.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"jsx": "preserve",
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2017"
|
||||
],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"preserveConstEnums": true,
|
||||
"removeComments": false,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "esnext"
|
||||
}
|
||||
}
|
3
packages/roleypoly-ui/tslint.json
Normal file
3
packages/roleypoly-ui/tslint.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "tslint-config-standard"
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// @flow
|
||||
import type Router from 'next/router'
|
||||
|
||||
export type PageProps = {
|
||||
router: Router,
|
||||
dispatch: (...any) => mixed
|
||||
}
|
6
packages/roleypoly-ui/types.ts
Normal file
6
packages/roleypoly-ui/types.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import Router from 'next/router'
|
||||
|
||||
export type PageProps = {
|
||||
router: Router,
|
||||
dispatch: (...stuff: any) => any
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import Router from 'next/router'
|
||||
|
||||
export default (context, target) => {
|
||||
export default async (context, target) => {
|
||||
if (context && context.res) {
|
||||
// server
|
||||
// 303: "See other"
|
||||
|
@ -8,6 +8,6 @@ export default (context, target) => {
|
|||
context.res.end()
|
||||
} else {
|
||||
// In the browser, we just pretend like this never even happened ;)
|
||||
Router.replace(target)
|
||||
await Router.replace(target)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue