Style team manager

This commit is contained in:
Jerko Steiner 2019-03-23 22:50:44 +08:00
parent 77838e8e0c
commit 3bcf9d646e
4 changed files with 165 additions and 84 deletions

View File

@ -2,6 +2,11 @@ import React from 'react'
import {ITeam, ReadonlyRecord} from '@rondo/common' import {ITeam, ReadonlyRecord} from '@rondo/common'
import {Link} from 'react-router-dom' import {Link} from 'react-router-dom'
import {TeamActions} from './TeamActions' import {TeamActions} from './TeamActions'
import {FaPlusSquare, FaSave, FaEdit, FaTimes} from 'react-icons/fa'
import {
Button, Control, Heading, Input, Panel, PanelHeading, PanelBlock
} from 'bloomer'
export interface ITeamListProps { export interface ITeamListProps {
teamsById: ReadonlyRecord<number, ITeam>, teamsById: ReadonlyRecord<number, ITeam>,
@ -14,7 +19,7 @@ export interface ITeamListProps {
export interface ITeamProps { export interface ITeamProps {
team: ITeam team: ITeam
editTeamId?: number // TODO handle edits via react-router params editTeamId?: number
onRemoveTeam: TeamActions['removeTeam'] onRemoveTeam: TeamActions['removeTeam']
onUpdateTeam: TeamActions['updateTeam'] onUpdateTeam: TeamActions['updateTeam']
} }
@ -33,7 +38,18 @@ export class TeamAdd extends React.PureComponent<IAddTeamProps, IAddTeamState> {
constructor(props: IAddTeamProps) { constructor(props: IAddTeamProps) {
super(props) super(props)
this.state = { this.state = {
name: props.team ? props.team.name : '', name: this.getName(props.team),
}
}
getName(team?: ITeam) {
return team ? team.name : ''
}
componentWillReceiveProps(nextProps: IAddTeamProps) {
const {team} = nextProps
if (team !== this.props.team) {
this.setState({
name: this.getName(team),
})
} }
} }
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@ -53,16 +69,28 @@ export class TeamAdd extends React.PureComponent<IAddTeamProps, IAddTeamState> {
render() { render() {
return ( return (
<form className='team-add' onSubmit={this.handleSubmit}> <form className='team-add' onSubmit={this.handleSubmit}>
<Heading>
{this.props.team ? 'Edit team' : 'Add team'} {this.props.team ? 'Edit team' : 'Add team'}
<input </Heading>
<Control hasIcons='left'>
<Input
placeholder='New Team Name'
type='text' type='text'
value={this.state.name} value={this.state.name}
onChange={this.handleChange} onChange={this.handleChange}
/> />
<input <span className='icon is-left'>
<FaPlusSquare />
</span>
</Control>
<div className='text-right mt-1'>
<Button
className='button is-primary'
type='submit' type='submit'
value='Save' >
/> <FaSave className='mr-1' /> Save
</Button>
</div>
</form> </form>
) )
} }
@ -76,19 +104,26 @@ export class TeamRow extends React.PureComponent<ITeamProps> {
render() { render() {
const {team} = this.props const {team} = this.props
return ( return (
<div className='team'> <React.Fragment>
{team.id} <div className='team-name'>
{this.props.editTeamId !== team.id {team.name}
? team.name
: <TeamAdd
onAddTeam={undefined as any}
onUpdateTeam={this.props.onUpdateTeam}
team={team}
/>
}
<Link to={`/teams/${team.id}/users`}>Edit</Link>
<button onClick={this.handleRemove}>Remove</button>
</div> </div>
<div className='ml-auto'>
<Link to={`/teams/${team.id}/users`}>
<Button aria-label='Edit'>
<FaEdit />
</Button>
</Link>
&nbsp;
<Button
aria-label='Remove'
onClick={this.handleRemove}
isColor='danger'
>
<FaTimes />
</Button>
</div>
</React.Fragment>
) )
} }
} }
@ -98,24 +133,43 @@ export class TeamList extends React.PureComponent<ITeamListProps> {
const {editTeamId, teamIds, teamsById} = this.props const {editTeamId, teamIds, teamsById} = this.props
return ( return (
<div className='team-list'> <Panel>
{!editTeamId && (
<React.Fragment>
<PanelHeading>Teams</PanelHeading>
{teamIds.map(teamId => { {teamIds.map(teamId => {
const team = teamsById[teamId] const team = teamsById[teamId]
return ( return (
<PanelBlock key={team.id}>
<TeamRow <TeamRow
key={team.id}
editTeamId={editTeamId} editTeamId={editTeamId}
onRemoveTeam={this.props.onRemoveTeam} onRemoveTeam={this.props.onRemoveTeam}
onUpdateTeam={this.props.onUpdateTeam} onUpdateTeam={this.props.onUpdateTeam}
team={team} team={team}
/> />
</PanelBlock>
) )
})} })}
<PanelBlock isDisplay='block'>
<TeamAdd <TeamAdd
onAddTeam={this.props.onAddTeam} onAddTeam={this.props.onAddTeam}
onUpdateTeam={undefined as any} onUpdateTeam={undefined as any}
/> />
</div> </PanelBlock>
</React.Fragment>
)}
{editTeamId && (
<PanelBlock isDisplay='block'>
<TeamAdd
team={teamsById[editTeamId]}
onAddTeam={undefined as any}
onUpdateTeam={this.props.onUpdateTeam}
/>
</PanelBlock>
)}
</Panel>
) )
} }
} }

View File

@ -1,10 +1,11 @@
import React from 'react' import React from 'react'
import {Title} from 'bloomer'
import {History, Location} from 'history'
import {ITeam, IUserInTeam, ReadonlyRecord} from '@rondo/common' import {ITeam, IUserInTeam, ReadonlyRecord} from '@rondo/common'
import {TeamActions} from './TeamActions'
import {TeamList} from './TeamList' import {TeamList} from './TeamList'
import {TeamUserList} from './TeamUserList' import {TeamUserList} from './TeamUserList'
import {TeamActions} from './TeamActions'
import {match} from 'react-router' import {match} from 'react-router'
import {History, Location} from 'history'
export interface ITeamManagerProps { export interface ITeamManagerProps {
history: History history: History
@ -35,15 +36,15 @@ export class TeamManager extends React.PureComponent<ITeamManagerProps> {
await this.props.fetchMyTeams() await this.props.fetchMyTeams()
} }
render() { render() {
// TODO load my teams on first launch // TypeOrm changes BigInt fields to Strings because they can be tool
// TODO use teamId from route url // large...
// TODO use editTeamId from route url const editTeamId = this.props.match.params.teamId as any as
// const {editTeamId} = this.props number | undefined
const editTeamId = this.props.match.params.teamId !== undefined ?
Number(this.props.match.params.teamId) : undefined
return ( return (
<React.Fragment> <div className='team-manager'>
<Title>Teams</Title>
<TeamList <TeamList
editTeamId={editTeamId} editTeamId={editTeamId}
teamsById={this.props.teamsById} teamsById={this.props.teamsById}
@ -65,7 +66,7 @@ export class TeamManager extends React.PureComponent<ITeamManagerProps> {
usersByKey={this.props.usersByKey} usersByKey={this.props.usersByKey}
/>} />}
</React.Fragment> </div>
) )
} }
} }

