From 208395392fda7133cfdd95886147730ff68efe17 Mon Sep 17 00:00:00 2001 From: bLue Date: Sun, 17 Dec 2023 11:16:20 +0800 Subject: [PATCH] feat: optimize competition public entry logic --- src/common | 2 +- src/pages/competitions-public/$id/intro.tsx | 105 ++++++++++++++---- src/pages/competitions/index.tsx | 2 +- src/pages/competitions/models/competitions.ts | 4 + 4 files changed, 91 insertions(+), 22 deletions(-) diff --git a/src/common b/src/common index 36ec1ca..37824b9 160000 --- a/src/common +++ b/src/common @@ -1 +1 @@ -Subproject commit 36ec1cad2e712c00884b42b2bd5e5a01f5ab933d +Subproject commit 37824b94a50cf650519b1ea42c4a568b00581488 diff --git a/src/pages/competitions-public/$id/intro.tsx b/src/pages/competitions-public/$id/intro.tsx index dc85072..2ad67d6 100644 --- a/src/pages/competitions-public/$id/intro.tsx +++ b/src/pages/competitions-public/$id/intro.tsx @@ -1,6 +1,7 @@ import React from 'react'; -import { Divider, Button } from 'antd'; +import { Divider, Button, Row, Col, Card } from 'antd'; import { connect } from 'dva'; +import router from 'umi/router'; import { ReduxProps, RouteProps } from '@/@types/props'; import { filterXSS as xss } from 'xss'; import PageAnimation from '@/components/PageAnimation'; @@ -10,6 +11,7 @@ import { ICompetition, ICompetitionSelfParticipant, ICompetitionSelfParticipantForm, + ICompetitionSettings, } from '@/common/interfaces/competition'; import { getPathParamId } from '@/utils/getPathParams'; import pages from '@/configs/pages'; @@ -17,12 +19,15 @@ import msg from '@/utils/msg'; import moment from 'moment'; import { ECompetitionUserStatus } from '@/common/enums'; import { Codes } from '@/common/codes'; -import SdutpcLogo from '../../../assets/images/sdutpc_logo_shadow.png'; +// import SdutpcLogo from '../../../assets/images/sdutpc_logo_shadow.png'; import GeneralFormModal from '@/components/GeneralFormModal'; import tracker from '@/utils/tracker'; import Link from 'umi/link'; -import { urlf } from '@/utils/format'; +import { urlf, toLongTs } from '@/utils/format'; import classNames from 'classnames'; +import getSetTimeStatus from '@/utils/getSetTimeStatus'; +import TimeStatusBadge from '@/components/TimeStatusBadge'; +import PageLoading from '@/components/PageLoading'; const CLOTHING_SIZES = ['S', 'M', 'L', 'XL', 'XXL', 'XXXL']; @@ -36,7 +41,8 @@ function getInitialState() { export interface Props extends ReduxProps, RouteProps { id: number; session: ISessionStatus; - data: ICompetition; + detail: ICompetition; + settings: ICompetitionSettings; } interface State { @@ -88,7 +94,6 @@ class CompetitionIntro extends React.Component { id: competitionId, }, }); - msg.auto(ret); if (ret.success) { this.setState({ selfParticipant: ret.data, @@ -209,12 +214,18 @@ class CompetitionIntro extends React.Component { }; inSignUpRange = () => { - const registerStartAt = new Date(this.props.data.registerStartAt); - const registerEndAt = new Date(this.props.data.registerEndAt); + const registerStartAt = new Date(this.props.detail.registerStartAt); + const registerEndAt = new Date(this.props.detail.registerEndAt); const serverTime = Date.now() - ((window as any)._t_diff || 0); return registerStartAt.getTime() <= serverTime && serverTime < registerEndAt.getTime(); }; + isSignUpEnded = () => { + const registerEndAt = new Date(this.props.detail.registerEndAt); + const serverTime = Date.now() - ((window as any)._t_diff || 0); + return serverTime >= registerEndAt.getTime(); + }; + getSignUpStatus = () => { const { selfParticipant } = this.state; if (!selfParticipant) { @@ -249,6 +260,10 @@ class CompetitionIntro extends React.Component { }; }; + enterCompetition = () => { + router.push(urlf(pages.competitions.home, { param: { id: this.props.id } })); + }; + renderSignUpStatus = () => { const { text, level } = this.getSignUpStatus(); const words = text.split(' '); @@ -272,6 +287,9 @@ class CompetitionIntro extends React.Component { renderSignUpAction = () => { const { id, session } = this.props; const { selfParticipant, cannotSignUpTips } = this.state; + if (this.isSignUpEnded()) { + return ; + } if (!this.inSignUpRange()) { return ; } @@ -361,7 +379,7 @@ class CompetitionIntro extends React.Component { } }; - renderSignUpArea = (data: ICompetition) => { + renderSignUpArea = (detail: ICompetition) => { const { selfParticipant } = this.state; return (
@@ -369,9 +387,9 @@ class CompetitionIntro extends React.Component {
Time range to sign up:{' '} - {data.registerStartAt && data.registerEndAt - ? `${moment(data.registerStartAt).format('YYYY-MM-DD HH:mm:ss')} ~ ${moment( - data.registerEndAt, + {detail.registerStartAt && detail.registerEndAt + ? `${moment(detail.registerStartAt).format('YYYY-MM-DD HH:mm:ss')} ~ ${moment( + detail.registerEndAt, ).format('YYYY-MM-DD HH:mm:ss')}` : 'Not Set'} @@ -389,28 +407,71 @@ class CompetitionIntro extends React.Component { }; render() { - const { loading, data, id } = this.props; - if (!loading && !data.competitionId) { + const { loading, detail, settings, id, session } = this.props; + if (loading) { + return ; + } + if (!detail?.competitionId || !settings) { return ; } + const currentTime = Date.now() - ((window as any)._t_diff || 0); + const startTime = toLongTs(detail.startAt); + const endTime = toLongTs(detail.endAt); + const timeStatus = getSetTimeStatus(startTime, endTime, currentTime); + const allowSessionLoginOnly = + settings.allowedAuthMethods.includes('session') && settings.allowedAuthMethods.length === 1; + // near start time 2h + const nearStartTime = startTime - currentTime < 2 * 60 * 60 * 1000; + return ( - +
{/*
SDUTPC
*/} + + + + +

{detail.title}

+

+ + {moment(startTime).format('YYYY-MM-DD HH:mm')} ~{' '} + {moment(endTime).format('YYYY-MM-DD HH:mm')} + +

+

+ +

+ {nearStartTime && ( +

+ {!session.loggedIn && allowSessionLoginOnly ? ( + + ) : ( + + )} +

+ )} +
+ +
+
-

{data.title}

+ {/*

{detail.title}

*/}
{/* sign up area */} - {this.renderSignUpArea(data)} + {settings.allowedJoinMethods.includes('register') && this.renderSignUpArea(detail)}
@@ -426,13 +487,17 @@ class CompetitionIntro extends React.Component { function mapStateToProps(state) { const id = getPathParamId(state.routing.location.pathname, pages.competitions.public.intro); - const data = state.competitions.detail[id] || ({} as ICompetition); + const detail = state.competitions.detail[id] || ({} as ICompetition); + const settings = state.competitions.settings[id] || ({} as ICompetitionSettings); const theme = state.settings.theme; return { id, session: state.session, - loading: !!state.loading.effects['competitions/getDetail'], - data, + loading: + !!state.loading.effects['competitions/getDetail'] || + !!state.loading.effects['competitions/getSettings'], + detail, + settings, theme, }; } diff --git a/src/pages/competitions/index.tsx b/src/pages/competitions/index.tsx index 9c7cfe5..0776a57 100644 --- a/src/pages/competitions/index.tsx +++ b/src/pages/competitions/index.tsx @@ -83,7 +83,7 @@ class CompetitionList extends React.Component {
diff --git a/src/pages/competitions/models/competitions.ts b/src/pages/competitions/models/competitions.ts index e3b4611..c6b1876 100644 --- a/src/pages/competitions/models/competitions.ts +++ b/src/pages/competitions/models/competitions.ts @@ -604,6 +604,10 @@ export default { type: 'getDetail', payload: { id: +matchPublicIntro.params['id'] }, }); + requestEffect(dispatch, { + type: 'getSettings', + payload: { id: +matchPublicIntro.params['id'] }, + }); } const matchOverview = matchPath(pathname, { path: pages.competitions.overview,