Skip to content

Commit

Permalink
feat: support switching competition login form
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamerblue committed Dec 17, 2023
1 parent 3bc2f0c commit 3df43b0
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 48 deletions.
205 changes: 157 additions & 48 deletions src/pages/competitions/$id/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import router from 'umi/router';
import { urlf } from '@/utils/format';
import tracker from '@/utils/tracker';
import { getCompetitionUserAvailablePages } from '@/utils/competition';
import { ICompetition, ICompetitionSettings } from '@/common/interfaces/competition';
import PageLoading from '@/components/PageLoading';

interface ICompetitionSessionState extends ICompetitionSessionStatus {
_code: number;
Expand All @@ -22,16 +24,97 @@ export interface Props extends ReduxProps, RouteProps, FormProps {
id: number;
globalSession: ISessionStatus;
session: ICompetitionSessionState;
detail: ICompetition;
settings: ICompetitionSettings;
}

interface State {}
type TabType = '' | 'loginGlobal' | 'loginCompetition';

interface State {
tab: TabType;
}

class CompetitionBase extends React.Component<Props, State> {
static defaultProps: Partial<Props> = {};

constructor(props) {
private tabs = {
loginGlobal: {
title: 'Login OJ Account',
body: () => {
const { settings } = this.props;
const { getFieldDecorator } = this.props.form;
return (
<Form layout="vertical" hideRequiredMark={true} onSubmit={this.handleSubmit}>
<Form.Item label="Email or Username">
{getFieldDecorator('loginName', {
rules: [{
required: true, message: 'Please input email or username',
}],
})(<Input />)}
</Form.Item>

<Form.Item label="Password">
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input password' }],
})(<Input type="password" />)}
</Form.Item>

{settings.allowedAuthMethods.includes('password') &&
<Form.Item>
Switch to <a onClick={e => this.switchTab(e, 'loginCompetition')}>UID/Password Method</a>
</Form.Item>}

<Form.Item>
<Button type="primary" block htmlType="submit">Submit</Button>
</Form.Item>
</Form>
);
},
},

loginCompetition: {
title: 'Login Competition',
body: () => {
const { globalSession, settings } = this.props;
const { getFieldDecorator } = this.props.form;
return (
<Form layout="vertical" hideRequiredMark={true} onSubmit={this.handleSubmit}>
<Form.Item label="UID">
{getFieldDecorator('userId', {
rules: [
{
required: true,
message: 'Please input UID',
},
],
})(<Input />)}
</Form.Item>

<Form.Item label="Password">
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input password' }],
})(<Input type="password" />)}
</Form.Item>

{!globalSession.loggedIn && settings.allowedAuthMethods.includes('session') &&
<Form.Item>
Have an OJ account signed up this competition? <a onClick={e => this.switchTab(e, 'loginGlobal')}>Login</a>
</Form.Item>}

<Form.Item>
<Button type="primary" block htmlType="submit">Submit</Button>
</Form.Item>
</Form>
);
},
},
}

constructor(props: Props) {
super(props);
this.state = {};
this.state = {
tab: props.settings?.allowedAuthMethods.includes('session') ? 'loginGlobal' : 'loginCompetition',
};
}

componentDidMount(): void {
Expand All @@ -46,6 +129,15 @@ class CompetitionBase extends React.Component<Props, State> {
}
}

switchTab = (e, tab) => {
this.setState({ tab });
tracker.event({
category: 'competitions',
action: 'switchLoginTab',
label: tab,
});
};

redirect(props: Readonly<Props>) {
let redirectUri: string = props.location.query.redirect
? `/competitions/${props.id}${props.location.query.redirect}`
Expand All @@ -69,68 +161,83 @@ class CompetitionBase extends React.Component<Props, State> {
this.props.form.validateFields((err, values) => {
if (!err) {
const { id, dispatch } = this.props;
dispatch({
type: 'competitions/login',
payload: {
id,
data: {
userId: +values.userId,
password: values.password,
},
},
}).then((ret) => {
msg.auto(ret);
if (ret.success) {
msg.success(`Login Success`);
tracker.event({
category: 'competitions',
action: 'loginContest',
switch (this.state.tab) {
case 'loginGlobal': {
dispatch({
type: 'session/login',
payload: values,
}).then((ret) => {
msg.auto(ret);
if (ret.success) {
msg.success(`Welcome back, ${ret.data.nickname}`);
tracker.event({
category: 'competitions',
action: 'loginCompetition',
label: this.state.tab,
});
dispatch({
type: 'session/setSession',
payload: { user: ret.data },
});
dispatch({
type: 'competitions/getSession',
payload: {
id,
force: true,
},
});
}
});
break;
}
case 'loginCompetition': {
dispatch({
type: 'competitions/getSession',
type: 'competitions/login',
payload: {
id,
force: true,
data: {
userId: +values.userId,
password: values.password,
},
},
}).then((ret) => {
msg.auto(ret);
if (ret.success) {
msg.success(`Login Success`);
tracker.event({
category: 'competitions',
action: 'loginCompetition',
label: this.state.tab,
});
dispatch({
type: 'competitions/getSession',
payload: {
id,
force: true,
},
});
}
});
break;
}
});
}
}
});
};

render() {
const { getFieldDecorator } = this.props.form;
const { tab } = this.state;
if (!tab) {
return <PageLoading />;
}

return (
<div className="content-view-xs center-view">
<div className="text-center" style={{ marginBottom: '30px' }}>
<h2>Login Competition</h2>
<h2>{this.tabs[tab].title}</h2>
</div>
<div className="center-form">
<Form layout="vertical" hideRequiredMark={true} onSubmit={this.handleSubmit}>
<Form.Item label="UID">
{getFieldDecorator('userId', {
rules: [
{
required: true,
message: 'Please input UID',
},
],
})(<Input />)}
</Form.Item>

<Form.Item label="Password">
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Please input password' }],
})(<Input type="password" />)}
</Form.Item>

<Form.Item>
<Button type="primary" block htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
{this.tabs[tab].body()}
</div>
</div>
);
Expand All @@ -143,6 +250,8 @@ function mapStateToProps(state) {
id,
globalSession: state.session,
session: state.competitions.session[id],
detail: state.competitions.detail[id],
settings: state.competitions.settings[id],
};
}

Expand Down
8 changes: 8 additions & 0 deletions src/pages/competitions/models/competitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ export default {
}
return ret;
},
*getListData({ payload: query }, { call }) {
const formattedQuery: IListQuery = {
order: [['competitionId', 'DESC']],
...formatListQuery(query),
};
const ret: IApiResponse<IList<ICompetition>> = yield call(service.getList, formattedQuery);
return ret;
},
*getSession({ payload: { id, force = false } }, { call, put, select }) {
if (!force) {
const savedState = yield select((state) => state.competitions.session[id]);
Expand Down

0 comments on commit 3df43b0

Please sign in to comment.