Add better type checking when connecting components
This commit is contained in:
parent
150a02b344
commit
f2e44f477c
@ -1,7 +1,7 @@
|
|||||||
// Maybe this won't be necessary after this is merged:
|
// Maybe this won't be necessary after this is merged:
|
||||||
// https://github.com/Microsoft/TypeScript/pull/29478
|
// https://github.com/Microsoft/TypeScript/pull/29478
|
||||||
|
|
||||||
export interface IAction<T, ActionType extends string> {
|
export interface IAction<T = any, ActionType extends string = string> {
|
||||||
payload: Promise<T> | T,
|
payload: Promise<T> | T,
|
||||||
type: ActionType
|
type: ActionType
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import {Redirect} from '../components/Redirect'
|
|||||||
|
|
||||||
export interface ILoginFormProps {
|
export interface ILoginFormProps {
|
||||||
error?: string
|
error?: string
|
||||||
onSubmit: () => Promise<IUser>
|
onSubmit: () => void
|
||||||
onChange: (name: string, value: string) => void
|
onChange: (name: string, value: string) => void
|
||||||
data: ICredentials
|
data: ICredentials
|
||||||
user?: IUser
|
user?: IUser
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {Connector} from '../redux/Connector'
|
import {Connector} from '../redux/Connector'
|
||||||
import {ICredentials} from '@rondo/common'
|
import {INewUser} from '@rondo/common'
|
||||||
import {ILoginState} from './LoginReducer'
|
import {ILoginState} from './LoginReducer'
|
||||||
import {IStateSelector} from '../redux'
|
import {IStateSelector} from '../redux'
|
||||||
import {LoginActions} from './LoginActions'
|
import {LoginActions} from './LoginActions'
|
||||||
@ -7,9 +7,11 @@ import {RegisterForm} from './RegisterForm'
|
|||||||
import {bindActionCreators} from 'redux'
|
import {bindActionCreators} from 'redux'
|
||||||
import {withForm} from './withForm'
|
import {withForm} from './withForm'
|
||||||
|
|
||||||
const defaultCredentials: ICredentials = {
|
const defaultCredentials: INewUser = {
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RegisterConnector extends Connector<ILoginState> {
|
export class RegisterConnector extends Connector<ILoginState> {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {IAction} from '../actions'
|
||||||
|
|
||||||
export interface IComponentProps<Data> {
|
export interface IComponentProps<Data> {
|
||||||
onSubmit: () => void
|
onSubmit: () => void
|
||||||
@ -9,7 +10,7 @@ export interface IComponentProps<Data> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IFormHOCProps<Data> {
|
export interface IFormHOCProps<Data> {
|
||||||
onSubmit: (props: Data) => Promise<void>
|
onSubmit: (props: Data) => IAction<any, any>
|
||||||
// TODO figure out what would happen if the underlying child component
|
// TODO figure out what would happen if the underlying child component
|
||||||
// would have the same required property as the HOC, like onSuccess?
|
// would have the same required property as the HOC, like onSuccess?
|
||||||
onSuccess?: () => void
|
onSuccess?: () => void
|
||||||
@ -33,7 +34,9 @@ export function withForm<Data, Props extends IComponentProps<Data>>(
|
|||||||
handleSubmit = async (e: React.FormEvent) => {
|
handleSubmit = async (e: React.FormEvent) => {
|
||||||
const {clearOnSuccess, onSuccess} = this.props
|
const {clearOnSuccess, onSuccess} = this.props
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
await this.props.onSubmit(this.state)
|
const promise = this.props.onSubmit(this.state)
|
||||||
|
console.log('aaaaaaaaa', promise)
|
||||||
|
await promise
|
||||||
if (clearOnSuccess) {
|
if (clearOnSuccess) {
|
||||||
this.setState(initialState)
|
this.setState(initialState)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,9 +35,9 @@ export abstract class Connector<LocalState> {
|
|||||||
|
|
||||||
protected wrap<
|
protected wrap<
|
||||||
State,
|
State,
|
||||||
StateProps,
|
Props,
|
||||||
DispatchProps,
|
StateProps extends Partial<Props>,
|
||||||
Props
|
DispatchProps extends Partial<Props>,
|
||||||
>(
|
>(
|
||||||
getLocalState: IStateSelector<State, LocalState>,
|
getLocalState: IStateSelector<State, LocalState>,
|
||||||
mapStateToProps: (state: LocalState) => StateProps,
|
mapStateToProps: (state: LocalState) => StateProps,
|
||||||
|
|||||||
@ -1,25 +1,26 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {IAction} from '../actions'
|
||||||
import {ITeam, ReadonlyRecord} from '@rondo/common'
|
import {ITeam, ReadonlyRecord} from '@rondo/common'
|
||||||
|
|
||||||
export interface ITeamListProps {
|
export interface ITeamListProps {
|
||||||
teamsById: ReadonlyRecord<number, ITeam>,
|
teamsById: ReadonlyRecord<number, ITeam>,
|
||||||
teamIds: ReadonlyArray<number>,
|
teamIds: ReadonlyArray<number>,
|
||||||
onAddTeam: (params: {name: string}) => Promise<void>
|
onAddTeam: (params: {name: string}) => IAction
|
||||||
onRemoveTeam: (params: {id: number}) => Promise<void>
|
onRemoveTeam: (params: {id: number}) => IAction
|
||||||
onUpdateTeam: (params: {id: number, name: string}) => Promise<void>
|
onUpdateTeam: (params: {id: number, name: string}) => IAction
|
||||||
editTeamId: number
|
editTeamId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITeamProps {
|
export interface ITeamProps {
|
||||||
team: ITeam
|
team: ITeam
|
||||||
editTeamId: number // TODO handle edits via react-router params
|
editTeamId: number // TODO handle edits via react-router params
|
||||||
onRemoveTeam: (params: {id: number}) => Promise<void>
|
onRemoveTeam: (params: {id: number}) => IAction
|
||||||
onUpdateTeam: (params: {id: number, name: string}) => Promise<void>
|
onUpdateTeam: (params: {id: number, name: string}) => IAction
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAddTeamProps {
|
export interface IAddTeamProps {
|
||||||
onAddTeam: (params: {name: string}) => Promise<void>
|
onAddTeam: (params: {name: string}) => IAction
|
||||||
onUpdateTeam: (params: {id: number, name: string}) => Promise<void>
|
onUpdateTeam: (params: {id: number, name: string}) => IAction
|
||||||
team?: ITeam
|
team?: ITeam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import {IAction} from '../actions'
|
||||||
import {ITeam, IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
import {ITeam, IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
||||||
import {TeamList} from './TeamList'
|
import {TeamList} from './TeamList'
|
||||||
import {TeamUserList} from './TeamUserList'
|
import {TeamUserList} from './TeamUserList'
|
||||||
// import {Route} from 'react-router-dom'
|
|
||||||
|
|
||||||
export interface ITeamManagerProps {
|
export interface ITeamManagerProps {
|
||||||
createTeam: (params: {name: string}) => Promise<void>
|
createTeam: (params: {name: string}) => IAction
|
||||||
updateTeam: (params: {id: number, name: string}) => Promise<void>
|
updateTeam: (params: {id: number, name: string}) => IAction
|
||||||
removeTeam: (params: {id: number}) => Promise<void>
|
removeTeam: (params: {id: number}) => IAction
|
||||||
|
|
||||||
addUser: (params: {userId: number, teamId: number}) => Promise<void>
|
addUser: (params: {userId: number, teamId: number, roleId: number}) => IAction
|
||||||
removeUser: (params: {userId: number, teamId: number}) => Promise<void>
|
removeUser: (params: {userId: number, teamId: number}) => IAction
|
||||||
fetchMyTeams: () => void
|
fetchMyTeams: () => IAction
|
||||||
fetchUsersInTeam: () => void
|
fetchUsersInTeam: (params: {teamId: number}) => IAction
|
||||||
findUserByEmail: (email: string) => Promise<IUser>
|
findUserByEmail: (email: string) => IAction<IUser | undefined>
|
||||||
|
|
||||||
teamsById: ReadonlyRecord<number, ITeam>
|
teamsById: ReadonlyRecord<number, ITeam>
|
||||||
teamIds: ReadonlyArray<number>
|
teamIds: ReadonlyArray<number>
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
import {IUser, IUserInTeam, ReadonlyRecord} from '@rondo/common'
|
||||||
|
import {IAction} from '../actions'
|
||||||
|
|
||||||
const EMPTY_ARRAY: ReadonlyArray<string> = []
|
const EMPTY_ARRAY: ReadonlyArray<string> = []
|
||||||
|
|
||||||
export interface ITeamUsersProps {
|
export interface ITeamUsersProps {
|
||||||
// fetchMyTeams: () => void,
|
// fetchMyTeams: () => void,
|
||||||
fetchUsersInTeam: (teamId: number) => void
|
fetchUsersInTeam: (params: {teamId: number}) => IAction
|
||||||
findUserByEmail: (email: string) => Promise<IUser>
|
findUserByEmail: (email: string) => IAction
|
||||||
|
|
||||||
onAddUser: (params: {userId: number, teamId: number}) => Promise<void>
|
onAddUser: (params: {userId: number, teamId: number, roleId: number})
|
||||||
onRemoveUser: (params: {userId: number, teamId: number}) => Promise<void>
|
=> IAction<IUserInTeam>
|
||||||
|
onRemoveUser: (params: {userId: number, teamId: number}) => IAction
|
||||||
|
|
||||||
teamId: number
|
teamId: number
|
||||||
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
userKeysByTeamId: ReadonlyRecord<number, ReadonlyArray<string>>
|
||||||
@ -22,8 +24,12 @@ export interface ITeamUserProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IAddUserProps {
|
export interface IAddUserProps {
|
||||||
onAddUser: (params: {userId: number, teamId: number}) => Promise<void>
|
onAddUser: (params: {
|
||||||
onSearchUser: (email: string) => Promise<IUser>
|
userId: number,
|
||||||
|
teamId: number,
|
||||||
|
roleId: number,
|
||||||
|
}) => IAction<IUserInTeam>
|
||||||
|
onSearchUser: (email: string) => IAction<IUser>
|
||||||
teamId: number
|
teamId: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +76,7 @@ export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const {teamId} = this.props
|
const {teamId} = this.props
|
||||||
const {email} = this.state
|
const {email} = this.state
|
||||||
const user = await this.props.onSearchUser(email)
|
const user = await this.props.onSearchUser(email).payload
|
||||||
if (!user) {
|
if (!user) {
|
||||||
// TODO handle this better via 404 status code
|
// TODO handle this better via 404 status code
|
||||||
return
|
return
|
||||||
@ -78,6 +84,7 @@ export class AddUser extends React.PureComponent<IAddUserProps, IAddUserState> {
|
|||||||
await this.props.onAddUser({
|
await this.props.onAddUser({
|
||||||
teamId,
|
teamId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
roleId: 1,
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setState({email: '', user: undefined})
|
this.setState({email: '', user: undefined})
|
||||||
@ -111,7 +118,7 @@ export class TeamUserList extends React.PureComponent<ITeamUsersProps> {
|
|||||||
}
|
}
|
||||||
async fetchUsersInTeam(teamId: number) {
|
async fetchUsersInTeam(teamId: number) {
|
||||||
if (teamId) {
|
if (teamId) {
|
||||||
await this.props.fetchUsersInTeam(teamId)
|
await this.props.fetchUsersInTeam({teamId})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user