From 42dff402309ef995d38f9759fbb24fbb322293b3 Mon Sep 17 00:00:00 2001 From: Yan Yunitski Date: Fri, 8 Sep 2023 15:40:20 +0300 Subject: [PATCH] linter improvements --- services/app/apps/codebattle/.eslintrc.yml | 25 +- services/app/apps/codebattle/.prettierrc.json | 9 + .../assets/js/__mocks__/react-select.jsx | 20 +- .../js/__mocks__/react-select/async.jsx | 16 +- .../js/__tests__/ContributorsList.test.jsx | 22 +- .../assets/js/__tests__/LobbyWidget.test.jsx | 264 ++- .../assets/js/__tests__/RatingList.test.jsx | 20 +- .../assets/js/__tests__/Registration.test.jsx | 4 +- .../js/__tests__/RootContainer.test.jsx | 101 +- .../assets/js/__tests__/UserSettings.test.jsx | 44 +- .../js/__tests__/WaitingOpponentInfo.test.jsx | 6 +- .../assets/js/__tests__/helpers/index.js | 9 +- services/app/apps/codebattle/assets/js/app.js | 8 +- .../apps/codebattle/assets/js/widgets/App.jsx | 248 +-- .../js/widgets/components/AccordeonBox.jsx | 105 +- .../assets/js/widgets/components/Card.jsx | 14 +- .../js/widgets/components/ChatContextMenu.jsx | 95 +- .../js/widgets/components/ChatHeader.jsx | 6 +- .../js/widgets/components/ChatInput.jsx | 34 +- .../js/widgets/components/CopyButton.jsx | 6 +- .../js/widgets/components/CountdownTimer.jsx | 9 +- .../components/DropdownMenuDefault.jsx | 43 +- .../assets/js/widgets/components/Editor.jsx | 126 +- .../js/widgets/components/EmojiPicker.jsx | 12 +- .../js/widgets/components/EmojiTooltip.jsx | 45 +- .../js/widgets/components/ExtensionPopup.jsx | 42 +- .../components/FeedbackAlertNotification.jsx | 19 +- .../js/widgets/components/FeedbackWidget.jsx | 59 +- .../js/widgets/components/GameLevelBadge.jsx | 17 +- .../js/widgets/components/GamesHeatmap.jsx | 10 +- .../widgets/components/InvitesContainer.jsx | 133 +- .../js/widgets/components/LanguageIcon.jsx | 16 +- .../js/widgets/components/LanguagePicker.jsx | 11 +- .../widgets/components/LanguagePickerView.jsx | 96 +- .../assets/js/widgets/components/Loading.jsx | 17 +- .../assets/js/widgets/components/Message.jsx | 31 +- .../assets/js/widgets/components/Messages.jsx | 52 +- .../assets/js/widgets/components/Modal.js | 5 +- .../js/widgets/components/PlayerLoading.jsx | 12 +- .../components/PopoverStickOnHover.jsx | 36 +- .../js/widgets/components/ResultIcon.jsx | 18 +- .../assets/js/widgets/components/Rooms.jsx | 42 +- .../widgets/components/SideScrollControls.jsx | 54 +- .../js/widgets/components/TournamentType.jsx | 9 +- .../widgets/components/UserAchievements.jsx | 24 +- .../assets/js/widgets/components/UserInfo.jsx | 30 +- .../assets/js/widgets/components/UserName.jsx | 47 +- .../js/widgets/components/UserStats.jsx | 18 +- .../config/editorSettingsByUserType.js | 14 +- .../js/widgets/config/editorUserTypes.js | 2 +- .../assets/js/widgets/config/hashLinkNames.js | 8 +- .../assets/js/widgets/config/levelRatio.js | 8 +- .../assets/js/widgets/config/solutionTypes.js | 8 +- .../assets/js/widgets/config/tournament.js | 10 +- .../codebattle/assets/js/widgets/index.jsx | 36 +- .../assets/js/widgets/lib/player.js | 66 +- .../codebattle/assets/js/widgets/lib/sound.js | 13 +- .../assets/js/widgets/machines/editor.js | 28 +- .../assets/js/widgets/machines/game.js | 13 +- .../assets/js/widgets/machines/selectors.js | 43 +- .../assets/js/widgets/machines/task.js | 17 +- .../assets/js/widgets/middlewares/Chat.js | 19 +- .../assets/js/widgets/middlewares/Game.js | 533 +++--- .../assets/js/widgets/middlewares/Invite.js | 79 +- .../assets/js/widgets/middlewares/Lobby.js | 57 +- .../assets/js/widgets/middlewares/Main.js | 32 +- .../assets/js/widgets/middlewares/Room.js | 12 +- .../js/widgets/middlewares/StairwayGame.js | 28 +- .../js/widgets/middlewares/Tournament.js | 37 +- .../assets/js/widgets/middlewares/Users.js | 57 +- .../js/widgets/pages/GameRoomWidget.jsx | 62 +- .../widgets/pages/builder/AssertsOutput.jsx | 17 +- .../pages/builder/BackToTaskBuilderButton.jsx | 7 +- .../widgets/pages/builder/BuilderActions.jsx | 52 +- .../pages/builder/BuilderEditorsWidget.jsx | 129 +- .../pages/builder/BuilderExampleForm.jsx | 256 +-- .../pages/builder/BuilderSettingsWidget.jsx | 30 +- .../widgets/pages/builder/BuilderStatus.jsx | 37 +- .../pages/builder/BuilderTaskAssignment.jsx | 89 +- .../widgets/pages/builder/ExamplePreview.jsx | 26 +- .../pages/builder/ExamplesEditPanel.jsx | 97 +- .../widgets/pages/builder/ExamplesTrack.jsx | 137 +- .../pages/builder/InputSignatureEditPanel.jsx | 85 +- .../builder/OutputSignatureEditPanel.jsx | 37 +- .../pages/builder/PreviewAssertsPanel.jsx | 74 +- .../widgets/pages/builder/SignatureForm.jsx | 48 +- .../pages/builder/SignaturePreview.jsx | 26 +- .../widgets/pages/builder/SignatureTrack.jsx | 139 +- .../pages/builder/TaskConfigurationModal.jsx | 20 +- .../pages/builder/TaskConfirmationModal.jsx | 28 +- .../pages/builder/TaskPropStatusIcon.jsx | 43 +- .../widgets/pages/game/ActionsAfterGame.jsx | 8 +- .../js/widgets/pages/game/AnimationModal.jsx | 17 +- .../pages/game/ApprovePlaybookButtons.jsx | 64 +- .../widgets/pages/game/BackToHomeButton.jsx | 2 +- .../js/widgets/pages/game/ChatWidget.jsx | 54 +- .../widgets/pages/game/CodebattlePlayer.jsx | 66 +- .../pages/game/CodebattleSliderBar.jsx | 145 +- .../widgets/pages/game/ContributorsList.jsx | 32 +- .../js/widgets/pages/game/ControlPanel.jsx | 30 +- .../js/widgets/pages/game/DarkModeButton.jsx | 4 +- .../js/widgets/pages/game/EditorContainer.jsx | 102 +- .../pages/game/EditorHeightButtons.jsx | 14 +- .../js/widgets/pages/game/EditorToolbar.jsx | 104 +- .../widgets/pages/game/GameActionButtons.jsx | 36 +- .../js/widgets/pages/game/GameResult.jsx | 40 +- .../js/widgets/pages/game/GameResultIcon.jsx | 18 +- .../js/widgets/pages/game/GameWidget.jsx | 101 +- .../js/widgets/pages/game/GoToNextGame.jsx | 18 +- .../js/widgets/pages/game/InfoWidget.jsx | 45 +- .../js/widgets/pages/game/NetworkAlert.jsx | 7 +- .../js/widgets/pages/game/NewGameButton.jsx | 16 +- .../js/widgets/pages/game/Notifications.jsx | 29 +- .../assets/js/widgets/pages/game/Output.jsx | 50 +- .../js/widgets/pages/game/OutputTab.jsx | 14 +- .../js/widgets/pages/game/RematchButton.jsx | 39 +- .../pages/game/ReplayerControlButton.jsx | 16 +- .../js/widgets/pages/game/SignUpButton.jsx | 12 +- .../pages/game/StartTrainingButton.jsx | 4 +- .../js/widgets/pages/game/TaskAssignment.jsx | 18 +- .../pages/game/TaskDescriptionMarkdown.jsx | 34 +- .../pages/game/TaskLanguageSelection.jsx | 12 +- .../js/widgets/pages/game/TimerContainer.jsx | 10 +- .../js/widgets/pages/game/UserGameScore.jsx | 2 +- .../js/widgets/pages/game/VimModeButton.jsx | 4 +- .../pages/game/WaitingOpponentInfo.jsx | 12 +- .../js/widgets/pages/lobby/Announcement.jsx | 46 +- .../widgets/pages/lobby/ChatActionModal.jsx | 98 +- .../js/widgets/pages/lobby/CompletedGames.jsx | 68 +- .../widgets/pages/lobby/CreateGameDialog.jsx | 84 +- .../widgets/pages/lobby/GameActionButton.jsx | 64 +- .../js/widgets/pages/lobby/GameCard.jsx | 68 +- .../widgets/pages/lobby/GameProgressBar.jsx | 13 +- .../widgets/pages/lobby/GameRoomPreview.jsx | 22 +- .../js/widgets/pages/lobby/GameStateBadge.jsx | 4 +- .../js/widgets/pages/lobby/Leaderboard.jsx | 36 +- .../js/widgets/pages/lobby/LobbyChat.jsx | 113 +- .../js/widgets/pages/lobby/LobbyWidget.jsx | 273 ++- .../js/widgets/pages/lobby/ShowButton.jsx | 8 +- .../js/widgets/pages/lobby/TaskChoice.jsx | 121 +- .../js/widgets/pages/lobby/TournamentCard.jsx | 15 +- .../js/widgets/pages/profile/Heatmap.jsx | 10 +- .../js/widgets/pages/profile/UserProfile.jsx | 153 +- .../js/widgets/pages/rating/RatingList.jsx | 64 +- .../pages/registration/Registration.jsx | 322 ++-- .../widgets/pages/settings/UserSettings.jsx | 29 +- .../pages/settings/UserSettingsForm.jsx | 274 ++- .../IndividualIntendedPlayersPanel.jsx | 63 +- .../pages/tournament/IndividualMatches.jsx | 60 +- .../widgets/pages/tournament/JoinButton.jsx | 14 +- .../widgets/pages/tournament/Participants.jsx | 65 +- .../widgets/pages/tournament/PlayerPicker.jsx | 43 +- .../tournament/StairwayEditorContainer.jsx | 12 +- .../tournament/StairwayEditorToolbar.jsx | 80 +- .../pages/tournament/StairwayGameInfo.jsx | 4 +- .../pages/tournament/StairwayOutputTab.jsx | 18 +- .../pages/tournament/StairwayRounds.jsx | 30 +- .../widgets/pages/tournament/TeamMatches.jsx | 43 +- .../widgets/pages/tournament/Tournament.jsx | 141 +- .../pages/tournament/TournamentChat.jsx | 19 +- .../pages/tournament/TournamentChatInput.jsx | 30 +- .../pages/tournament/TournamentHeader.jsx | 69 +- .../TournamentMainControlButtons.jsx | 102 +- .../assets/js/widgets/selectors/index.js | 358 ++-- .../assets/js/widgets/slices/builder.js | 45 +- .../assets/js/widgets/slices/chat.js | 21 +- .../js/widgets/slices/completedGames.js | 23 +- .../assets/js/widgets/slices/editor.js | 15 +- .../js/widgets/slices/executionOutput.js | 10 +- .../assets/js/widgets/slices/game.js | 5 +- .../assets/js/widgets/slices/index.js | 12 +- .../assets/js/widgets/slices/initial.js | 94 +- .../assets/js/widgets/slices/invites.js | 2 +- .../assets/js/widgets/slices/leaderboard.js | 49 +- .../assets/js/widgets/slices/lobby.js | 21 +- .../assets/js/widgets/slices/playbook.js | 4 +- .../assets/js/widgets/slices/stairway.js | 2 +- .../assets/js/widgets/slices/user.js | 16 +- .../assets/js/widgets/slices/userSettings.js | 8 +- .../assets/js/widgets/utils/builder.js | 50 +- .../assets/js/widgets/utils/chat.js | 42 +- .../assets/js/widgets/utils/editor.js | 4 +- .../assets/js/widgets/utils/gameRoom.js | 16 +- .../assets/js/widgets/utils/names.js | 2 +- .../assets/js/widgets/utils/notification.js | 4 +- .../assets/js/widgets/utils/urlBuilders.js | 4 +- .../js/widgets/utils/useChatContextMenu.js | 49 +- .../assets/js/widgets/utils/useChatRooms.js | 7 +- .../assets/js/widgets/utils/useClickAway.js | 42 +- .../assets/js/widgets/utils/useEvent.js | 48 +- .../js/widgets/utils/useGameRoomMachine.js | 36 +- .../assets/js/widgets/utils/useKey.js | 37 +- .../widgets/utils/useTaskDescriptionParams.js | 7 +- .../js/widgets/utils/useValidationExample.js | 39 +- .../assets/js/widgets/utils/users.js | 4 +- services/app/apps/codebattle/package.json | 25 +- services/app/apps/codebattle/yarn.lock | 1533 +++++++++++------ 197 files changed, 5573 insertions(+), 5566 deletions(-) create mode 100644 services/app/apps/codebattle/.prettierrc.json diff --git a/services/app/apps/codebattle/.eslintrc.yml b/services/app/apps/codebattle/.eslintrc.yml index 8b30adc47..eda6e562c 100644 --- a/services/app/apps/codebattle/.eslintrc.yml +++ b/services/app/apps/codebattle/.eslintrc.yml @@ -6,6 +6,7 @@ plugins: - jsx-a11y - jest - react-hooks + - sort-destructure-keys env: node: true browser: true @@ -15,6 +16,7 @@ parser: "@babel/eslint-parser" extends: - "airbnb" - "plugin:jest/recommended" + - "plugin:prettier/recommended" rules: no-console: 0 @@ -43,13 +45,31 @@ rules: group: internal pathGroupsExcludedImportTypes: - internal + import/extensions: + - error + - js: never + jsx: never no-param-reassign: 0 arrow-parens: - 2 - - "as-needed" + - "always" react/jsx-props-no-spreading: 0 react/static-property-placement: 0 react/state-in-constructor: 0 + react/function-component-definition: "off" + react/jsx-sort-props: + - 1 + - callbacksLast: true + shorthandFirst: true + shorthandLast: false + ignoreCase: false + noSortAlphabetically: false + reservedFirst: true + multiline: last + react/no-unstable-nested-components: + - warn + - allowAsProps: true + class-methods-use-this: "off" jest/no-disabled-tests: "warn" jest/no-focused-tests: "error" jest/no-identical-title: "error" @@ -60,3 +80,6 @@ rules: template-curly-spacing: "off" indent: "off" max-len: ["error", 140, 2] + sort-destructure-keys/sort-destructure-keys: + - 1 + - caseSensitive: false diff --git a/services/app/apps/codebattle/.prettierrc.json b/services/app/apps/codebattle/.prettierrc.json new file mode 100644 index 000000000..768f983d7 --- /dev/null +++ b/services/app/apps/codebattle/.prettierrc.json @@ -0,0 +1,9 @@ +{ + "printWidth": 100, + "trailingComma": "all", + "tabWidth": 2, + "singleQuote": true, + "jsxSingleQuote": false, + "bracketSameLine": false, + "arrowParens": "always" +} diff --git a/services/app/apps/codebattle/assets/js/__mocks__/react-select.jsx b/services/app/apps/codebattle/assets/js/__mocks__/react-select.jsx index 906f67f6c..b50939797 100644 --- a/services/app/apps/codebattle/assets/js/__mocks__/react-select.jsx +++ b/services/app/apps/codebattle/assets/js/__mocks__/react-select.jsx @@ -1,32 +1,26 @@ import React, { useState } from 'react'; -const Select = ({ options, onChange, filterOption }) => { +function Select({ filterOption, onChange, options }) { const [selectInput, setSelectInput] = useState('task'); return (
{options - .filter(option => ( - filterOption({ value: { name: option.value.name } }, selectInput) - )) - .map(option => ( + .filter((option) => filterOption({ value: { name: option.value.name } }, selectInput)) + .map((option) => ( - ))} -
); -}; +} export default Select; diff --git a/services/app/apps/codebattle/assets/js/__mocks__/react-select/async.jsx b/services/app/apps/codebattle/assets/js/__mocks__/react-select/async.jsx index 1b22dd3a2..905ea69b6 100644 --- a/services/app/apps/codebattle/assets/js/__mocks__/react-select/async.jsx +++ b/services/app/apps/codebattle/assets/js/__mocks__/react-select/async.jsx @@ -1,11 +1,11 @@ import React, { useState, useEffect } from 'react'; -const AsyncSelect = ({ loadOptions, onChange }) => { +function AsyncSelect({ loadOptions, onChange }) { const [entities, setEntities] = useState([]); useEffect(() => { - const callback = options => { - setEntities(options.map(option => option.value)); + const callback = (options) => { + setEntities(options.map((option) => option.value)); }; loadOptions('test', callback); @@ -14,17 +14,13 @@ const AsyncSelect = ({ loadOptions, onChange }) => { return (
- {entities.map(entity => ( - ))}
); -}; +} export default AsyncSelect; diff --git a/services/app/apps/codebattle/assets/js/__tests__/ContributorsList.test.jsx b/services/app/apps/codebattle/assets/js/__tests__/ContributorsList.test.jsx index 2fbc2bfa6..ea76646e8 100644 --- a/services/app/apps/codebattle/assets/js/__tests__/ContributorsList.test.jsx +++ b/services/app/apps/codebattle/assets/js/__tests__/ContributorsList.test.jsx @@ -9,16 +9,20 @@ import { Provider } from 'react-redux'; import ContributorsList from '../widgets/pages/game/ContributorsList'; import reducers from '../widgets/slices'; -jest.mock('gon', () => { - const gonParams = { local: 'en' }; - return { getAsset: type => gonParams[type] }; -}, { virtual: true }); +jest.mock( + 'gon', + () => { + const gonParams = { local: 'en' }; + return { getAsset: (type) => gonParams[type] }; + }, + { virtual: true }, +); jest.mock('axios'); const users = []; axios.get.mockResolvedValue({ data: users }); -test('test rendering ContributorsList', async () => { +test('rendering of ContributorsList', async () => { const reducer = combineReducers(reducers); const preloadedState = { @@ -28,6 +32,10 @@ test('test rendering ContributorsList', async () => { reducer, preloadedState, }); - const { findByText } = render(); - expect(await findByText(/This users have contributed to this task:/)).toBeInTheDocument(); + const { findByText } = render( + + + , + ); + expect(await findByText(/This users have contributed to this task:/)).toBeInTheDocument(); }); diff --git a/services/app/apps/codebattle/assets/js/__tests__/LobbyWidget.test.jsx b/services/app/apps/codebattle/assets/js/__tests__/LobbyWidget.test.jsx index c138cb447..eb0a91090 100644 --- a/services/app/apps/codebattle/assets/js/__tests__/LobbyWidget.test.jsx +++ b/services/app/apps/codebattle/assets/js/__tests__/LobbyWidget.test.jsx @@ -22,7 +22,8 @@ Object.defineProperty(window, 'scrollTo', { jest.mock( '../widgets/components/UserInfo', - () => function UserInfo() { + () => + function UserInfo() { return (
           {`${i18n.t('Receive:')} ${JSON.stringify(result)}`}
-          {`${i18n.t('Expected:')} ${JSON.stringify(assert.expected)}`}
-          {`${i18n.t('Arguments:')} ${JSON.stringify(assert.arguments)}`}
+          {`${i18n.t('Expected:')} ${JSON.stringify(
+            assert.expected,
+          )}`}
+          {`${i18n.t('Arguments:')} ${JSON.stringify(
+            assert.arguments,
+          )}`}
         
{hasOutput && ( - <> -
- {children} -
- +
+ {children} +
)} ); } -const Item = ({ output }) => { +function Item({ output }) { if (output === '') { return null; } @@ -163,7 +186,7 @@ const Item = ({ output }) => { ); -}; +} AccordeonBox.Item = Item; AccordeonBox.Menu = Menu; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Card.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Card.jsx index 95cda3a81..427321ced 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Card.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Card.jsx @@ -1,10 +1,12 @@ import React from 'react'; -const Card = ({ title, children }) => ( -
-

{title}

- {children} -
-); +function Card({ children, title }) { + return ( +
+

{title}

+ {children} +
+ ); +} export default Card; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/ChatContextMenu.jsx b/services/app/apps/codebattle/assets/js/widgets/components/ChatContextMenu.jsx index eac3cc073..3c97cecea 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/ChatContextMenu.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/ChatContextMenu.jsx @@ -1,27 +1,14 @@ -import React, { - useState, - useCallback, - useMemo, - memo, -} from 'react'; +import React, { useState, useCallback, useMemo, memo } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import cn from 'classnames'; import qs from 'qs'; -import { - Menu, - Item, - Separator, -} from 'react-contexify'; +import { Menu, Item, Separator } from 'react-contexify'; import { useSelector, useDispatch } from 'react-redux'; import { pushCommand } from '@/middlewares/Chat'; import { openDirect } from '@/middlewares/Lobby'; -import { - currentUserIsAdminSelector, - currentUserIdSelector, - lobbyDataSelector, -} from '@/selectors'; +import { currentUserIsAdminSelector, currentUserIdSelector, lobbyDataSelector } from '@/selectors'; import { actions } from '@/slices'; import { getLobbyUrl, getUserProfileUrl } from '@/utils/urlBuilders'; @@ -29,6 +16,9 @@ const blackSwordSrc = '/assets/images/fight-black.png'; const whiteSwordSrc = '/assets/images/fight-white.png'; function ChatContextMenu({ + children, + inputRef, + menuId, request = { user: { name: null, @@ -37,31 +27,22 @@ function ChatContextMenu({ canInvite: false, }, }, - menuId, - inputRef, - children, }) { const dispatch = useDispatch(); const [swordIconSrc, setSwordIconSrc] = useState(blackSwordSrc); - const currentUserIsAdmin = useSelector(state => currentUserIsAdminSelector(state)); + const currentUserIsAdmin = useSelector((state) => currentUserIsAdminSelector(state)); const currentUserId = useSelector(currentUserIdSelector); const { activeGames } = useSelector(lobbyDataSelector); - const { - isBot, - canInvite, - name, - userId, - } = request.user; + const { canInvite, isBot, name, userId } = request.user; const isCurrentUserHasActiveGames = useMemo( - () => ( + () => activeGames || activeGames.length > 0 ? activeGames.some(({ players }) => players.some(({ id }) => id === currentUserId)) - : true - ), + : true, [activeGames, currentUserId], ); const isCurrentUser = !!userId && currentUserId === userId; @@ -99,9 +80,7 @@ function ChatContextMenu({ opponent_id: userId, }); if (`/${window.location.hash}`.startsWith(getLobbyUrl())) { - dispatch( - actions.showCreateGameInviteModal({ opponentInfo: { id: userId, name } }), - ); + dispatch(actions.showCreateGameInviteModal({ opponentInfo: { id: userId, name } })); } else { window.location.href = getLobbyUrl(queryParamsString); } @@ -130,53 +109,36 @@ function ChatContextMenu({ return ( <> {children} - - - + + + Copy Name - - + + Info {canCreatePrivateRoom ? ( - + Direct message ) : null} {canInvite && ( invite - - + + Ban diff --git a/services/app/apps/codebattle/assets/js/widgets/components/ChatHeader.jsx b/services/app/apps/codebattle/assets/js/widgets/components/ChatHeader.jsx index 84badf051..ac6375adc 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/ChatHeader.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/ChatHeader.jsx @@ -7,7 +7,7 @@ import * as selectors from '../selectors'; import Rooms from './Rooms'; -export default function ChatHeader({ showRooms = false, disabled = false }) { +export default function ChatHeader({ disabled = false, showRooms = false }) { const currentUserIsAdmin = useSelector(selectors.currentUserIsAdminSelector); const handleCleanBanned = () => { @@ -19,12 +19,12 @@ export default function ChatHeader({ showRooms = false, disabled = false }) { {showRooms && } {currentUserIsAdmin && ( diff --git a/services/app/apps/codebattle/assets/js/widgets/components/ChatInput.jsx b/services/app/apps/codebattle/assets/js/widgets/components/ChatInput.jsx index 7cda002b7..8e564d145 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/ChatInput.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/ChatInput.jsx @@ -13,18 +13,18 @@ import useClickAway from '../utils/useClickAway'; import EmojiPicker from './EmojiPicker'; import EmojiToolTip from './EmojiTooltip'; -const trimColons = message => message.slice(0, message.lastIndexOf(':')); +const trimColons = (message) => message.slice(0, message.lastIndexOf(':')); -const getColons = message => message.slice(message.lastIndexOf(':') + 1); +const getColons = (message) => message.slice(message.lastIndexOf(':') + 1); -const getTooltipVisibility = async msg => { +const getTooltipVisibility = async (msg) => { const endsWithEmojiCodeRegex = /.*:[a-zA-Z]{0,}([^ ])+$/; if (!endsWithEmojiCodeRegex.test(msg)) return Promise.resolve(false); const colons = getColons(msg); return !isEmpty(await SearchIndex.search(colons)); }; -export default function ChatInput({ inputRef, disabled = false }) { +export default function ChatInput({ disabled = false, inputRef }) { const [isPickerVisible, setPickerVisibility] = useState(false); const [isTooltipVisible, setTooltipVisibility] = useState(false); const [text, setText] = useState(''); @@ -35,7 +35,7 @@ export default function ChatInput({ inputRef, disabled = false }) { setTooltipVisibility(await getTooltipVisibility(value)); }; - const handleSubmit = e => { + const handleSubmit = (e) => { e.preventDefault(); const message = { text, @@ -69,10 +69,7 @@ export default function ChatInput({ inputRef, disabled = false }) { hideTooltip(); await setText(`${before}${native}${after}`); input.focus(); - input.setSelectionRange( - caretPosition + native.length, - caretPosition + native.length, - ); + input.setSelectionRange(caretPosition + native.length, caretPosition + native.length); }; useClickAway( @@ -88,17 +85,14 @@ export default function ChatInput({ inputRef, disabled = false }) { }, []); return ( -
+ {isTooltipVisible && ( )} {isPickerVisible && ( - + )}
diff --git a/services/app/apps/codebattle/assets/js/widgets/components/CopyButton.jsx b/services/app/apps/codebattle/assets/js/widgets/components/CopyButton.jsx index 1d3a6772a..edd93c0fe 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/CopyButton.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/CopyButton.jsx @@ -3,7 +3,7 @@ import React, { useState, useCallback } from 'react'; import copy from 'copy-to-clipboard'; import i18n from 'i18next'; -function CopyButton({ className, value, disabled = false }) { +function CopyButton({ className, disabled = false, value }) { const [copied, setCopied] = useState(false); const onClick = useCallback(() => { @@ -15,11 +15,11 @@ function CopyButton({ className, value, disabled = false }) { return ( diff --git a/services/app/apps/codebattle/assets/js/widgets/components/CountdownTimer.jsx b/services/app/apps/codebattle/assets/js/widgets/components/CountdownTimer.jsx index 69d0edbaa..ad6c4ebad 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/CountdownTimer.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/CountdownTimer.jsx @@ -4,9 +4,7 @@ import cn from 'classnames'; import moment from 'moment'; import PropTypes from 'prop-types'; -const getProgress = (a, b) => ( - 100 - Math.ceil((a / b) * 100) -); +const getProgress = (a, b) => 100 - Math.ceil((a / b) * 100); const getDuration = (time, timeoutSeconds) => { const diff = moment().diff(moment.utc(time)); @@ -47,10 +45,7 @@ function CountdownTimer({ time, timeoutSeconds }) { {timeoutSeconds && 'Timeout in: '} {moment.utc(duration).format('HH:mm:ss')} -
+
); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/DropdownMenuDefault.jsx b/services/app/apps/codebattle/assets/js/widgets/components/DropdownMenuDefault.jsx index baf301ac2..a1208a4d1 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/DropdownMenuDefault.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/DropdownMenuDefault.jsx @@ -3,31 +3,30 @@ import React from 'react'; import i18n from '../../i18n'; import levelToClass from '../config/levelToClass'; -const DropdownItem = ({ level, setLevel, setLevelClass }) => ( - -); +function DropdownItem({ level, setLevel, setLevelClass }) { + return ( + + ); +} const DropdownMenuDefault = ({ currentLevel, setLevel, setLevelClass }) => { - const orderedLevels = ['random', 'elementary', 'easy', 'medium', 'hard'].filter(level => level !== currentLevel); + const orderedLevels = ['random', 'elementary', 'easy', 'medium', 'hard'].filter( + (level) => level !== currentLevel, + ); - return orderedLevels.map(level => ( - + return orderedLevels.map((level) => ( + )); }; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx index 53f70e17b..1f18ec55b 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Editor.jsx @@ -41,16 +41,17 @@ class Editor extends PureComponent { // eslint-disable-next-line react/sort-comp notIncludedSyntaxHightlight = new Set(['haskell', 'elixir']); - ctrPlusS = null + ctrPlusS = null; - remoteKeys = [] + remoteKeys = []; constructor(props) { super(props); this.statusBarRef = React.createRef(); - const convertRemToPixels = rem => rem * parseFloat(getComputedStyle(document.documentElement).fontSize); + // const convertRemToPixels = (rem) => + // rem * parseFloat(getComputedStyle(document.documentElement).fontSize); // statusBarHeight = lineHeight = current fontSize * 1.5 - this.statusBarHeight = convertRemToPixels(1) * 1.5; + // this.statusBarHeight = convertRemToPixels(1) * 1.5; this.options = { tabSize: getLanguageTabSize(props.syntax), insertSpaces: shouldReplaceTabsWithSpaces(props.syntax), @@ -72,18 +73,13 @@ class Editor extends PureComponent { }, }; /** @param {KeyboardEvent} e */ - this.ctrPlusS = e => { + this.ctrPlusS = (e) => { if (e.key === 's' && (e.metaKey || e.ctrlKey)) e.preventDefault(); }; } async componentDidMount() { - const { - mode, - syntax, - checkResult, - toggleMuteSound, - } = this.props; + const { checkResult, mode, syntax, toggleMuteSound } = this.props; this.modes = { default: () => null, @@ -121,12 +117,7 @@ class Editor extends PureComponent { async componentDidUpdate(prevProps, prevState) { const { remote } = this.state; - const { - syntax, - mode, - editable, - loading = false, - } = this.props; + const { editable, loading = false, mode, syntax } = this.props; if (mode !== prevProps.mode) { if (this.currentMode) { @@ -157,16 +148,15 @@ class Editor extends PureComponent { const model = this.editor.getModel(); if (prevProps.syntax !== syntax) { - model.updateOptions({ tabSize: getLanguageTabSize(syntax), insertSpaces: shouldReplaceTabsWithSpaces(syntax) }); + model.updateOptions({ + tabSize: getLanguageTabSize(syntax), + insertSpaces: shouldReplaceTabsWithSpaces(syntax), + }); await this.updateHightLightForNotIncludeSyntax(syntax); } - if ( - prevState.remote !== remote - && remote.cursor.range - && remote.selection.range - ) { + if (prevState.remote !== remote && remote.cursor.range && remote.selection.range) { this.remoteKeys = this.editor.deltaDecorations(this.remoteKeys, Object.values(remote)); } @@ -181,7 +171,7 @@ class Editor extends PureComponent { this.clearCursorListeners(); } - updateHightLightForNotIncludeSyntax = async syntax => { + updateHightLightForNotIncludeSyntax = async (syntax) => { if (this.notIncludedSyntaxHightlight.has(syntax)) { const { default: HighlightRules } = await import( `monaco-ace-tokenizer/lib/ace/definitions/${syntax}` @@ -196,7 +186,7 @@ class Editor extends PureComponent { handleResize = () => this.editor.layout(); - handleChangeCursorSelection = e => { + handleChangeCursorSelection = (e) => { const { editable, gameMode, onChangeCursorSelection } = this.props; const isTournament = gameMode === GameRoomModes.tournament; @@ -210,7 +200,7 @@ class Editor extends PureComponent { } }; - handleChangeCursorPosition = e => { + handleChangeCursorPosition = (e) => { const { editable, onChangeCursorPosition } = this.props; if (editable && onChangeCursorPosition) { @@ -221,9 +211,8 @@ class Editor extends PureComponent { updateRemoteCursorSelection = (startOffset, endOffset) => { const { editable, userType } = this.props; - const userClassName = userType === editorUserTypes.opponent - ? 'cb-remote-opponent' - : 'cb-remote-player'; + const userClassName = + userType === editorUserTypes.opponent ? 'cb-remote-opponent' : 'cb-remote-player'; if (!editable) { const startPosition = this.editor.getModel().getPositionAt(startOffset); @@ -235,27 +224,21 @@ class Editor extends PureComponent { const endLineNumber = endPosition.lineNumber; const selection = { - range: new this.monaco.Range( - startLineNumber, - startColumn, - endLineNumber, - endColumn, - ), + range: new this.monaco.Range(startLineNumber, startColumn, endLineNumber, endColumn), options: { className: `cb-editor-remote-selection ${userClassName}` }, }; - this.setState(state => ({ + this.setState((state) => ({ remote: { ...state.remote, selection }, })); } - } + }; - updateRemoteCursorPosition = offset => { + updateRemoteCursorPosition = (offset) => { const { editable, userType } = this.props; const position = this.editor.getModel().getPositionAt(offset); - const userClassName = userType === editorUserTypes.opponent - ? 'cb-remote-opponent' - : 'cb-remote-player'; + const userClassName = + userType === editorUserTypes.opponent ? 'cb-remote-opponent' : 'cb-remote-player'; if (!editable) { const cursor = { @@ -268,14 +251,14 @@ class Editor extends PureComponent { options: { className: `cb-editor-remote-cursor ${userClassName}` }, }; - this.setState(state => ({ + this.setState((state) => ({ remote: { ...state.remote, cursor, }, })); } - } + }; clearCursorListeners = () => {}; @@ -303,17 +286,11 @@ class Editor extends PureComponent { if (editable && !isTournament && !isBuilder) { this.editor.focus(); } else if (editable && isTournament) { - this.editor.addCommand( - monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, - () => null, - ); + this.editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_V, () => null); this.editor.focus(); } else { // disable copying for spectator - this.editor.addCommand( - monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_C, - () => null, - ); + this.editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KEY_C, () => null); // this.editor.onDidChangeCursorSelection(() => { // const { column, lineNumber } = this.editor.getPosition(); // this.editor.setPosition({ lineNumber, column }); @@ -322,23 +299,15 @@ class Editor extends PureComponent { // this.editor.getModel().updateOptions({ tabSize: this.tabSize }); - this.editor.addCommand( - this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.Enter, - () => null, - ); + this.editor.addCommand(this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.Enter, () => null); - this.editor.addCommand( - this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.KEY_M, - () => null, - ); + this.editor.addCommand(this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.KEY_M, () => null); window.addEventListener('resize', this.handleResize); }; render() { - const { - value, syntax, onChange, theme, loading = false, - } = this.props; + const { loading = false, onChange, syntax, theme, value } = this.props; // FIXME: move here and apply mapping object const mappedSyntax = languages[syntax]; const statusBarClassName = cn('position-absolute px-1', { @@ -346,36 +315,37 @@ class Editor extends PureComponent { 'bg-white text-dark': theme === editorThemes.light, }); - const loadingClassName = cn('position-absolute align-items-center justify-content-center w-100 h-100', { - 'd-flex cb-loading-background': loading, - 'd-none': !loading, - }); + const loadingClassName = cn( + 'position-absolute align-items-center justify-content-center w-100 h-100', + { + 'd-flex cb-loading-background': loading, + 'd-none': !loading, + }, + ); return ( <> -
-
+
+
+ +
); } } -const mapStateToProps = state => { +const mapStateToProps = (state) => { const gameMode = gameModeSelector(state); return { gameMode, diff --git a/services/app/apps/codebattle/assets/js/widgets/components/EmojiPicker.jsx b/services/app/apps/codebattle/assets/js/widgets/components/EmojiPicker.jsx index c3c458991..004524dad 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/EmojiPicker.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/EmojiPicker.jsx @@ -5,22 +5,22 @@ import Picker from '@emoji-mart/react'; import useKey from '../utils/useKey'; -export default function EmojiPicker({ handleSelect, hide, disabled = false }) { +export default function EmojiPicker({ disabled = false, handleSelect, hide }) { useKey('Escape', () => hide(), { event: 'keyup' }); const handleOnClickOutside = () => hide(); return ( ); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/EmojiTooltip.jsx b/services/app/apps/codebattle/assets/js/widgets/components/EmojiTooltip.jsx index 237ef764a..97daaac15 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/EmojiTooltip.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/EmojiTooltip.jsx @@ -10,7 +10,7 @@ export default function EmojiTooltip({ colons, handleSelect, hide }) { const [emojis, setEmojis] = useState([]); const increaseIndex = () => { - setActiveIndex(prevIndex => { + setActiveIndex((prevIndex) => { const increment = prevIndex !== emojis.length - 1 ? 1 : -emojis.length + 1; return prevIndex + increment; }); @@ -19,7 +19,7 @@ export default function EmojiTooltip({ colons, handleSelect, hide }) { useEffect(() => { const fetchEmojis = async () => { const rawEmojis = await SearchIndex.search(colons); - const preparedEmojis = rawEmojis.map(emoji => ({ + const preparedEmojis = rawEmojis.map((emoji) => ({ ...emoji, native: emoji.skins[0].native, colons: emoji.skins[0].shortcodes, @@ -31,7 +31,7 @@ export default function EmojiTooltip({ colons, handleSelect, hide }) { }, [colons]); const decreaseIndex = () => { - setActiveIndex(prevIndex => { + setActiveIndex((prevIndex) => { const decrement = prevIndex !== 0 ? 1 : -emojis.length + 1; return prevIndex - decrement; }); @@ -39,31 +39,38 @@ export default function EmojiTooltip({ colons, handleSelect, hide }) { useKey('Escape', () => hide()); - useKey('Enter', e => { - e.preventDefault(); - handleSelect(emojis[activeIndex]); - }, {}, [activeIndex, emojis]); + useKey( + 'Enter', + (e) => { + e.preventDefault(); + handleSelect(emojis[activeIndex]); + }, + {}, + [activeIndex, emojis], + ); useKey('ArrowUp', () => decreaseIndex(), {}, [emojis]); useKey('ArrowDown', () => increaseIndex(), {}, [emojis]); return ( ); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/ExtensionPopup.jsx b/services/app/apps/codebattle/assets/js/widgets/components/ExtensionPopup.jsx index 0426eda84..1720812cf 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/ExtensionPopup.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/ExtensionPopup.jsx @@ -4,20 +4,23 @@ import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; import { createRoot } from 'react-dom'; -const isExtensionInstalled = info => new Promise(resolve => { - const img = new Image(); - img.src = `chrome-extension://${info.id}/${info.path}`; - img.onload = () => { +const isExtensionInstalled = (info) => + new Promise((resolve) => { + const img = new Image(); + img.src = `chrome-extension://${info.id}/${info.path}`; + img.onload = () => { resolve(true); - }; - img.onerror = () => { - resolve(false); - }; -}); + }; + img.onerror = () => { + resolve(false); + }; + }); function ExtensionPopup() { const [modalShowing, setModalShowing] = useState(true); - const handleHide = () => { setModalShowing(false); }; + const handleHide = () => { + setModalShowing(false); + }; return ( @@ -30,10 +33,10 @@ function ExtensionPopup() {

{'We have a '} chrome extension @@ -42,17 +45,14 @@ function ExtensionPopup() { - @@ -60,7 +60,7 @@ function ExtensionPopup() { ); } -export default domElement => { +export default (domElement) => { const lastCheckExtension = window.localStorage.getItem('lastCheckExtension'); const nowTime = Date.now(); const threeDay = 1000 * 60 * 60 * 24 * 3; @@ -68,7 +68,7 @@ export default domElement => { if (window.chrome && isExpired) { // TODO: move to env config extension id and icon path const extensionInfo = { id: 'embfhnfkfobkdohleknckodkmhgmpdli', path: 'assets/128.png' }; - isExtensionInstalled(extensionInfo).then(isInstall => { + isExtensionInstalled(extensionInfo).then((isInstall) => { if (!isInstall) { window.localStorage.setItem('lastCheckExtension', nowTime); createRoot(domElement).render(); diff --git a/services/app/apps/codebattle/assets/js/widgets/components/FeedbackAlertNotification.jsx b/services/app/apps/codebattle/assets/js/widgets/components/FeedbackAlertNotification.jsx index 0a41f0c62..170308452 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/FeedbackAlertNotification.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/FeedbackAlertNotification.jsx @@ -9,7 +9,7 @@ import AlertCodes from '../config/alertCodes'; import { gameAlertsSelector } from '../selectors/index'; import { actions } from '../slices'; -const getNotification = status => { +const getNotification = (status) => { switch (status) { case AlertCodes.feedbackSendSuccessful: { return { @@ -33,12 +33,15 @@ function FeedbackAlertNotification() { const dispatch = useDispatch(); const alerts = useSelector(gameAlertsSelector); - const handleClose = useCallback(id => { - dispatch(actions.deleteAlert(id)); - }, [dispatch]); + const handleClose = useCallback( + (id) => { + dispatch(actions.deleteAlert(id)); + }, + [dispatch], + ); if (isEmpty(alerts)) { - return <>; + return null; } return Object.entries(alerts).map(([key, value]) => { @@ -46,11 +49,11 @@ function FeedbackAlertNotification() { return ( handleClose(key)} key={key} - variant={result.status} + dismissible className="row mb-0 rounded-0 alert alert-info alert-dismissible fade show" + variant={result.status} + onClose={() => handleClose(key)} > {result.message} diff --git a/services/app/apps/codebattle/assets/js/widgets/components/FeedbackWidget.jsx b/services/app/apps/codebattle/assets/js/widgets/components/FeedbackWidget.jsx index bf1adf5ef..c15ddd94d 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/FeedbackWidget.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/FeedbackWidget.jsx @@ -8,47 +8,56 @@ import AlertCodes from '../config/alertCodes'; import { currentUserNameSelector } from '../selectors/index'; import { actions } from '../slices'; -const sendToServer = (payload, success, error) => fetch('/api/v1/feedback', { - method: 'POST', - headers: { - 'Content-type': 'application/json', - 'x-csrf-token': window.csrf_token, - }, - body: JSON.stringify(payload), -}) - .then(success) - .catch(error); +const sendToServer = (payload, success, error) => + fetch('/api/v1/feedback', { + method: 'POST', + headers: { + 'Content-type': 'application/json', + 'x-csrf-token': window.csrf_token, + }, + body: JSON.stringify(payload), + }) + .then(success) + .catch(error); function FeedbackWidget() { const dispatch = useDispatch(); const currentUserName = useSelector(currentUserNameSelector); - const addAlert = useCallback(status => { - dispatch(actions.addAlert({ [Date.now()]: status })); - }, [dispatch]); + const addAlert = useCallback( + (status) => { + dispatch(actions.addAlert({ [Date.now()]: status })); + }, + [dispatch], + ); return ( ( )} - theme={themes.dark} - user={currentUserName} - onSubmit={(payload, success, error) => sendToServer(payload) - .then(() => { - addAlert(AlertCodes.feedbackSendSuccessful); - success(); - }) - .catch(() => { - addAlert(AlertCodes.feedbackSendError); - error(); - })} + onSubmit={(payload, success, error) => + sendToServer(payload) + .then(() => { + addAlert(AlertCodes.feedbackSendSuccessful); + success(); + }) + .catch(() => { + addAlert(AlertCodes.feedbackSendError); + error(); + }) + } /> ); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/GameLevelBadge.jsx b/services/app/apps/codebattle/assets/js/widgets/components/GameLevelBadge.jsx index 0359bd3c1..b95faa15d 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/GameLevelBadge.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/GameLevelBadge.jsx @@ -1,14 +1,11 @@ import React from 'react'; -const GameLevelBadge = ({ level }) => ( -

- {level} -
-); +function GameLevelBadge({ level }) { + return ( +
+ {level} +
+ ); +} export default GameLevelBadge; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/GamesHeatmap.jsx b/services/app/apps/codebattle/assets/js/widgets/components/GamesHeatmap.jsx index cdee780b9..cfe871d1f 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/GamesHeatmap.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/GamesHeatmap.jsx @@ -16,10 +16,10 @@ function GamesHeatmap() { useEffect(() => { axios .get('/api/v1/game_activity') - .then(response => { + .then((response) => { setActivities(response.data.activities); }) - .catch(error => { + .catch((error) => { dispatch(actions.setError(error)); }); }, [dispatch]); @@ -33,13 +33,13 @@ function GamesHeatmap() { { + classForValue={(value) => { if (!value) { return 'color-empty'; } return GamesHeatmap.colorScale(value.count); }} - titleForValue={value => { + titleForValue={(value) => { if (!value) { return 'No games'; } @@ -51,7 +51,7 @@ function GamesHeatmap() { ); } -GamesHeatmap.colorScale = count => { +GamesHeatmap.colorScale = (count) => { if (count >= 5) { return 'color-huge'; } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/InvitesContainer.jsx b/services/app/apps/codebattle/assets/js/widgets/components/InvitesContainer.jsx index bac30f7f7..0b89304da 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/InvitesContainer.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/InvitesContainer.jsx @@ -7,12 +7,7 @@ import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Popover from 'react-bootstrap/Popover'; import { useDispatch, useSelector } from 'react-redux'; -import { - initInvites, - acceptInvite, - declineInvite, - cancelInvite, -} from '../middlewares/Invite'; +import { initInvites, acceptInvite, declineInvite, cancelInvite } from '../middlewares/Invite'; import initPresence from '../middlewares/Main'; import * as selectors from '../selectors'; import { selectors as invitesSelectors } from '../slices/invites'; @@ -22,56 +17,54 @@ import GameLevelBadge from './GameLevelBadge'; const NoInvites = () =>
No Invites
; -function InvitesList({ list, currentUserId }) { +function InvitesList({ currentUserId, list }) { const dispatch = useDispatch(); return list .sort(({ creatorId }) => creatorId === currentUserId) - .map(({ - id, creatorId, recipientId, creator, recipient, gameParams, -}) => ( -
-
- -
- {currentUserId === recipientId && ( - <> - - {creator.name} - invited you - - - - + .map(({ creator, creatorId, gameParams, id, recipient, recipientId }) => ( +
+
+ +
+ {currentUserId === recipientId && ( + <> + + {creator.name} + invited you + + + + )} - {currentUserId === creatorId && ( - <> - - {'You invited '} - {recipient.name} - - - + {currentUserId === creatorId && ( + <> + + {'You invited '} + {recipient.name} + + + )} -
+
)); } @@ -79,17 +72,14 @@ function OnlineIndicator() { const { presenceList } = useSelector(selectors.lobbyDataSelector); const count = presenceList ? presenceList.length : 0; - return ( - <> - {`${count} Online`} - - ); + return {`${count} Online`}; } function InvitesContainer() { const currentUserId = useSelector(selectors.currentUserIdSelector); - const checkInvitePlayers = ({ creatorId, recipientId }) => creatorId === currentUserId || recipientId === currentUserId; - const filterInvites = invite => invite.state === 'pending' && checkInvitePlayers(invite); + const checkInvitePlayers = ({ creatorId, recipientId }) => + creatorId === currentUserId || recipientId === currentUserId; + const filterInvites = (invite) => invite.state === 'pending' && checkInvitePlayers(invite); const invites = useSelector(invitesSelectors.selectAll).filter(filterInvites); const dispatch = useDispatch(); @@ -102,12 +92,9 @@ function InvitesContainer() { }, []); useEffect(() => { - const inviteClasses = cn( - 'position-absolute invites-counter badge badge-danger', - { - 'd-none': invites.length === 0, - }, - ); + const inviteClasses = cn('position-absolute invites-counter badge badge-danger', { + 'd-none': invites.length === 0, + }); const invitesCountElement = document.getElementById('invites-counter-id'); invitesCountElement.classList.add(...inviteClasses.split(' ')); invitesCountElement.textContent = invites.length; @@ -119,25 +106,21 @@ function InvitesContainer() { <> {invites.length === 0 ? ( ) : ( - + )} - )} + } > {({ ref, ...triggerHandler }) => ( - ); } return ( - <> - ); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Loading.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Loading.jsx index 3218bc271..0da61fb16 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Loading.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Loading.jsx @@ -2,21 +2,24 @@ import React from 'react'; import ReactLoading from 'react-loading'; -const getSize = ({ small = false, adaptive = false }) => { +const getSize = ({ adaptive = false, small = false }) => { switch (true) { - case adaptive: return 16; - case small: return 30; - default: return 50; + case adaptive: + return 16; + case small: + return 30; + default: + return 50; } }; -const Loading = params => { +function Loading(params) { const size = getSize(params); return (
- +
); -}; +} export default Loading; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Message.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Message.jsx index 6a7c4d240..af235b482 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Message.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Message.jsx @@ -5,15 +5,7 @@ import moment from 'moment'; import MessageTag from './MessageTag'; -const Message = ({ - text = '', - name = '', - userId, - type, - time, - meta, - displayMenu, -}) => { +function Message({ displayMenu, meta, name = '', text = '', time, type, userId }) { if (!text) { return null; } @@ -66,30 +58,27 @@ const Message = ({ return (
- - {`${name}: `} - + {`${name}: `} - {parts.map((part, i) => renderMessagePart(part, i))}
); -}; +} export default Message; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Messages.jsx b/services/app/apps/codebattle/assets/js/widgets/components/Messages.jsx index 86fef25dd..825d84ae7 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Messages.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/Messages.jsx @@ -12,7 +12,7 @@ const getKey = (id, time, name) => { return `${time}-${name}`; }; -function Messages({ messages, displayMenu = () => {} }) { +function Messages({ displayMenu = () => {}, messages }) { const listRef = useRef(); const { stayScrolled /* , scrollBottom */ } = useStayScrolled(listRef); @@ -23,33 +23,29 @@ function Messages({ messages, displayMenu = () => {} }) { }, [messages.length, stayScrolled]); return ( - <> -
    - {messages.map(message => { - const { - id, userId, name, text, type, time, meta, - } = message; - - const key = getKey(id, time, name); - - return ( - - ); - })} -
- +
    + {messages.map((message) => { + const { id, meta, name, text, time, type, userId } = message; + + const key = getKey(id, time, name); + + return ( + + ); + })} +
); } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/Modal.js b/services/app/apps/codebattle/assets/js/widgets/components/Modal.js index 67f3b23f3..b1dce3f82 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/Modal.js +++ b/services/app/apps/codebattle/assets/js/widgets/components/Modal.js @@ -20,9 +20,6 @@ export default class Modal extends React.Component { render() { const { children } = this.props; - return createPortal( - children, - this.el, - ); + return createPortal(children, this.el); } } diff --git a/services/app/apps/codebattle/assets/js/widgets/components/PlayerLoading.jsx b/services/app/apps/codebattle/assets/js/widgets/components/PlayerLoading.jsx index 3b94a653c..6eed24ba2 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/PlayerLoading.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/PlayerLoading.jsx @@ -2,11 +2,17 @@ import React from 'react'; import ReactLoading from 'react-loading'; -const PlayerLoading = ({ small = false, show = false }) => { +function PlayerLoading({ show = false, small = false }) { const size = small ? 30 : 50; return ( - + ); -}; +} export default PlayerLoading; diff --git a/services/app/apps/codebattle/assets/js/widgets/components/PopoverStickOnHover.jsx b/services/app/apps/codebattle/assets/js/widgets/components/PopoverStickOnHover.jsx index 9a2cbce41..5c098ae62 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/PopoverStickOnHover.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/PopoverStickOnHover.jsx @@ -5,23 +5,16 @@ import PropTypes from 'prop-types'; import Overlay from 'react-bootstrap/Overlay'; import Popover from 'react-bootstrap/Popover'; -function PopoverStickOnHover({ - id, - delay, - onMouseEnter, - children, - component, - placement, -}) { +function PopoverStickOnHover({ children, component, delay, id, onMouseEnter, placement }) { const [showPopover, setShowPopover] = useState(false); const childNode = useRef(null); let setTimeoutConst = null; useEffect(() => () => { - if (setTimeoutConst) { - clearTimeout(setTimeoutConst); - } - }); + if (setTimeoutConst) { + clearTimeout(setTimeoutConst); + } + }); const handleMouseEnter = () => { setTimeoutConst = setTimeout(() => { @@ -35,34 +28,31 @@ function PopoverStickOnHover({ setShowPopover(false); }; - const displayChild = React.Children.map(children, child => React.cloneElement(child, { + const displayChild = React.Children.map(children, (child) => + React.cloneElement(child, { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, - ref: node => { + ref: (node) => { childNode.current = node; const { ref } = child; if (typeof ref === 'function') { ref(node); } }, - }))[0]; + }), + )[0]; return ( <> {displayChild} - + { setShowPopover(true); }} - onMouseLeave={handleMouseLeave} - id={id} > {component} diff --git a/services/app/apps/codebattle/assets/js/widgets/components/ResultIcon.jsx b/services/app/apps/codebattle/assets/js/widgets/components/ResultIcon.jsx index 6d11a7d2d..08a4756a5 100644 --- a/services/app/apps/codebattle/assets/js/widgets/components/ResultIcon.jsx +++ b/services/app/apps/codebattle/assets/js/widgets/components/ResultIcon.jsx @@ -3,17 +3,14 @@ import React from 'react'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; -const ResultIcon = ({ gameId, player1, player2 }) => { +function ResultIcon({ gameId, player1, player2 }) { const tooltipId = `tooltip-${gameId}-${player1.id}`; if (player1.result === 'gave_up') { return ( - Player gave up} - placement="left" - > + Player gave up} placement="left"> -