-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6770c52
commit 238c331
Showing
19 changed files
with
757 additions
and
26 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule common
updated
5 files
+42 −0 | codes/codes.json | |
+14 −0 | codes/index.ts | |
+79 −0 | contracts/user.ts | |
+15 −0 | enums/index.ts | |
+30 −0 | routes/be.route.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import React from 'react'; | ||
import { connect } from 'dva'; | ||
import { Form, Modal } from 'antd'; | ||
import { FormProps, ReduxProps } from '@/@types/props'; | ||
import UserSelect from './UserSelect'; | ||
|
||
export interface Props extends ReduxProps, FormProps { | ||
invitationCode: string; | ||
confirmLoading: boolean; | ||
onAddMember: (userId: number) => Promise<boolean>; | ||
} | ||
|
||
interface State { | ||
visible: boolean; | ||
} | ||
|
||
class AddTeamMemberModal extends React.Component<Props, State> { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
visible: false, | ||
}; | ||
} | ||
|
||
handleOk = () => { | ||
const { form } = this.props; | ||
this.props.form.validateFields((err, values) => { | ||
if (!err) { | ||
const users = values.users; | ||
const userIds = Array.isArray(users) ? users.map((v) => +v.key) : [+users.key]; | ||
this.props.onAddMember(userIds[0]).then((success) => { | ||
if (success) { | ||
form.resetFields(); | ||
this.handleHideModel(); | ||
} | ||
}); | ||
} | ||
}); | ||
}; | ||
|
||
handleShowModel = (e) => { | ||
if (e) { | ||
e.stopPropagation(); | ||
} | ||
this.setState({ visible: true }); | ||
}; | ||
|
||
handleHideModel = () => { | ||
this.setState({ visible: false }); | ||
}; | ||
|
||
render() { | ||
const { children, confirmLoading, invitationCode, form } = this.props; | ||
const { getFieldDecorator } = form; | ||
|
||
return ( | ||
<> | ||
<span onClick={this.handleShowModel}>{children}</span> | ||
<Modal | ||
title="Invite Team Member" | ||
visible={this.state.visible} | ||
okText="Submit" | ||
confirmLoading={confirmLoading} | ||
onOk={this.handleOk} | ||
onCancel={this.handleHideModel} | ||
> | ||
<Form layout="vertical" hideRequiredMark={true}> | ||
<Form.Item label="User"> | ||
{getFieldDecorator('users', { | ||
rules: [{ required: true, message: 'Please select a user' }], | ||
})( | ||
<UserSelect | ||
placeholder="Input nickname to search" | ||
nameFormat={(u) => `${u.nickname} (UID: ${u.userId})`} | ||
/>, | ||
)} | ||
</Form.Item> | ||
</Form> | ||
<p className="text-secondary mb-sm"> | ||
After being invited, the user still need to confirm through your code: | ||
</p> | ||
<p className="text-center text-bold" style={{ fontSize: '18px' }}> | ||
{invitationCode} | ||
</p> | ||
</Modal> | ||
</> | ||
); | ||
} | ||
} | ||
|
||
function mapStateToProps(state) { | ||
return {}; | ||
} | ||
|
||
export default connect(mapStateToProps)(Form.create()(AddTeamMemberModal)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import React from 'react'; | ||
import { connect } from 'dva'; | ||
import { Form, Input, Modal, Table } from 'antd'; | ||
import { FormProps, ReduxProps } from '@/@types/props'; | ||
import msg from '@/utils/msg'; | ||
import tracker from '@/utils/tracker'; | ||
import { codeMsgs, Codes } from '@/common/codes'; | ||
import TimeBar from './TimeBar'; | ||
import UserBar from './UserBar'; | ||
|
||
export interface Props extends ReduxProps, FormProps { | ||
userId: number; | ||
teams: IUserSelfJoinedTeam[]; | ||
confirmJoinLoading: boolean; | ||
} | ||
|
||
interface State { | ||
visible: boolean; | ||
invitationCode: string; | ||
} | ||
|
||
class SelfTeamsModal extends React.Component<Props, State> { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
visible: false, | ||
invitationCode: '', | ||
}; | ||
} | ||
|
||
handleConfirmJoinTeam = () => { | ||
const { dispatch, confirmJoinLoading } = this.props; | ||
if (confirmJoinLoading) { | ||
return; | ||
} | ||
const { invitationCode } = this.state; | ||
if (!invitationCode) { | ||
msg.error('Please input invitation code'); | ||
return; | ||
} | ||
if (isNaN(+invitationCode)) { | ||
msg.error(codeMsgs[Codes.USER_NOT_INVITED_TO_THIS_TEAM]); | ||
return; | ||
} | ||
dispatch({ | ||
type: 'users/confirmJoinTeam', | ||
payload: { | ||
teamUserId: +invitationCode || 0, | ||
}, | ||
}).then((ret) => { | ||
msg.auto(ret); | ||
if (ret.success) { | ||
msg.success('Joined successfully'); | ||
// this.handleHideModel(); | ||
this.setState({ invitationCode: '' }); | ||
tracker.event({ | ||
category: 'users', | ||
action: 'confirmJoinTeam', | ||
}); | ||
dispatch({ | ||
type: 'users/getSelfJoinedTeams', | ||
}); | ||
} | ||
}); | ||
}; | ||
|
||
handleShowModel = (e) => { | ||
if (e) { | ||
e.stopPropagation(); | ||
} | ||
this.setState({ visible: true }); | ||
}; | ||
|
||
handleHideModel = () => { | ||
this.setState({ visible: false }); | ||
}; | ||
|
||
render() { | ||
const { children, loading, teams, form } = this.props; | ||
|
||
return ( | ||
<> | ||
<span onClick={this.handleShowModel}>{children}</span> | ||
<Modal | ||
title="My Teams" | ||
visible={this.state.visible} | ||
onCancel={this.handleHideModel} | ||
footer={null} | ||
> | ||
<Form layout="vertical" hideRequiredMark={true}> | ||
<Form.Item label="Join an Invited Team"> | ||
<Input.Search | ||
enterButton="Join" | ||
placeholder="Invitation code" | ||
className="input-button" | ||
value={this.state.invitationCode} | ||
onChange={(e) => this.setState({ invitationCode: e.target.value })} | ||
onSearch={this.handleConfirmJoinTeam} | ||
/> | ||
</Form.Item> | ||
</Form> | ||
|
||
<h4>Joined Teams</h4> | ||
<Table | ||
dataSource={teams} | ||
rowKey="teamUserId" | ||
loading={loading} | ||
pagination={false} | ||
className="responsive-table" | ||
> | ||
<Table.Column | ||
title="Team" | ||
key="team" | ||
render={(text, record: IUserSelfJoinedTeam) => ( | ||
<span> | ||
{record.nickname} | ||
<br /> | ||
<span className="text-secondary" style={{ fontSize: '12px' }}>Account: {record.username}</span> | ||
</span> | ||
)} | ||
/> | ||
<Table.Column | ||
title="Members" | ||
key="members" | ||
render={(text, record: IUserSelfJoinedTeam) => ( | ||
<span> | ||
{record.members.map((member) => ( | ||
<UserBar key={member.userId} user={member} hideName useTooltip /> | ||
))} | ||
</span> | ||
)} | ||
/> | ||
<Table.Column | ||
title="Joined at" | ||
key="joinedAt" | ||
render={(text, record: IUserSelfJoinedTeam) => ( | ||
<span> | ||
<TimeBar time={new Date(record.selfJoinedAt).getTime()} /> | ||
</span> | ||
)} | ||
/> | ||
</Table> | ||
</Modal> | ||
</> | ||
); | ||
} | ||
} | ||
|
||
function mapStateToProps(state) { | ||
return { | ||
loading: !!state.loading.effects['users/getSelfJoinedTeams'], | ||
teams: state.users.selfJoinedTeams, | ||
confirmJoinLoading: !!state.loading.effects['users/confirmJoinTeam'], | ||
}; | ||
} | ||
|
||
export default connect(mapStateToProps)(Form.create()(SelfTeamsModal)); |
Oops, something went wrong.