mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-06-14 17:49:08 +00:00
sync: full redux retrofit done
This commit is contained in:
parent
cfc623b228
commit
f5220aa6dc
14 changed files with 206 additions and 122 deletions
|
@ -2,7 +2,9 @@ module.exports = (R, $) => {
|
|||
R.get('/api/servers', async (ctx) => {
|
||||
const { userId } = ctx.session
|
||||
const srv = $.discord.getRelevantServers(userId)
|
||||
ctx.body = $.discord.presentableServers(srv, userId)
|
||||
const presentable = $.discord.presentableServers(srv, userId)
|
||||
|
||||
ctx.body = presentable
|
||||
})
|
||||
|
||||
R.get('/api/server/:id', async (ctx) => {
|
||||
|
@ -18,8 +20,8 @@ module.exports = (R, $) => {
|
|||
}
|
||||
|
||||
const gm = srv.members.get(userId)
|
||||
const roles = $.discord.presentableRoles(id, gm)
|
||||
const server = $.discord.presentableRoles(id, gm)
|
||||
|
||||
ctx.body = roles
|
||||
ctx.body = server
|
||||
})
|
||||
}
|
||||
|
|
|
@ -41,22 +41,26 @@ class DiscordService extends Service {
|
|||
ownerID: server.ownerID,
|
||||
icon: server.icon
|
||||
},
|
||||
roles: this.presentableRoles(server.id, gm),
|
||||
message: 'moe moe kyuuuuuuuuun~',
|
||||
perms: this.getPermissions(gm)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
presentableRoles (serverId, gm) {
|
||||
return this.client.guilds.get(serverId).roles.filter(r => r.id !== serverId).map((role) => {
|
||||
return {
|
||||
color: role.hexColor,
|
||||
position: role.position,
|
||||
calculatedPosition: role.calculatedPosition,
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
selected: gm.roles.has(role.id)
|
||||
}
|
||||
})
|
||||
return this.client.guilds
|
||||
.get(serverId)
|
||||
.roles
|
||||
.filter(r => r.id !== serverId)
|
||||
.map((role) => ({
|
||||
color: role.hexColor,
|
||||
position: role.position,
|
||||
calculatedPosition: role.calculatedPosition,
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
selected: gm.roles.has(role.id)
|
||||
}))
|
||||
}
|
||||
|
||||
getPermissions (gm) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
"eslint": "^4.13.0",
|
||||
"immutable": "^3.8.2",
|
||||
"prop-types": "^15.6.0",
|
||||
"radium": "^0.19.6",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-immutable-proptypes": "^2.1.0",
|
||||
|
|
|
@ -7,6 +7,10 @@ export const fetchServers = async dispatch => {
|
|||
type: Symbol.for('update servers'),
|
||||
data: rsp.body
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: Symbol.for('app ready')
|
||||
})
|
||||
}
|
||||
|
||||
export const userInit = async dispatch => {
|
||||
|
|
47
UI/src/components/role-picker/actions.js
Normal file
47
UI/src/components/role-picker/actions.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { Map, Set } from 'immutable'
|
||||
import superagent from 'superagent'
|
||||
|
||||
export const roleUpdate = (id, oldState) => (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: Symbol.for('update selected roles'),
|
||||
data: {
|
||||
id,
|
||||
state: !oldState
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const setup = id => async dispatch => {
|
||||
const rsp = await superagent.get(`/api/server/${id}`)
|
||||
const data = rsp.body
|
||||
|
||||
dispatch({
|
||||
type: Symbol.for('update server roles'),
|
||||
data: {
|
||||
id,
|
||||
roles: data
|
||||
}
|
||||
})
|
||||
|
||||
dispatch(constructView(id))
|
||||
}
|
||||
|
||||
export const constructView = id => (dispatch, getState) => {
|
||||
const server = getState().servers.get(id)
|
||||
const roles = server.get('roles')
|
||||
|
||||
const categories = roles.groupBy(x => x.get('category'))
|
||||
const selected = roles.reduce((acc, r) => {
|
||||
return acc.set(r.id, r.selected)
|
||||
}, Map())
|
||||
|
||||
console.log(categories, selected)
|
||||
dispatch({
|
||||
type: Symbol.for('setup role picker'),
|
||||
data: {
|
||||
viewMap: categories,
|
||||
rolesSelected: selected,
|
||||
originalRolesSelected: selected
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,62 +1,47 @@
|
|||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import superagent from 'superagent'
|
||||
import * as Actions from './actions'
|
||||
import './RolePicker.sass'
|
||||
|
||||
import Role from '../role'
|
||||
|
||||
const mapState = ({ rolePicker, servers }, ownProps) => {
|
||||
console.log(servers)
|
||||
return {
|
||||
data: rolePicker,
|
||||
server: servers.get(ownProps.match.params.server)
|
||||
}
|
||||
}
|
||||
|
||||
@connect(mapState)
|
||||
class RolePicker extends Component {
|
||||
state = {
|
||||
roles: [],
|
||||
categories: {},
|
||||
hidden: true,
|
||||
serverMessage: `Hey there. This is a cool UI you can pick your roles from. If you have any questions, ask the mods on Discord!`
|
||||
}
|
||||
|
||||
async componentDidUpdate (prevProps) {
|
||||
if (prevProps.match.params.server !== this.props.match.params.server) {
|
||||
this.setState({ hidden: true })
|
||||
setTimeout(async () => {
|
||||
this.setState({ roles: [] })
|
||||
this.setState({ roles: await this.getRoles(this.props.match.params.server), hidden: false })
|
||||
}, 350)
|
||||
}
|
||||
}
|
||||
|
||||
async componentWillMount () {
|
||||
this.setState({ roles: await this.getRoles(this.props.match.params.server), hidden: false })
|
||||
}
|
||||
|
||||
async getRoles (id) {
|
||||
const rsp = await superagent.get(`/api/server/${id}`)
|
||||
return rsp.body//.map(r => { r.selected = false; return r })
|
||||
}
|
||||
|
||||
onChange = k => (newVal, oldVal) => {
|
||||
this.setState((prevState) => {
|
||||
return { roles: prevState.roles.map(r => {
|
||||
if (r.id === k) {
|
||||
r.selected = newVal
|
||||
}
|
||||
|
||||
return r
|
||||
})}
|
||||
})
|
||||
componentWillMount () {
|
||||
const { dispatch, match: { params: { server } } } = this.props
|
||||
dispatch(Actions.setup(server))
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div className={`role-picker ${(this.state.hidden) ? 'hidden' : ''}`}>
|
||||
<section>
|
||||
<h3>Server Message</h3>
|
||||
<p>{this.state.serverMessage}</p>
|
||||
</section>
|
||||
console.log(this.props)
|
||||
if (this.props.server === undefined) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <div className={`role-picker ${(this.props.data.hidden) ? 'hidden' : ''}`}>
|
||||
{ (this.props.server.get('message') !== '')
|
||||
? <section>
|
||||
<h3>Server Message</h3>
|
||||
<p>{this.props.server.get('message')}</p>
|
||||
</section>
|
||||
: null
|
||||
}
|
||||
<section>
|
||||
<h3>Roles</h3>
|
||||
{
|
||||
this.state.roles.map((r, k) => {
|
||||
|
||||
return <Role key={k} role={r} onToggle={this.onChange(r.id)} />
|
||||
{/* {
|
||||
this.props.data.roles.map((r, k) => {
|
||||
return <Role key={k} role={r} onToggle={this.dispatch(Actions.roleUpdate(r.id, r.selected))} />
|
||||
})
|
||||
}
|
||||
} */}
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ class ServersNavigation extends Component {
|
|||
|
||||
static propTypes = {
|
||||
user: ImmutablePropTypes.map.isRequired,
|
||||
servers: ImmutablePropTypes.setOf(ImmutablePropTypes.map).isRequired,
|
||||
servers: ImmutablePropTypes.setOf(ImmutablePropTypes.orderedMap).isRequired,
|
||||
className: PropTypes.string
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,12 @@ class ServersNavigation extends Component {
|
|||
return <Fragment>
|
||||
<UserCard user={this.props.user} />
|
||||
<div className={this.props.className}>
|
||||
{ this.props.servers.map((s, i) => <ServerCard server={s} user={this.props.user} key={i} />) }
|
||||
{
|
||||
this.props.servers.reduce((acc, s, i) => {
|
||||
acc.push(<ServerCard server={s} user={this.props.user} key={i} />)
|
||||
return acc
|
||||
}, [])
|
||||
}
|
||||
</div>
|
||||
</Fragment>
|
||||
}
|
||||
|
|
|
@ -15,28 +15,29 @@ class ServerCard extends Component {
|
|||
|
||||
let icon = ''
|
||||
|
||||
console.log(__filename, server)
|
||||
|
||||
const s = server.get('server')
|
||||
const gm = server.get('gm')
|
||||
const perms = server.get('perms')
|
||||
if (perms.canManageRoles) {
|
||||
if (perms.get('canManageRoles')) {
|
||||
icon = <span title='Role Manager' uk-tooltip='' role='img' aria-label='Role Manager'>🔰</span>
|
||||
}
|
||||
|
||||
if (perms.isAdmin) {
|
||||
if (perms.get('isAdmin')) {
|
||||
icon = <span title='Server Admin' uk-tooltip='' role='img' aria-label='Server Admin'>🔰⭐️</span>
|
||||
}
|
||||
|
||||
return <NavLink className='server-list__item' activeClassName='active' to={`/s/${s.id}`}>
|
||||
return <NavLink className='server-list__item' activeClassName='active' to={`/s/${s.get('id')}`}>
|
||||
<div className='server-list__item__icon'>
|
||||
<img src={`https://cdn.discordapp.com/icons/${s.id}/${s.icon}.png`} alt={s.name} />
|
||||
<img src={`https://cdn.discordapp.com/icons/${s.get('id')}/${s.get('icon')}.png`} alt={s.name} />
|
||||
</div>
|
||||
<div className='server-list__item__info'>
|
||||
<b>{s.name}</b><br />
|
||||
<span style={{ color: gm.color }}>{ gm.nickname || user.get('username') }</span> { icon }
|
||||
<b>{s.get('name')}</b><br />
|
||||
<span style={{ color: gm.get('color') }}>{ gm.get('nickname') || user.get('username') }</span> { icon }
|
||||
</div>
|
||||
</NavLink>
|
||||
}
|
||||
}
|
||||
|
||||
export default Radium(ServerCard)
|
||||
export default ServerCard
|
||||
|
|
|
@ -16,7 +16,7 @@ class UserCard extends Component {
|
|||
const avatar = user.get('avatar')
|
||||
|
||||
if (avatar === '' || avatar == null) {
|
||||
return `https://cdn.discordapp.com/embed/avatars/${Math.ceil(Math.random() * 9999) % 4}.png`
|
||||
return `https://cdn.discordapp.com/embed/avatars/${Math.ceil(Math.random() * 9999) % 5}.png`
|
||||
}
|
||||
|
||||
return `https://cdn.discordapp.com/avatars/${user.get('id')}/${avatar}.png`
|
||||
|
|
|
@ -2,10 +2,31 @@ import { combineReducers } from 'redux'
|
|||
|
||||
import servers from './servers'
|
||||
import user from './user'
|
||||
import rolePicker from './role-picker'
|
||||
// import roles from './roles'
|
||||
|
||||
const initialState = {
|
||||
ready: false
|
||||
}
|
||||
|
||||
const appState = (state = initialState, { type }) => {
|
||||
switch (type) {
|
||||
case Symbol.for('app ready'):
|
||||
return {
|
||||
ready: true
|
||||
}
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
appState,
|
||||
servers,
|
||||
user
|
||||
user,
|
||||
// roles,
|
||||
rolePicker
|
||||
})
|
||||
|
||||
export default rootReducer
|
||||
|
|
37
UI/src/reducers/role-picker.js
Normal file
37
UI/src/reducers/role-picker.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { Map, Set } from 'immutable'
|
||||
|
||||
const initialState = Map({
|
||||
hidden: true, // should the view be hidden?
|
||||
emptyRoles: true, // helps derender roles so there's no visible element state change
|
||||
viewMap: Set([]), // roles in categories
|
||||
originalRolesSelected: Map({}), // Map<role id, bool> -- original roles for diffing against selected
|
||||
rolesSelected: Map({}) // Map<role id, bool> -- new roles for diffing
|
||||
})
|
||||
|
||||
export default (state = initialState, { type, data }) => {
|
||||
switch (type) {
|
||||
case Symbol.for('setup role picker'):
|
||||
return state.merge(data)
|
||||
|
||||
case Symbol.for('hide role picker ui'):
|
||||
return {
|
||||
...state,
|
||||
hidden: data
|
||||
}
|
||||
|
||||
case Symbol.for('reset role picker ui'):
|
||||
return {
|
||||
...state,
|
||||
emptyRoles: data
|
||||
}
|
||||
|
||||
case Symbol.for('zero role picker'):
|
||||
return initialState
|
||||
|
||||
case Symbol.for('update selected roles'):
|
||||
return state.set('rolesSelected', state.get('rolesSelected').set(data.id, data.state))
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
|
@ -1,34 +1,39 @@
|
|||
import { Set, Map } from 'immutable'
|
||||
import { Set, OrderedMap, Map, fromJS } from 'immutable'
|
||||
|
||||
const blankServer = Map({
|
||||
'id': '386659935687147521',
|
||||
'gm': {
|
||||
'nickname': null,
|
||||
'color': '#cca1a1'
|
||||
id: '386659935687147521',
|
||||
gm: {
|
||||
nickname: null,
|
||||
color: '#cca1a1'
|
||||
},
|
||||
'server': {
|
||||
'id': '386659935687147521',
|
||||
'name': 'Roleypoly',
|
||||
'ownerID': '62601275618889728',
|
||||
'icon': '4fa0c1063649a739f3fe1a0589aa2c03'
|
||||
message: 'Hey hey!',
|
||||
server: {
|
||||
id: '386659935687147521',
|
||||
name: 'Roleypoly',
|
||||
ownerID: '62601275618889728',
|
||||
icon: '4fa0c1063649a739f3fe1a0589aa2c03'
|
||||
},
|
||||
'perms': {
|
||||
'isAdmin': true,
|
||||
'canManageRoles': true
|
||||
roles: Set([]),
|
||||
perms: {
|
||||
isAdmin: true,
|
||||
canManageRoles: true
|
||||
}
|
||||
})
|
||||
|
||||
const initialState = Set([])
|
||||
const initialState = OrderedMap({})
|
||||
|
||||
export default (state = initialState, { type, data }) => {
|
||||
console.log(__filename, type, data)
|
||||
|
||||
switch (type) {
|
||||
case Symbol.for('update servers'):
|
||||
return data.reduce((acc, s) => acc.add(Map(s)), Set())
|
||||
|
||||
return data.reduce((acc, s) => acc.set(s.id, fromJS(s)), OrderedMap())
|
||||
|
||||
// case Symbol.for('update server roles'):
|
||||
// return state.set(data.id,
|
||||
// state.get(data.id).set('roles', Set(data.roles))
|
||||
// )
|
||||
|
||||
case Symbol.for('add debug server'):
|
||||
return Set([blankServer])
|
||||
return state.set('0', blankServer)
|
||||
|
||||
default:
|
||||
return state
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Component, Fragment } from 'react'
|
||||
import { Route } from 'react-router-dom'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import Servers from '../components/servers'
|
||||
import OauthCallback from '../components/oauth-callback'
|
||||
|
@ -7,8 +8,13 @@ import OauthFlow from '../components/oauth-flow'
|
|||
|
||||
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
|
||||
|
||||
@connect(({ appState }) => ({ ready: appState.ready }))
|
||||
export default class AppRouter extends Component {
|
||||
render () {
|
||||
if (!this.props.ready) {
|
||||
return null
|
||||
}
|
||||
|
||||
return <Fragment>
|
||||
<Route exact path='/' component={aaa} />
|
||||
<Route path='/s' component={Servers} />
|
||||
|
|
32
UI/yarn.lock
32
UI/yarn.lock
|
@ -214,10 +214,6 @@ array-find-index@^1.0.1:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
|
||||
array-find@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
|
||||
|
||||
array-flatten@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
|
||||
|
@ -1298,10 +1294,6 @@ boom@5.x.x:
|
|||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
bowser@^1.0.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.8.1.tgz#49785777e7302febadb1a5b71d9a646520ed310d"
|
||||
|
||||
boxen@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
|
||||
|
@ -2884,10 +2876,6 @@ execa@^0.7.0:
|
|||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
exenv@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
|
||||
expand-brackets@^0.1.4:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
|
||||
|
@ -3704,10 +3692,6 @@ https-browserify@^1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
|
||||
hyphenate-style-name@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
|
||||
|
||||
iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||
|
@ -3779,13 +3763,6 @@ ini@^1.3.4, ini@~1.3.0:
|
|||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
||||
|
||||
inline-style-prefixer@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
|
||||
dependencies:
|
||||
bowser "^1.0.0"
|
||||
hyphenate-style-name "^1.0.1"
|
||||
|
||||
inquirer@3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.1.tgz#06ceb0f540f45ca548c17d6840959878265fa175"
|
||||
|
@ -5977,15 +5954,6 @@ querystringify@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb"
|
||||
|
||||
radium@^0.19.6:
|
||||
version "0.19.6"
|
||||
resolved "https://registry.yarnpkg.com/radium/-/radium-0.19.6.tgz#b86721d08dbd303b061a4ae2ebb06cc6e335ae72"
|
||||
dependencies:
|
||||
array-find "^1.0.0"
|
||||
exenv "^1.2.1"
|
||||
inline-style-prefixer "^2.0.5"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
randomatic@^1.1.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue