From 7b16f9bd13db88e023f0471fb7f5679679167f8b Mon Sep 17 00:00:00 2001 From: ReDBrother Date: Sat, 18 Oct 2025 15:50:40 +0300 Subject: [PATCH] add event modal and fix some styles --- .../apps/codebattle/assets/css/custom.scss | 2 - .../app/apps/codebattle/assets/css/style.scss | 10 +- .../apps/codebattle/assets/js/i18n/dayjs.js | 10 + .../apps/codebattle/assets/js/widgets/App.jsx | 4 +- .../widgets/components/LanguagePickerView.jsx | 9 +- .../assets/js/widgets/components/UserInfo.jsx | 4 +- .../assets/js/widgets/config/modalCodes.js | 1 + .../js/widgets/pages/game/AnimationModal.jsx | 14 +- .../js/widgets/pages/game/OutputTab.jsx | 4 +- .../js/widgets/pages/schedule/EventModal.jsx | 240 ++++++++++++++++++ .../widgets/pages/schedule/ScheduleLegend.jsx | 60 +++++ .../pages/schedule/TournamentSchedule.jsx | 120 +++------ .../widgets/pages/tournament/ControlPanel.jsx | 2 +- .../widgets/pages/tournament/ReportsPanel.jsx | 54 +--- .../pages/tournament/TournamentHeader.jsx | 4 +- .../TournamentMainControlButtons.jsx | 21 +- .../assets/js/widgets/slices/leaderboard.js | 16 +- .../utils/useTournamentScheduleModals.js | 21 ++ 18 files changed, 432 insertions(+), 164 deletions(-) create mode 100644 services/app/apps/codebattle/assets/js/i18n/dayjs.js create mode 100644 services/app/apps/codebattle/assets/js/widgets/pages/schedule/EventModal.jsx create mode 100644 services/app/apps/codebattle/assets/js/widgets/pages/schedule/ScheduleLegend.jsx create mode 100644 services/app/apps/codebattle/assets/js/widgets/utils/useTournamentScheduleModals.js diff --git a/services/app/apps/codebattle/assets/css/custom.scss b/services/app/apps/codebattle/assets/css/custom.scss index 6f9c8ff46..71865934d 100644 --- a/services/app/apps/codebattle/assets/css/custom.scss +++ b/services/app/apps/codebattle/assets/css/custom.scss @@ -56,13 +56,11 @@ } .cb-custom-event-td:not(:last-child)::after { - background-color: black; right: 0; top: 8px; } .cb-custom-event-nav-item:not(:first-child):not(.active)::after { - background-color: white; left: 0; top: 13px; } diff --git a/services/app/apps/codebattle/assets/css/style.scss b/services/app/apps/codebattle/assets/css/style.scss index d0d195035..de653d3aa 100644 --- a/services/app/apps/codebattle/assets/css/style.scss +++ b/services/app/apps/codebattle/assets/css/style.scss @@ -2178,7 +2178,8 @@ a.cb-text:hover { background-color: $cb-success; border-color: $cb-success; - &:hover { + &:hover:not(:disabled), + &:hover:not(.disabled) { background-color: $cb-hovered-success; border-color: $cb-hovered-success; } @@ -2187,7 +2188,8 @@ a.cb-text:hover { .cb-btn-outline-success { border-color: $cb-success; - &:hover { + &:hover:not(:disabled), + &:hover:not(.disabled) { background-color: $cb-hovered-success; border-color: $cb-hovered-success; } @@ -2500,3 +2502,7 @@ a.cb-text:hover { // background-color: rgba(90, 123, 151, 0.2); // } // + +.btn-link { + color: white; +} diff --git a/services/app/apps/codebattle/assets/js/i18n/dayjs.js b/services/app/apps/codebattle/assets/js/i18n/dayjs.js new file mode 100644 index 000000000..b6274d5b6 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/i18n/dayjs.js @@ -0,0 +1,10 @@ +import dayjs from 'dayjs'; +import duration from 'dayjs/plugin/duration'; +import timezone from 'dayjs/plugin/timezone'; +import utc from 'dayjs/plugin/utc'; + +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(duration); + +export default dayjs; diff --git a/services/app/apps/codebattle/assets/js/widgets/App.jsx b/services/app/apps/codebattle/assets/js/widgets/App.jsx index bac9c9ea3..864a3baf6 100755 --- a/services/app/apps/codebattle/assets/js/widgets/App.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/App.jsx @@ -148,7 +148,9 @@ export const TournamentsSchedulePage = () => ( - + + + diff --git a/services/app/apps/codebattle/assets/js/widgets/components/LanguagePickerView.jsx b/services/app/apps/codebattle/assets/js/widgets/components/LanguagePickerView.jsx index 38ebcfe92..249e81dc2 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/LanguagePickerView.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/LanguagePickerView.jsx @@ -9,7 +9,7 @@ import * as selectors from '../selectors'; import LanguageIcon from './LanguageIcon'; -const customStyle = { +export const customStyle = { control: provided => ({ ...provided, color: 'white', @@ -24,6 +24,10 @@ const customStyle = { borderColor: '#4c4c5a', }, }), + singleValue: provider => ({ + ...provider, + color: 'white', + }), indicatorsContainer: provided => ({ ...provided, height: '29px', @@ -39,14 +43,17 @@ const customStyle = { }), input: provided => ({ ...provided, + color: 'white', height: '21px', }), menu: provided => ({ ...provided, + color: 'white', backgroundColor: '#2a2a35', }), option: provided => ({ ...provided, + color: 'white', backgroundColor: '#2a2a35', ':hover': { backgroundColor: '#3a3f50', diff --git a/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx b/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx index 5953b42be..385e60c95 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/UserInfo.jsx @@ -62,11 +62,11 @@ function UserInfo({ const content = useMemo(() => , [user]); if (!user?.id) { - return John Doe; + return John Doe; } if (user?.id === 0) { - return {user.name}; + return {user.name}; } const isOnline = presenceList.some(({ id }) => id === user?.id); diff --git a/services/app/apps/codebattle/assets/js/widgets/config/modalCodes.js b/services/app/apps/codebattle/assets/js/widgets/config/modalCodes.js index 06aec1e87..8defb3212 100644 --- a/services/app/apps/codebattle/assets/js/widgets/config/modalCodes.js +++ b/services/app/apps/codebattle/assets/js/widgets/config/modalCodes.js @@ -8,6 +8,7 @@ const modalCodes = { premiumRestrictionModal: 'premium_restriction_modal', awardModal: 'award_modal', eventStageModal: 'event_stage_modal', + calendarEventModal: 'calendar_event_modal', }; export default modalCodes; diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/game/AnimationModal.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/game/AnimationModal.jsx index 22d15cd5b..fcc23ece7 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/game/AnimationModal.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/game/AnimationModal.jsx @@ -35,6 +35,13 @@ const AnimationModal = NiceModal.create(() => { const currentUserId = useSelector(state => currentUserIdSelector(state)); const tournamentId = useSelector(state => state.game.gameStatus.tournamentId); + useEffect(() => { + if (modal.visible) { + NiceModal.hide(ModalCodes.premiumRestrictionModal); + NiceModal.hide(ModalCodes.taskDescriptionModal); + } + }, [modal.visible]); + const currentPlayer = players[currentUserId]; if (!currentPlayer || currentPlayer.result === 'undefined') { @@ -48,13 +55,6 @@ const AnimationModal = NiceModal.create(() => { : i18n.t("If you read this you've lost the game"); const buttonText = result === 'won' ? i18n.t('GG') : i18n.t("I'll be back"); - useEffect(() => { - if (modal.visible) { - NiceModal.hide(ModalCodes.premiumRestrictionModal); - NiceModal.hide(ModalCodes.taskDescriptionModal); - } - }, [modal.visible]); - return ( { return ( <> - {isShowMessage && {assertsStatusMessage}} - {message} + {isShowMessage && {assertsStatusMessage}} + {message} ); }; diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/schedule/EventModal.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/EventModal.jsx new file mode 100644 index 000000000..85714fd63 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/EventModal.jsx @@ -0,0 +1,240 @@ +import React, { + memo, useCallback, useEffect, useState, +} from 'react'; + +import NiceModal, { useModal } from '@ebay/nice-modal-react'; +import cn from 'classnames'; +import i18n from 'i18next'; +import capitalize from 'lodash/capitalize'; +import Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import { useSelector } from 'react-redux'; + +import { currentUserIsAdminSelector } from '@/selectors'; + +import dayjs from '../../../i18n/dayjs'; +import ModalCodes from '../../config/modalCodes'; + +import { grades } from './TournamentSchedule'; + +const getRankingPoints = grade => { + switch (grade) { + case grades.rookie: return [8, 4, 2]; + case grades.challenger: return [16, 8, 4, 2]; + case grades.pro: return [128, 64, 32, 16, 8, 4, 2]; + case grades.elite: return [256, 128, 64, 32, 16, 8, 4, 2]; + case grades.masters: return [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2]; + case grades.grandSlam: return [2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2]; + default: return [0]; + } +}; + +const getTasksCount = grade => { + switch (grade) { + case grades.rookie: return 4; + case grades.challenger: return 6; + case grades.pro: return 8; + case grades.elite: return 10; + case grades.masters: return 12; + case grades.grandSlam: return 14; + default: return 0; + } +}; + +const GradeInfo = ({ grade, selected }) => ( +
+ + {capitalize(grade)} + {selected === grade ? ' (*)' : ''} + + + [ + {getRankingPoints(grade).join(', ')} + ] + +
+); + +const Timer = ({ date = new Date(), label }) => { + const [duration, setDuration] = useState(0); + const [stoped, setStoped] = useState(0); + + useEffect(() => { + if (stoped) { + return () => { }; + } + + const interval = setInterval(() => { + setDuration(dayjs(date).diff(dayjs())); + }, 100); + + return () => { + clearInterval(interval); + }; + }, [date, stoped, setDuration]); + + if (stoped || duration > 1000 * 60 * 60 * 24) { + return <>; + } + + if (duration < 0) { + setStoped(true); + return <>; + } + + return ( + <> + {label} + {' '} + {dayjs.duration(duration).format('HH:mm:ss')} + + ); +}; + +export const EventModal = NiceModal.create(({ event: selectedEvent, events, clearEvent }) => { + const [currentEvent, setCurrentEvent] = useState(); + const [prevEvent, setPrevEvent] = useState(); + const [nextEvent, setNextEvent] = useState(); + + const isAdmin = useSelector(currentUserIsAdminSelector); + + const modal = useModal(ModalCodes.calendarEventModal); + + const event = currentEvent || selectedEvent; + const isUpcoming = event?.resourse?.grade === 'upcoming'; + + useEffect(() => { + if (event) { + const sortedEvents = events.sort((a, b) => dayjs(a.start).diff(dayjs(b.start))); + const eventIndex = sortedEvents.findIndex(e => e.resourse.id === event.resourse.id); + + if (eventIndex === -1) return; + + if (eventIndex < 1) { + setPrevEvent(undefined); + } else { + setPrevEvent(sortedEvents[eventIndex - 1]); + } + + if (eventIndex > events.length - 2) { + setNextEvent(undefined); + } else { + setNextEvent(sortedEvents[eventIndex + 1]); + } + } + }, [event, events, setPrevEvent, setNextEvent]); + + const clickPrev = useCallback(() => { + setCurrentEvent(prevEvent); + }, [setCurrentEvent, prevEvent]); + const clickNext = useCallback(() => { + setCurrentEvent(nextEvent); + }, [setCurrentEvent, nextEvent]); + const handleClose = useCallback(() => { + modal.hide(); + clearEvent(); + }, [modal, clearEvent]); + + return ( + + + + {event.resourse.grade !== grades.open && Codebattle League 2025} + {i18n.t('Tournament: %{name}', { name: event.title })} + + + +
+
+
+ {prevEvent && ( +
{ }} + className="btn-link" + tabIndex="0" + > + {'<<'} + {prevEvent.title} +
+ )} +
+
+ {nextEvent && ( +
{ }} + className="btn-link" + tabIndex="0" + > + {nextEvent.title} + {'>>'} +
+ )} +
+
+
+ {`Start Date: ${dayjs(event.start).format('MMMM DD, YYYY')}`} + {`Time: ${dayjs(event.start).format('hh:mm A')} - ${dayjs(event.end).format('hh:mm A')}`} + {event.resourse.grade !== grades.open + && {`First Place Points: ${getRankingPoints(event.resourse.grade)[0]} Ranking Points`}} + +
+
+ {event.resourse.grade !== grades.open ? ( + <> + Tournament Highlights: + Prizes: Codebattle T-shirt merch for a top-tier of League + {`Challenges: ${getTasksCount(event.resourse.grade)} unique algorithm problems`} + Impact: Advancing in the Codebattle programmer rankings +
+
+
View League Ranking Points System
+
+ {[grades.rookie, grades.challenger, grades.pro, grades.elite, grades.masters, grades.grandSlam].map(grade => ( + + ))} +
+
+
+ + ) : ( + <> + Tournament Description: + {event.resourse.description} + + )} +
+
+
+ + {event.resourse.id && ( + + {i18n.t('Open Tournament')} + + )} + + +
+ ); +}); + +export default memo(EventModal); diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/schedule/ScheduleLegend.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/ScheduleLegend.jsx new file mode 100644 index 000000000..2bb106bd3 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/ScheduleLegend.jsx @@ -0,0 +1,60 @@ +import React from 'react'; + +import cn from 'classnames'; +import { useSelector } from 'react-redux'; + +import { currentUserIsAdminSelector } from '@/selectors'; + +export const states = { + contest: '#contest', + my: '#my', + all: '#all', +}; + +const sectionBtnClassName = cn( + 'btn btn-secondary border-0 cb-btn-secondary cb-rounded mx-2', +); + +const ScheduleLegend = ({ onChangeContext, loading, context }) => { + const isAdmin = useSelector(currentUserIsAdminSelector); + + return ( +
+ + + {isAdmin && ( + + )} +
+ ); +}; + +export default ScheduleLegend; diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/schedule/TournamentSchedule.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/TournamentSchedule.jsx index 86f104273..b26eed602 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/schedule/TournamentSchedule.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/schedule/TournamentSchedule.jsx @@ -1,5 +1,6 @@ import React, { useCallback, useEffect, useState } from 'react'; +import NiceModal from '@ebay/nice-modal-react'; import cn from 'classnames'; import dayjs from 'dayjs'; import uniqBy from 'lodash/uniqBy'; @@ -8,10 +9,13 @@ import { useSelector } from 'react-redux'; import { uploadTournamentsByFilter } from '@/middlewares/Tournament'; import { currentUserIdSelector, currentUserIsAdminSelector } from '@/selectors'; +import useTournamentScheduleModals from '@/utils/useTournamentScheduleModals'; -import tournamentStates from '../../config/tournament'; +import ModalCodes from '../../config/modalCodes'; -const grades = { +import ScheduleLegend, { states } from './ScheduleLegend'; + +export const grades = { open: 'open', rookie: 'rookie', challenger: 'challenger', @@ -21,12 +25,6 @@ const grades = { grandSlam: 'grand_slam', }; -const states = { - contest: '#contest', - my: '#my', - all: '#all', -}; - const views = { month: 'month', week: 'week', @@ -34,7 +32,6 @@ const views = { agenda: 'agenda', }; -// const filterRookieGrade = e => !(e.resourse.grade === 'rookie' && e.resourse.state === tournamentStates.upcoming); const haveSeasonGrade = t => t.grade !== grades.open; const filterMyTournaments = userId => t => t.ownerId === userId; @@ -62,6 +59,7 @@ const getEventFromTournamentData = t => ({ .toDate(), resourse: { id: t.id, + description: t.description, state: t.state, grade: t.grade, }, @@ -103,21 +101,18 @@ const checkNeedLoading = (oldData, newDate) => { const TournamentSchedule = () => { const [event, setSelectedEvent] = useState(null); const [context, setContext] = useState(getStateFromHash); - const [hash, setHash] = useState({ + const [tournaments, setTournaments] = useState({ seasonTournaments: [], userTournaments: [], loading: true, }); - const [tournaments, setTournaments] = useState([]); const [events, setEvents] = useState([]); const [date, setDate] = useState(dayjs().format()); const [view, setView] = useState(views.month); const isAdmin = useSelector(currentUserIsAdminSelector); const currentUserId = useSelector(currentUserIdSelector); - const sectionBtnClassName = cn( - 'btn btn-secondary border-0 cb-btn-secondary cb-rounded mx-2', - ); + useTournamentScheduleModals(); const codebattleLocalizer = dayjsLocalizer(dayjs); @@ -126,7 +121,7 @@ const TournamentSchedule = () => { const endMonth = dayjs(newDate).endOf('month').toISOString(); const [seasonTournaments, userTournaments] = await uploadTournamentsByFilter(beginMonth, endMonth); - setHash({ seasonTournaments, userTournaments, loading: false }); + setTournaments({ seasonTournaments, userTournaments, loading: false }); }; const onView = useCallback( @@ -156,7 +151,7 @@ const TournamentSchedule = () => { const onNavigate = newDate => { if (checkNeedLoading(date, newDate)) { const abortController = new AbortController(); - setHash(state => ({ ...state, loading: true })); + setTournaments(state => ({ ...state, loading: true })); setEvents([]); loadTournaments(abortController, newDate).catch(e => { console.error(e); @@ -180,84 +175,51 @@ const TournamentSchedule = () => { return; } + if (tournaments.loading) { + setEvents([]); + return; + } + if (context === states.contest) { - const newTournaments = uniqBy([ - ...hash.seasonTournaments, - ...hash.userTournaments.filter(haveSeasonGrade), - ], 'id'); + const newEvents = uniqBy([ + ...tournaments.seasonTournaments, + ...tournaments.userTournaments.filter(haveSeasonGrade), + ], 'id').map(getEventFromTournamentData); - setTournaments(newTournaments); + setEvents(newEvents); } else if (context === states.my) { - setTournaments( - hash.userTournaments.filter(filterMyTournaments(currentUserId)), - ); - } else if (context === states.all) { - const newTournaments = uniqBy([ - ...hash.seasonTournaments, - ...hash.userTournaments, - ], 'id'); + const newEvents = tournaments.userTournaments + .filter(filterMyTournaments(currentUserId)) + .map(getEventFromTournamentData); - setTournaments(newTournaments); - } - }, [context, hash, setTournaments, currentUserId, isAdmin]); + setEvents(newEvents); + } else if (context === states.all) { + const newEvents = uniqBy([ + ...tournaments.seasonTournaments, + ...tournaments.userTournaments, + ], 'id').map(getEventFromTournamentData); - useEffect(() => { - if (tournaments) { - setEvents(tournaments.map(getEventFromTournamentData)); + setEvents(newEvents); } - }, [tournaments]); + }, [context, currentUserId, tournaments, isAdmin]); useEffect(() => { - if ( - event?.resourse - && event?.resourse?.state !== tournamentStates.upcoming - ) { - window.location.href = `/tournaments/${event.resourse.id}`; + if (event) { + NiceModal.show(ModalCodes.calendarEventModal, { event, events, clearEvent: setSelectedEvent }); } - }, [event]); - - // const filteredEvents = events.filter(filterRookieGrade); + /* eslint-disable-next-line */ + }, [event, setSelectedEvent]); return (
-
- - - {isAdmin && ( - - )} -
+ ({ - ...provided, - height: '33px', - minHeight: '31px', - minWidth: '210px', - borderRadius: '0.3rem', - backgroundColor: 'hsl(0, 0%, 100%)', - }), - indicatorsContainer: provided => ({ - ...provided, - height: '29px', - }), - clearIndicator: provided => ({ - ...provided, - padding: '5px', - }), - dropdownIndicator: provided => ({ - ...provided, - padding: '5px', - }), - input: provided => ({ - ...provided, - height: '21px', - }), -}; - const customEventTrClassName = cn( - 'text-dark cb-custom-event-tr', + 'cb-custom-event-tr align-items-center', ); const tableDataCellClassName = cn( - 'p-1 pl-4 my-2 align-middle text-nowrap position-relative cb-custom-event-td border-0', + 'p-1 pl-4 my-2 ml-2 align-middle text-nowrap position-relative cb-custom-event-td border-0', ); const reportStatusOptions = [ @@ -85,8 +59,8 @@ function ReportsPanel() { return (
- - +
+
{i18next.t('Offender')} @@ -123,20 +97,18 @@ function ReportsPanel() { -

- {moment - .utc(item.insertedAt) - .local() - .format('YYYY-MM-DD HH:mm:ss')} -

+ + {dayjs(item.insertedAt) + .format('YYYY-MM-DD HH:mm:ss')} +
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentHeader.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentHeader.jsx index 41d49e0e1..7e9b2756e 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentHeader.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentHeader.jsx @@ -185,7 +185,7 @@ function TournamentHeader({ }, ); const copyBtnClassName = cn('btn btn-sm rounded-right', { - 'btn-secondary': !hasCustomEventStyle, + 'btn-secondary cb-btn-secondary': !hasCustomEventStyle, 'cb-custom-event-btn-secondary': hasCustomEventStyle, }); // const backBtnClassName = cn('btn rounded-lg ml-lg-2 mr-2', { @@ -328,7 +328,7 @@ function TournamentHeader({ |
- +
diff --git a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx index ec8d2d186..329885b1b 100644 --- a/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/pages/tournament/TournamentMainControlButtons.jsx @@ -1,11 +1,10 @@ -import React, { memo, useCallback, useContext } from 'react'; +import React, { memo, useCallback } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import cn from 'classnames'; import Dropdown from 'react-bootstrap/Dropdown'; import { useDispatch } from 'react-redux'; -import CustomEventStylesContext from '../../components/CustomEventStylesContext'; import { cancelTournament, restartTournament as handleRestartTournament, @@ -45,8 +44,6 @@ const TournamentMainControlButtons = ({ }) => { const dispatch = useDispatch(); - const hasCustomEventStyles = useContext(CustomEventStylesContext); - const handleStartTournament = useCallback(() => { handleStartRound('firstRound'); }, [handleStartRound]); @@ -57,21 +54,13 @@ const TournamentMainControlButtons = ({ handleStartRound('nextRound'); }, [handleStartRound]); - const restartBtnClassName = cn('btn text-white text-nowrap ml-lg-2 rounded-left', { - 'btn-info': !hasCustomEventStyles, - 'cb-custom-event-btn-info': hasCustomEventStyles, - }); - const roundBtnClassName = cn('btn text-white text-nowrap ml-lg-2 rounded-left', { - 'btn-success': !hasCustomEventStyles, - 'cb-custom-event-btn-success': hasCustomEventStyles, - }); + const restartBtnClassName = cn('btn text-nowrap ml-lg-2 rounded-left btn-secondary cb-btn-secondary'); + const roundBtnClassName = cn('btn text-nowrap ml-lg-2 rounded-left btn-success cb-btn-success text-white'); const dropdownBtnClassName = cn('btn text-white rounded-right', { 'rounded-left': streamMode, - 'btn-info': !hasCustomEventStyles && canRestart, - 'btn-success': !hasCustomEventStyles && !canRestart, - 'cb-custom-event-btn-info': hasCustomEventStyles && canRestart, - 'cb-custom-event-btn-success': hasCustomEventStyles && !canRestart, + 'btn-secondary cb-btn-secondary': canRestart, + 'btn-success cb-btn-success text-white': !canRestart, }); return ( diff --git a/services/app/apps/codebattle/assets/js/widgets/slices/leaderboard.js b/services/app/apps/codebattle/assets/js/widgets/slices/leaderboard.js index 2bc1d2ea3..9b55e358a 100644 --- a/services/app/apps/codebattle/assets/js/widgets/slices/leaderboard.js +++ b/services/app/apps/codebattle/assets/js/widgets/slices/leaderboard.js @@ -30,14 +30,14 @@ const fetchUsers = createAsyncThunk( }; const params = periodType === periodTypes.ALL - ? baseParams - : { - ...baseParams, - date_from: moment() - .startOf(periodMapping[periodType]) - .utc() - .format('YYYY-MM-DD'), - }; + ? baseParams + : { + ...baseParams, + date_from: moment() + .startOf(periodMapping[periodType]) + .utc() + .format('YYYY-MM-DD'), + }; const response = await axios.get('/api/v1/users', { params }); diff --git a/services/app/apps/codebattle/assets/js/widgets/utils/useTournamentScheduleModals.js b/services/app/apps/codebattle/assets/js/widgets/utils/useTournamentScheduleModals.js new file mode 100644 index 000000000..7efb620b1 --- /dev/null +++ b/services/app/apps/codebattle/assets/js/widgets/utils/useTournamentScheduleModals.js @@ -0,0 +1,21 @@ +import { useEffect } from 'react'; + +import NiceModal, { unregister } from '@ebay/nice-modal-react'; + +import ModalCodes from '../config/modalCodes'; +import { EventModal } from '../pages/schedule/EventModal'; + +const useTournamentScheduleModals = () => { + useEffect(() => { + NiceModal.register(ModalCodes.calendarEventModal, EventModal); + + const unregisterModals = () => { + unregister(ModalCodes.calendarEventModal); + }; + + return unregisterModals; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); +}; + +export default useTournamentScheduleModals;