diff --git a/services/app/apps/codebattle/.eslintrc.yml b/services/app/apps/codebattle/.eslintrc.yml
index 8b30adc47..e682d1d09 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,30 @@ 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
+ 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 +79,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 => (
- onChange({ value: entity })}
- key={entity.name}
- >
+ {entities.map((entity) => (
+ onChange({ value: entity })}>
{entity.name}
))}
);
-};
+}
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..c819d9e9e 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,61 +109,44 @@ function ChatContextMenu({
return (
<>
{children}
-