View File

@ -119,5 +119,4 @@ export function Team(state = defaultState, action: TeamActionType): ITeamState {
default: default:
return state return state
} }
return state
} }

View File

@ -1,6 +1,11 @@
import React from 'react' import React from 'react'
import {IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common' import {IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
import {TeamActions} from './TeamActions' import {TeamActions} from './TeamActions'
import {FaUser, FaSave, FaTimes} from 'react-icons/fa'
import {
Button, Control, Heading, Input, Panel, PanelHeading, PanelBlock
} from 'bloomer'
const EMPTY_ARRAY: ReadonlyArray<string> = [] const EMPTY_ARRAY: ReadonlyArray<string> = []
@ -42,15 +47,21 @@ export class TeamUser extends React.PureComponent<ITeamUserProps> {
const {user} = this.props const {user} = this.props
// TODO style // TODO style
return ( return (
<div className='team-user'> <React.Fragment>
<div className='user'>
{user.displayName} {user.displayName}
<button </div>
<div className='ml-auto'>
<Button
aria-label='Remove'
isColor='danger'
className='team-user-remove' className='team-user-remove'
onClick={this.handleRemoveUser} onClick={this.handleRemoveUser}
> >
Remove <FaTimes />
</button> </Button>
</div> </div>
</React.Fragment>
) )
} }
} }
@ -89,13 +100,27 @@ export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
render() { render() {
return ( return (
<form onSubmit={this.handleAddUser}> <form onSubmit={this.handleAddUser}>
<input <Heading>Add User</Heading>
<Control hasIcons='left'>
<Input
onChange={this.handleChangeEmail} onChange={this.handleChangeEmail}
placeholder='Email' placeholder='Email'
type='email' type='email'
value={this.state.email} value={this.state.email}
/> />
<input type='submit' value='Add' /> <span className='icon is-left'>
<FaUser />
</span>
</Control>
<div className='mt-1 text-right'>
<Button
isColor='primary'
type='submit'
>
<FaSave className='mr-1' />
Add
</Button>
</div>
</form> </form>
) )
} }
@ -104,8 +129,7 @@ export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
export class TeamUserList extends React.PureComponent<ITeamUsersProps> { export class TeamUserList extends React.PureComponent<ITeamUsersProps> {
async componentDidMount() { async componentDidMount() {
await this.fetchUsersInTeam(this.props.teamId) await this.fetchUsersInTeam(this.props.teamId)
} } async componentWillReceiveProps(nextProps: ITeamUsersProps) {
async componentWillReceiveProps(nextProps: ITeamUsersProps) {
const {teamId} = nextProps const {teamId} = nextProps
if (teamId !== this.props.teamId) { if (teamId !== this.props.teamId) {
this.fetchUsersInTeam(teamId) this.fetchUsersInTeam(teamId)
@ -121,26 +145,29 @@ export class TeamUserList extends React.PureComponent<ITeamUsersProps> {
|| EMPTY_ARRAY || EMPTY_ARRAY
return ( return (
<React.Fragment> <Panel>
<div className='team-user-list'> <PanelHeading>Users in Team</PanelHeading>
{userKeysByTeamId.map(key => { {userKeysByTeamId.map(key => {
const user = this.props.usersByKey[key] const user = this.props.usersByKey[key]
return ( return (
<PanelBlock key={key}>
<TeamUser <TeamUser
key={key} key={key}
user={user} user={user}
onRemoveUser={this.props.onRemoveUser} onRemoveUser={this.props.onRemoveUser}
/> />
</PanelBlock>
) )
})} })}
</div>
<PanelBlock isDisplay='block'>
<AddUser <AddUser
onAddUser={this.props.onAddUser} onAddUser={this.props.onAddUser}
onSearchUser={this.props.findUserByEmail} onSearchUser={this.props.findUserByEmail}
teamId={this.props.teamId} teamId={this.props.teamId}
/> />
</React.Fragment> </PanelBlock>
</Panel>
) )
} }
} }