master 87986aad70b2 cached
199 files
268.1 KB
79.8k tokens
193 symbols
1 requests
Download .txt
Showing preview only (323K chars total). Download the full file or copy to clipboard to get everything.
Repository: rolling-scopes-school/RSS-Teams-FE
Branch: master
Commit: 87986aad70b2
Files: 199
Total size: 268.1 KB

Directory structure:
gitextract_043m4_he/

├── .eslintrc.js
├── .firebaserc
├── .github/
│   └── workflows/
│       └── deploy-client.yml
├── .gitignore
├── .prettierrc
├── README.md
├── firebase.json
├── package.json
├── pre-build.js
├── public/
│   ├── index.html
│   ├── manifest.json
│   └── robots.txt
├── src/
│   ├── appConstants/
│   │   ├── api.ts
│   │   ├── colors.ts
│   │   └── index.ts
│   ├── assets/
│   │   └── fonts/
│   │       ├── Poppins-Bold-700.otf
│   │       ├── Poppins-Medium-500.otf
│   │       ├── Poppins-Regular-400.otf
│   │       └── Poppins-SemiBold-600.otf
│   ├── components/
│   │   ├── App/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── CommonSelectList/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── CourseField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── ErrorBoundary/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── ErrorModal/
│   │   │   └── index.tsx
│   │   ├── FilterForm/
│   │   │   ├── filterFormFields.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── FilterSelect/
│   │   │   └── index.tsx
│   │   ├── Footer/
│   │   │   ├── components/
│   │   │   │   ├── FooterContent/
│   │   │   │   │   └── index.tsx
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Header/
│   │   │   ├── components/
│   │   │   │   ├── BurgerMenu/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   ├── MenuWrapper/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── CoursesSelect/
│   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   ├── LangSelect/
│   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   └── Nav/
│   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │       └── styled.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── InputField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Loader/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Modal/
│   │   │   ├── index.module.css
│   │   │   └── index.tsx
│   │   ├── ModalCreateEditTeam/
│   │   │   └── index.tsx
│   │   ├── ModalCreated/
│   │   │   └── index.tsx
│   │   ├── ModalEditCourse/
│   │   │   └── index.tsx
│   │   ├── ModalExpel/
│   │   │   └── index.tsx
│   │   ├── ModalJoin/
│   │   │   └── index.tsx
│   │   ├── Pagination/
│   │   │   ├── index.tsx
│   │   │   └── style.css
│   │   ├── PrivateRoute/
│   │   │   └── index.tsx
│   │   ├── SelectField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── TablePopup/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── TourGuide/
│   │   │   ├── index.tsx
│   │   │   ├── style.css
│   │   │   ├── styled.ts
│   │   │   └── tourConfig.tsx
│   │   └── index.ts
│   ├── graphql/
│   │   ├── mutations/
│   │   │   ├── addUserToTeamMutation.ts
│   │   │   ├── createCourseMutation.ts
│   │   │   ├── createTeamMutation.ts
│   │   │   ├── index.ts
│   │   │   ├── removeUserFromCourseMutation.ts
│   │   │   ├── removeUserFromTeamMutation.ts
│   │   │   ├── sortStudentsMutation.ts
│   │   │   ├── updUserMutation.ts
│   │   │   ├── updateCourseMutation.ts
│   │   │   └── updateTeamMutation.ts
│   │   └── queries/
│   │       ├── coursesQuery.ts
│   │       ├── index.ts
│   │       ├── teamsQuery.ts
│   │       ├── usersQuery.ts
│   │       └── whoAmIQuery.ts
│   ├── hooks/
│   │   └── graphql/
│   │       ├── index.ts
│   │       ├── mutations/
│   │       │   ├── useAddUserToTeamMutation.ts
│   │       │   ├── useCreateCourseMutation.ts
│   │       │   ├── useCreateTeamMutation.ts
│   │       │   ├── useExpelUserFromTeamMutation.ts
│   │       │   ├── useRemoveUserFromCourseMutation.ts
│   │       │   ├── useRemoveUserFromTeamMutation.ts
│   │       │   ├── useSortStudentsMutation.ts
│   │       │   ├── useUpdUserMutation.ts
│   │       │   ├── useUpdateCourseMutation.ts
│   │       │   └── useUpdateTeamMutation.ts
│   │       └── queries/
│   │           ├── useCoursesQuery.ts
│   │           ├── useTeamsQuery.ts
│   │           ├── useUsersQuery.ts
│   │           └── useWhoAmIQuery.ts
│   ├── index.tsx
│   ├── modules/
│   │   ├── AdminPage/
│   │   │   ├── components/
│   │   │   │   ├── ContentWrapper/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── AddCourseBlock/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── InputsBlock/
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── CoursesList/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── Course/
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   └── ShowCourseSelect/
│   │   │   │   │   │       └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   └── index.tsx
│   │   ├── EditProfile/
│   │   │   ├── components/
│   │   │   │   └── UserCourseListItem/
│   │   │   │       ├── index.tsx
│   │   │   │       └── styled.ts
│   │   │   ├── formFields.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── LoginPage/
│   │   │   ├── components/
│   │   │   │   ├── LoginInfoBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── loginPageMiddleware.ts
│   │   │   ├── loginPageReducer.ts
│   │   │   ├── selectors.ts
│   │   │   └── styled.ts
│   │   ├── NotFoundPage/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── StudentsTable/
│   │   │   ├── components/
│   │   │   │   └── Dashboard/
│   │   │   │       ├── components/
│   │   │   │       │   ├── TableBody/
│   │   │   │       │   │   ├── components/
│   │   │   │       │   │   │   └── TableRow/
│   │   │   │       │   │   │       ├── components/
│   │   │   │       │   │   │       │   └── TableItem/
│   │   │   │       │   │   │       │       ├── index.tsx
│   │   │   │       │   │   │       │       └── styled.ts
│   │   │   │       │   │   │       ├── index.tsx
│   │   │   │       │   │   │       └── styled.ts
│   │   │   │       │   │   ├── index.tsx
│   │   │   │       │   │   ├── styled.ts
│   │   │   │       │   │   └── styles.css
│   │   │   │       │   ├── TableHead/
│   │   │   │       │   │   ├── index.tsx
│   │   │   │       │   │   └── styled.ts
│   │   │   │       │   └── index.ts
│   │   │   │       ├── index.tsx
│   │   │   │       └── styled.ts
│   │   │   ├── index.tsx
│   │   │   ├── selectors.ts
│   │   │   ├── studentsTableReducer.ts
│   │   │   └── styled.ts
│   │   ├── TeamsList/
│   │   │   ├── components/
│   │   │   │   ├── TeamListModals/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── useCommonMutations.ts
│   │   │   │   ├── Teams/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── MemberListToggle/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── MyTeam/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── MyTeamInfoBlock/
│   │   │   │   │   │   │   │       ├── components/
│   │   │   │   │   │   │   │       │   ├── MyTeamInfoLine/
│   │   │   │   │   │   │   │       │   │   ├── index.tsx
│   │   │   │   │   │   │   │       │   │   └── styled.tsx
│   │   │   │   │   │   │   │       │   └── NotificationPopup/
│   │   │   │   │   │   │   │       │       ├── index.tsx
│   │   │   │   │   │   │   │       │       └── styled.ts
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── TeamItem/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.tsx
│   │   │   │   │   │   ├── TeamUserTable/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── TableRow/
│   │   │   │   │   │   │   │       ├── components/
│   │   │   │   │   │   │   │       │   ├── ExpelButton/
│   │   │   │   │   │   │   │       │   │   ├── index.tsx
│   │   │   │   │   │   │   │       │   │   └── styled.ts
│   │   │   │   │   │   │   │       │   ├── TableCell/
│   │   │   │   │   │   │   │       │   │   └── index.tsx
│   │   │   │   │   │   │   │       │   └── index.ts
│   │   │   │   │   │   │   │       └── index.tsx
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.tsx
│   │   │   │   │   │   ├── TeamsHeader/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.tsx
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── selectors.ts
│   │   │   ├── styled.ts
│   │   │   └── teamsListReducer.ts
│   │   ├── TokenPage/
│   │   │   └── index.tsx
│   │   ├── TutorialPage/
│   │   │   ├── components/
│   │   │   │   ├── NoteBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   ├── StepBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── styled.ts
│   │   │   └── tutorialPageInfo.tsx
│   │   └── index.ts
│   ├── react-app-env.d.ts
│   ├── reportWebVitals.ts
│   ├── setupTests.ts
│   ├── store/
│   │   └── index.tsx
│   ├── translation/
│   │   ├── en/
│   │   │   └── en.json
│   │   ├── resources.ts
│   │   └── ru/
│   │       └── ru.json
│   ├── types.ts
│   ├── typography/
│   │   ├── common.css
│   │   ├── fonts.css
│   │   ├── index.ts
│   │   └── normalize.css
│   └── utils/
│       └── isFieldValid.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.js
================================================
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: [
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier/@typescript-eslint',
    'plugin:react-hooks/recommended',
    'plugin:prettier/recommended',
  ],
  plugins: ['@typescript-eslint', 'react', 'prettier', 'react-hooks'],
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },

  rules: {
    'react-hooks/rules-of-hooks': 'error',
    'react-hooks/exhaustive-deps': 'warn',
    'comma-dangle': ['error', 'only-multiline'],
    'react/prop-types': 'off',
    'react/display-name': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    'prettier/prettier': ['error', { endOfLine: 'auto' }],
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/ban-ts-ignore': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-var-reqiures': 'off',
  },

  settings: {
    react: {
      version: 'detect',
    },
  },
  globals: { React: 'writable' },
};


================================================
FILE: .firebaserc
================================================
{
  "projects": {
    "default": "rss-teams"
  }
}


================================================
FILE: .github/workflows/deploy-client.yml
================================================
name: Build and Deploy
on:
  push:
    branches:
      - master

jobs:
  admin:
    name: Deploy PROD
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repo
        uses: actions/checkout@master
      - name: Install Dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Archive Production Artifact
        uses: actions/upload-artifact@master
        with:
          name: build
          path: build
      - name: Deploy to Firebase
        uses: w9jds/firebase-action@master
        with:
          args: deploy --only hosting
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
/.eslintcache*

# testing
/coverage

# production
/build
/.firebase

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.eslintcache*


================================================
FILE: .prettierrc
================================================

{
  "endOfLine": "auto",
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}

================================================
FILE: README.md
================================================
# RSS-Teams-FE - Deprecated and no longer maintained. The latest deployed version will become unavailable from 28/10/2022 due to Heroku limitations.
Link to deployment - https://rss-teams.web.app/login

Stack:  
1 React - https://reactjs.org/  
2 Redux, redux-thunk, redux-devtools-extension - https://redux.js.org/  
3 Typescript - https://www.typescriptlang.org/  
4 Apollo - https://www.howtographql.com/  

Used libs:  
1 styled-components - https://askd.rocks/pres/styled-gdg/  
2 react-router/react-router-dom - https://reactrouter.com/  
3 react-hook-form  
4 react-window  
5 react-paginate  
6 reactour  

Linters: prettier, eslint.

Branch RSSFE-01 contains login via github made frontend way.

App description:  
The application is intended for use by students of The Rolling Scopes School. The purpose of the application is to enable students to collect teams from friends, and single students - to be automatically assigned to teams.

Backend repo: https://github.com/rolling-scopes-school/RSS-Teams-BE  
MindMap: https://miro.com/welcomeonboard/2TsmiaGCbWQVZGhwyEW6EDfjdeQpOnKt6Hl62GvbVkT3ky3h02vqWHvI2gCz76cG

# Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `yarn start`

Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.\
You will also see any lint errors in the console.

### `yarn test`

Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.

### `yarn build`

Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

### `yarn eject`

**Note: this is a one-way operation. Once you `eject`, you can’t go back!**

If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.

Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.

You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).


================================================
FILE: firebase.json
================================================
{
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}


================================================
FILE: package.json
================================================
{
  "name": "rss-teams-fe",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@apollo/client": "^3.3.7",
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "@types/jest": "^26.0.15",
    "@types/node": "^12.0.0",
    "@types/react": "^16.9.53",
    "@types/react-dom": "^16.9.8",
    "@types/react-router-dom": "^5.1.7",
    "@types/react-virtualized-auto-sizer": "^1.0.0",
    "@types/react-window": "^1.8.2",
    "@types/reactour": "^1.18.1",
    "@types/redux-actions": "^2.6.1",
    "@types/styled-components": "^5.1.7",
    "graphql": "^15.5.0",
    "i18next": "^19.9.1",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-hook-form": "^6.15.1",
    "react-i18next": "^11.8.8",
    "react-paginate": "^7.0.0",
    "react-redux": "^7.2.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "4.0.3",
    "react-virtualized-auto-sizer": "^1.0.4",
    "react-window": "^1.8.6",
    "reactour": "^1.18.3",
    "redux": "^4.0.5",
    "redux-actions": "^2.6.5",
    "redux-thunk": "^2.3.0",
    "styled-components": "^5.2.1",
    "typescript": "4.2.4",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "npm run pre-build && react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "pre-build": "node pre-build",
    "deploy": "firebase deploy",
    "lint:eslint": "eslint \"{,!(node_modules)/**/}*.{ts,tsx}\"",
    "fix:prettier": "prettier --write \"{,!(node_modules)/**/}*.{ts,tsx}\"",
    "fix:eslint": "eslint --fix \"{,!(node_modules)/**/}*.{{ts,tsx}\""
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@types/react-paginate": "^6.2.1",
    "@types/react-redux": "^7.1.16",
    "@types/redux": "^3.6.0",
    "@typescript-eslint/eslint-plugin": "^4.14.1",
    "@typescript-eslint/parser": "^4.14.1",
    "eslint": "^7.19.0",
    "eslint-config-prettier": "^7.2.0",
    "eslint-plugin-prettier": "^3.3.1",
    "eslint-plugin-react": "^7.22.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "prettier": "^2.2.1",
    "redux-devtools-extension": "^2.13.8"
  }
}


================================================
FILE: pre-build.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
require('dotenv').config();

const BACKEND_LINK = `export const BACKEND_LINK = 'https://rss-teams.herokuapp.com/graphql';
`;

const AUTH_BACKEND_LINK = `export const AUTH_BACKEND_LINK = 'https://rss-teams.herokuapp.com/auth/github/';
`;

fs.writeFileSync('./src/appConstants/api.ts', BACKEND_LINK + AUTH_BACKEND_LINK);


================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="App for automatic distribution students of The Rolling Scopes School by teams"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/favicon.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>RSS Teams</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>


================================================
FILE: public/manifest.json
================================================
{
  "short_name": "RSS Teams",
  "name": "The Rolling Scopes School Teams",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "favicon.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "favicon.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}


================================================
FILE: public/robots.txt
================================================
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:


================================================
FILE: src/appConstants/api.ts
================================================
export const BACKEND_LINK = 'https://rss-teams-dev.herokuapp.com/graphql';
export const AUTH_BACKEND_LINK = 'https://rss-teams-dev.herokuapp.com/auth/github/';


================================================
FILE: src/appConstants/colors.ts
================================================
export const WHITE_COLOR = '#FFFFFF';
export const BG_COLOR = '#F2F8FD';
export const MAIN1_COLOR = '#6550F6'; // violet
export const MAIN1_DARK_COLOR = '#5039EF'; // dark violet
export const MAIN2_COLOR = '#FA6678'; // red
export const MAIN2_LIGHT_COLOR = '#FE7888'; // light red
export const LIGHT_TEXT_COLOR = '#7E96C2';
export const DARK_TEXT_COLOR = '#363D48';
export const OVERLAY_COLOR = '#363D4866';
export const DASHBOARD_HEADER_BG_COLOR = '#E1EEFA';
export const TABLE_SCROLLBAR_BG_COLOR = '#F9F9FD';
export const TABLE_SCROLLBAR_THUMB_COLOR = '#1E33570D';
export const TABLE_POPUP_BORDER_COLOR = '#363D4833';
export const FOOTER_NAMES_COLOR = '#9CA5B5';

export const ALERT_COLOR = '#FA6678'; // red


================================================
FILE: src/appConstants/index.ts
================================================
export { BACKEND_LINK, AUTH_BACKEND_LINK } from './api';

export const SET_USER_DATA = 'SET_USER_DATA';
export const AUTH_TOKEN = 'AUTH_TOKEN';
export const SET_TOKEN = 'SET_TOKEN';
export const SET_CURR_COURSE = 'SET_CURR_COURSE';
export const SET_COMMON_ERROR = 'SET_COMMON_ERROR';
export const SET_BURGER_MENU_OPEN = 'SET_BURGER_MENU_OPEN';
export const ACTIVE_MODAL_EXPEL = 'ACTIVE_MODAL_EXPEL';
export const ACTIVE_MODAL_LEAVE = 'ACTIVE_MODAL_LEAVE';
export const ACTIVE_MODAL_JOIN = 'ACTIVE_MODAL_JOIN';
export const ACTIVE_MODAL_CREATE_TEAM = 'ACTIVE_MODAL_CREATE_TEAM';
export const ACTIVE_MODAL_CREATED = 'ACTIVE_MODAL_CREATED';
export const ACTIVE_MODAL_UPDATE_SOCIAL_LINK = 'ACTIVE_MODAL_UPDATE_SOCIAL_LINK';
export const ACTIVE_MODAL_REMOVE_COURSE = 'ACTIVE_MODAL_REMOVE_COURSE';
export const ACTIVE_MODAL_SORT_STUDENTS = 'ACTIVE_MODAL_SORT_STUDENTS';
export const ACTIVE_MODAL_LEAVE_PAGE = 'ACTIVE_MODAL_LEAVE_PAGE';
export const ACTIVE_MODAL_CREATED_COURSE = 'ACTIVE_MODAL_CREATED_COURSE';
export const ACTIVE_MODAL_EDIT_COURSE = 'ACTIVE_MODAL_EDIT_COURSE';
export const SET_TEAM_MEMBER_EXPEL_ID = 'SET_TEAM_MEMBER_EXPEL_ID';
export const SET_TEAM_PASSWORD = 'SET_TEAM_PASSWORD';
export const SET_SOCIAL_LINK = 'SET_SOCIAL_LINK';
export const SET_FILTER_DATA = 'SET_FILTER_DATA';
export const SET_CURR_LANG = 'SET_CURR_LANG';
export const SET_EDIT_PROFILE_DATA_CHANGE = 'SET_EDIT_PROFILE_DATA_CHANGE';
export const SET_PATH_TO_THE_PAGE = 'SET_PATH_TO_THE_PAGE';
export const SET_IS_TOUR_OPEN = 'SET_IS_TOUR_OPEN';

export const USERS_PER_PAGE = 20;
export const TEAMS_PER_PAGE = 10;
export const CURRENT_YEAR = new Date(Date.now()).getFullYear();

export const CURRENT_COURSE = 'currentCourse';
export const CURRENT_LANG = 'currentLanguage';
export const TOUR_OPENING = 'tourOpening';

export const TABLE_HEADERS = [
  '№',
  'First / Last Name',
  'Score',
  'Team Number',
  'Telegram',
  'Discord',
  'Github',
  'Location',
  'Courses',
];

export const TABLE_TEAMS_HEADERS = [
  '№',
  'First / Last Name',
  'Score',
  'Telegram',
  'Discord',
  'Github',
  'Location',
  'Action',
];

export const INPUT_VALUES_EDIT_PROFILE: string[] = [
  'firstName',
  'lastName',
  'discord',
  'telegram',
  'city',
  'country',
  'score',
];

export const MODAL_INPUT_VALIDATION = {
  pattern: {
    value:
      /^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?|^((http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,
    message: 'Use the format',
  },
  maxLength: {
    value: 55,
    message: 'This input exceed maxLength.',
  },
};

export const COURSE_NAME_VALIDATION = {
  pattern: {
    value: `${CURRENT_YEAR}`,
    message: 'Please, enter correct course name',
  },
  minLength: {
    value: 5,
    message: 'Minimal length is 5.',
  },
  maxLength: {
    value: 55,
    message: 'This input exceed maxLength.',
  },
  uniq: {
    message: 'Please, enter unique course name',
  },
};

export const TEAM_SIZE_VALIDATION = {
  pattern: {
    value: /^[2-9]$/i,
    message: 'Please, enter correct team size',
  },
  minLength: {
    value: 1,
    message: 'Minimal length is 1.',
  },
  maxLength: {
    value: 1,
    message: 'This input exceed maxLength.',
  },
};

export const APP_NAVIGATION_LINKS = {
  ['/students']: {
    name: 'Dashboard',
    isAlwaysVisible: false,
  },
  ['/']: {
    name: 'Teams',
    isAlwaysVisible: false,
  },
  ['/edit-profile']: {
    name: 'Edit Profile',
    isAlwaysVisible: true,
  },
  ['/tutorial']: {
    name: 'Tutorial',
    isAlwaysVisible: true,
  },
  ['/admin']: {
    name: 'Admin',
    isAlwaysVisible: true,
  },
};

export const DEFAULT_LANGUAGE = 'en';
export const LANGUAGES: string[] = [DEFAULT_LANGUAGE, 'ru'];

export const Language: { [key: string]: string } = {
  en: 'EN',
  ru: 'RU',
};

export const FOOTER_INFO = [
  {
    title: 'Development',
    members: ['besovadevka', 'MadaShindeInai', 'self067', 'manuminsk', 'Malagor', 'dariavv'],
  },
  {
    title: 'Design',
    members: ['Nastya Kapylova'],
  },
];

export const LINK_TO_DESIGN_BLOCK = 'https://www.linkedin.com/in/nastya-kapylova-54126215a';

export const LINK_TO_REPO = 'https://github.com/rolling-scopes-school/RSS-Teams-FE';

export const addCourseInputsInfo = [
  { label: 'Course name', placeholder: 'Enter course name' },
  { label: 'Team size', placeholder: 'Enter team size' },
];

export const SHOW_COURSES_OPTIONS = [
  { id: '1', name: 'All' },
  { id: '2', name: 'Active' },
  { id: '3', name: 'Terminated' },
];

export const UNAUTHORIZED_ERROR_MESSAGE = 'Unauthorized';


================================================
FILE: src/components/App/index.tsx
================================================
import React, { FC, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import {
  TeamsList,
  LoginPage,
  StudentsTable,
  TokenPage,
  NotFoundPage,
  EditProfile,
  TutorialPage,
  AdminPage,
} from 'modules';
import { Loader, PrivateRoute, Header, Footer, ErrorModal, TourGuide } from 'components';
import { selectToken } from 'modules/LoginPage/selectors';
import { AUTH_TOKEN, CURRENT_COURSE, CURRENT_LANG, DEFAULT_LANGUAGE } from 'appConstants';
import { useWhoAmIQuery } from 'hooks/graphql';
import { AppStyled } from './styled';
import { setToken } from 'modules/LoginPage/loginPageReducer';
import { setUserData } from 'modules/StudentsTable/studentsTableReducer';
import { setCourse, setLanguage } from 'modules/LoginPage/loginPageMiddleware';

export const App: FC = () => {
  const dispatch = useDispatch();
  const loginToken = useSelector(selectToken);
  const [loading, setLoading] = useState(true);
  const { loadingW, whoAmI, errorW } = useWhoAmIQuery({
    skip: loginToken === null,
  });
  const newUserCheck = !!whoAmI?.courses.length;
  const isUserAdmin = !!whoAmI?.isAdmin;

  useEffect(() => {
    if (!loginToken) {
      const token = sessionStorage.getItem(AUTH_TOKEN);
      if (token) dispatch(setToken(token));
    }

    if (!!whoAmI) {
      dispatch(setUserData(whoAmI));
    }
    if (whoAmI?.courses[0]) {
      dispatch(setLanguage(localStorage.getItem(CURRENT_LANG) ?? DEFAULT_LANGUAGE));
      dispatch(
        setCourse(JSON.parse(localStorage.getItem(CURRENT_COURSE) as string) ?? whoAmI?.courses[0])
      );
    }

    if (!loadingW) setLoading(false);
  }, [dispatch, loginToken, loadingW, loading, whoAmI]);

  if (errorW) return <ErrorModal error={errorW} />;
  if (loading || loadingW) return <Loader />;

  return (
    <AppStyled>
      <Header />

      <Switch>
        <PrivateRoute
          path="/"
          exact
          isLoggedIn={!!loginToken}
          newUserCheck={newUserCheck}
          component={TeamsList}
        />
        <PrivateRoute
          exact
          path="/students"
          isLoggedIn={!!loginToken}
          newUserCheck={newUserCheck}
          component={StudentsTable}
        />
        <PrivateRoute
          exact
          path="/admin"
          isLoggedIn={!!loginToken && isUserAdmin}
          newUserCheck={isUserAdmin}
          component={AdminPage}
        />
        <Route exact path="/token/:id" component={TokenPage} />
        <Route exact path="/login" component={LoginPage} />
        <Route exact path="/edit-profile" component={EditProfile} />
        <Route exact path="/tutorial" component={TutorialPage} />
        <Route path="*" component={NotFoundPage} />
      </Switch>

      <TourGuide />

      {!!loginToken && <Footer />}
    </AppStyled>
  );
};


================================================
FILE: src/components/App/styled.ts
================================================
import styled from 'styled-components';

export const AppStyled = styled.div`
  position: relative;
  height: 100vh;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
`;


================================================
FILE: src/components/CommonSelectList/index.tsx
================================================
import React, { FC, useEffect, useRef } from 'react';
import { Course } from 'types';
import {
  StyledCoursesSelectWrapper,
  StyledCoursesSelectHeaderWrapper,
  StyledCoursesList,
  StyledCoursesSelectInfo,
  StyledCoursesSelectArrow,
} from './styled';
import { useTranslation } from 'react-i18next';
import { Language } from 'appConstants';

type CommonSelectProps = {
  displayList: boolean;
  setDisplayList: (display: boolean) => void;
  listItems: any;
  onClickHandler: any;
  title?: string;
  currItem: string;
  isLang?: boolean;
  menuToggle?: boolean;
  customStyle?: boolean;
  showOptionsSelect?: boolean;
};

export const CommonSelectList: FC<CommonSelectProps> = ({
  displayList,
  setDisplayList,
  listItems,
  onClickHandler,
  title,
  currItem,
  isLang,
  menuToggle,
  customStyle,
  showOptionsSelect,
}) => {
  const selectRef = useRef(null);
  const { t } = useTranslation();

  useEffect(() => {
    const closeEventHandler = (ev: MouseEvent) => {
      if ((selectRef.current as unknown as HTMLDivElement)?.contains(ev.target as HTMLDivElement)) {
        setDisplayList(!displayList);
        return;
      }
      setDisplayList(false);
    };

    document && document.addEventListener('click', closeEventHandler);

    return (): void => {
      document && document.removeEventListener('click', closeEventHandler);
    };
  }, [displayList, setDisplayList]);

  const isListItemsExists = !!listItems.length;

  return (
    <StyledCoursesSelectWrapper
      isClicked={displayList}
      {...{ isLang, menuToggle, customStyle, showOptionsSelect }}
      className={`CommonSelectList${!isLang && ' eighthStep'}`}
    >
      <StyledCoursesSelectHeaderWrapper
        isClicked={displayList}
        {...{ isLang, menuToggle, customStyle }}
      >
        {title && <p>{t(title)}</p>}
        <StyledCoursesSelectInfo
          hover={isListItemsExists}
          ref={selectRef}
          {...{ isLang, menuToggle, customStyle }}
        >
          <p>{t(currItem)}</p>
          {isListItemsExists && <StyledCoursesSelectArrow />}
        </StyledCoursesSelectInfo>
      </StyledCoursesSelectHeaderWrapper>{' '}
      {isListItemsExists && (
        <StyledCoursesList {...{ isLang, menuToggle, customStyle }}>
          {listItems.map((item: Course | string) => {
            return (
              <li
                key={typeof item === 'string' ? item : item.id}
                onClick={() => onClickHandler(item)}
              >
                {typeof item === 'string' ? Language[item] : t(item.name)}
              </li>
            );
          })}
        </StyledCoursesList>
      )}
    </StyledCoursesSelectWrapper>
  );
};


================================================
FILE: src/components/CommonSelectList/styled.ts
================================================
import {
  MAIN1_DARK_COLOR,
  WHITE_COLOR,
  MAIN1_COLOR,
  DARK_TEXT_COLOR,
  BG_COLOR,
  LIGHT_TEXT_COLOR,
} from 'appConstants/colors';
import styled from 'styled-components';
import { ReactComponent as CoursesSelectArrow } from 'assets/svg/coursesSelectArrow.svg';
import { HeaderAdaptiveFont, SVGArrowAdaptive } from 'typography';

type TStyledCoursesSelectInfo = {
  hover: boolean;
} & TFooterProp;

type TStyledCoursesSelectList = {
  isClicked: boolean;
  showOptionsSelect?: boolean;
} & TFooterProp;

type TFooterProp = {
  isLang?: boolean;
  menuToggle?: boolean;
  customStyle?: boolean;
};

export const StyledCoursesSelectWrapper = styled.div<TStyledCoursesSelectList>`
  position: ${({ showOptionsSelect }) => showOptionsSelect && 'absolute'};
  left: ${({ showOptionsSelect }) => showOptionsSelect && '5%'};
  z-index: 1;
  display: ${({ menuToggle }) => (menuToggle ? 'none' : 'flex')};
  flex-direction: column;
  width: ${({ isLang }) => (isLang ? '82px' : '300px')};
  height: fit-content;
  min-height: 40px;
  margin: ${({ isLang }) => !isLang && '0 20px 0 0'};
  overflow: hidden;
  font: 400 1rem/24px 'Poppins', sans-serif;
  color: ${({ customStyle }) => (customStyle ? DARK_TEXT_COLOR : WHITE_COLOR)};
  background-color: ${({ customStyle }) => (customStyle ? BG_COLOR : MAIN1_DARK_COLOR)};
  border-radius: 10px;
  ${HeaderAdaptiveFont}

  ul {
    margin-top: ${({ isClicked }) => (isClicked ? '-5px' : '-150%')};
  }

  @media (max-width: 1100px) {
    left: ${({ showOptionsSelect }) => showOptionsSelect && '9%'};
    top: ${({ showOptionsSelect }) => showOptionsSelect && '50%'};
  }
  @media (max-width: 768px) {
    left: ${({ showOptionsSelect }) => showOptionsSelect && '10%'};
  }
  @media (max-width: 700px) {
    width: ${({ isLang }) => !isLang && '260px'};
  }
  @media (max-width: 600px) {
    display: ${({ isLang }) => isLang && 'none'};
    display: ${({ menuToggle }) => menuToggle && 'flex'};
    margin: ${({ isLang }) => !isLang && '0 20px 0 0'};
  }
  @media (max-width: 440px) {
    width: ${({ isLang }) => !isLang && '200px'};
  }
  @media (max-width: 375px) {
    width: ${({ isLang }) => !isLang && '180px'};
  }
`;

export const StyledCoursesSelectHeaderWrapper = styled.div<TStyledCoursesSelectList>`
  z-index: 2;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 40px;
  padding: 8px 15px;
  background-color: ${({ customStyle }) => (customStyle ? BG_COLOR : MAIN1_DARK_COLOR)};
  border-radius: 10px;
  ${HeaderAdaptiveFont};

  p {
    margin: 0;
    font-weight: 400;
  }

  & > p {
    @media (max-width: 440px) {
      display: none;
    }
  }

  svg {
    transform: ${({ isClicked }) => (isClicked ? 'rotate(180deg)' : 'rotate(0deg)')};
    path {
      stroke: ${({ customStyle }) => customStyle && LIGHT_TEXT_COLOR};
    }
  }
`;

export const StyledCoursesList = styled.ul<TFooterProp>`
  display: flex;
  flex-direction: column;
  width: 100%;
  margin: 0;
  margin-top: 0;
  padding: 8px 10px;
  transition: all 0.7s ease-in-out;
  gap: 5px;
  ${HeaderAdaptiveFont}

  li {
    padding: 5px;
    list-style: none;
    background-color: ${({ customStyle }) => (customStyle ? WHITE_COLOR : MAIN1_COLOR)};
    border-radius: 10px;
    cursor: pointer;

    &:hover {
      background-color: transparent;
    }
  }
`;

export const StyledCoursesSelectInfo = styled.div<TStyledCoursesSelectInfo>`
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: ${({ isLang }) => isLang && '100%'};

  &:hover {
    cursor: ${({ hover }) => (hover ? 'pointer' : 'unset')};
  }

  p {
    overflow: hidden;
    max-width: 155px;
    margin-left: 5px;
    margin-right: ${({ hover }) => (hover ? '10px' : '31px')};
    font-weight: 500;
    white-space: nowrap;
    text-overflow: ellipsis;
    @media (max-width: 440px) {
      margin-left: 0;
      margin-right: ${({ hover }) => (hover ? '10px' : '0')};
    }
  }

  svg {
    ${SVGArrowAdaptive};
  }

  @media (max-width: 440px) {
    width: ${({ isLang }) => !isLang && '100%'};
  }
`;

export const StyledCoursesSelectArrow = styled(CoursesSelectArrow)`
  transition: transform 0.3s ease-in-out;
`;


================================================
FILE: src/components/CourseField/index.tsx
================================================
import React, { FC, SelectHTMLAttributes } from 'react';
import { Label, Select, SelectInner } from 'typography';
import { FieldWrapper, SelectCourse } from './styled';
import { ValidationAlert } from '../InputField/styled';
import { useTranslation } from 'react-i18next';

type Course = {
  id: string;
  name: string;
};

interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElement> {
  labelText?: string;
  placeholder: string;
  multi?: boolean;
  register: any;
  courses: Course[];
  onAdd?: any;
  isValid?: boolean;
}

export const CourseField: FC<SelectFieldProps> = ({
  labelText,
  placeholder,
  register,
  courses,
  onAdd,
  isValid,
  ...rest
}) => {
  const { t } = useTranslation();
  const courseOptions = courses
    ? courses.map((course: Course) => {
        return (
          <option key={course.id} value={course.id}>
            {course.name}
          </option>
        );
      })
    : null;
  return (
    <FieldWrapper>
      {labelText && <Label>{labelText}</Label>}
      <SelectCourse>
        <Select>
          <SelectInner
            placeholder={t(placeholder)}
            ref={register}
            value={0}
            onChange={(e: any) => {
              onAdd(courses.find((course: Course) => course.id === e.target.value));
            }}
            {...rest}
          >
            <option disabled hidden value="0">
              {t('Select course')}
            </option>
            {courseOptions}
          </SelectInner>
        </Select>
      </SelectCourse>
      {!isValid && <ValidationAlert>{t('You need to choose at least one course')}</ValidationAlert>}
    </FieldWrapper>
  );
};


================================================
FILE: src/components/CourseField/styled.ts
================================================
import styled from 'styled-components';
import { BG_COLOR, LIGHT_TEXT_COLOR, MAIN1_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { SVGParamsAdaptive } from 'typography';

type TPlusButton = {
  active?: boolean;
};

export const FieldWrapper = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 20px;
`;

export const SelectCourse = styled.div`
  width: 300px;
  margin-bottom: 0;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  @media (max-width: 440px) {
    width: 100%;
  }
`;

export const CourseButton = styled.button`
  width: 40px;
  height: 40px;
  margin-left: 10px;
  padding: 10px;
  outline: none;
  border-radius: 10px;
  border: none;
  cursor: pointer;

  svg {
    ${SVGParamsAdaptive};
  }
`;

export const PlusButton = styled(CourseButton)<TPlusButton>`
  background-color: ${({ active }) => (active ? MAIN1_COLOR : BG_COLOR)};

  path {
    stroke: ${({ active }) => (active ? WHITE_COLOR : LIGHT_TEXT_COLOR)};
  }
`;

export const CrossButton = styled(CourseButton)`
  background: ${BG_COLOR}
    url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3.05029 3.05054L12.9499 12.9501' stroke='%237E96C2' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M12.9497 3.05029L3.0501 12.9499' stroke='%237E96C2' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E%0A")
    no-repeat center center;
`;

export const PlaceholderOption = styled.option`
  display: none;
`;


================================================
FILE: src/components/ErrorBoundary/index.tsx
================================================
import React, { Component } from 'react';
import { BoundryContainer } from './styled';

interface ErrorBoundaryState {
  error: any;
  errorInfo: any;
}

class ErrorBoundary extends Component<any, ErrorBoundaryState> {
  state = { error: null, errorInfo: null };

  static getDerivedStateFromError(error: any, errorInfo: any) {
    return { error: error, errorInfo: errorInfo };
  }

  componentDidCatch(error: any, errorInfo: any) {
    // Catch errors in any components below and re-render with error message
    this.setState({
      error: error,
      errorInfo: errorInfo,
    });
    // You can also log error messages to an error reporting service here
  }

  handleReload() {
    location.reload();
  }

  render() {
    const { children } = this.props;

    if (this.state.errorInfo) {
      return (
        <BoundryContainer onClick={this.handleReload}>
          Something went wrong.
          <br /> Click on the page to reload it.
        </BoundryContainer>
      );
    }

    return <>{children}</>;
  }
}

export default ErrorBoundary;


================================================
FILE: src/components/ErrorBoundary/styled.ts
================================================
import styled from 'styled-components';
import { PageTitle } from 'typography';

export const BoundryContainer = styled(PageTitle)`
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 30px;
  text-align: center;
`;


================================================
FILE: src/components/ErrorModal/index.tsx
================================================
import React, { FC } from 'react';
import { Modal } from 'components';
import { ApolloError } from '@apollo/client';
import { UNAUTHORIZED_ERROR_MESSAGE } from 'appConstants';

type Props = {
  title?: string;
  text?: string;
  text2?: string;
  open?: boolean;
  cancelText?: string;
  isCrossIconVisible?: boolean;
  error?: ApolloError;
};

export const ErrorModal: FC<Props> = ({
  title = 'Something went wrong!',
  text = 'Please, try again later.',
  text2 = '@besovadevka or @MadaShindeInai',
  open = true,
  isCrossIconVisible = false,
  cancelText = 'Ok',
  error,
}) => {
  const isUserUnauthorized = !!error?.graphQLErrors.find(
    ({ message }) => message === UNAUTHORIZED_ERROR_MESSAGE
  );

  if (isUserUnauthorized) {
    return null;
  }

  const onClose = () => {
    location.reload();
  };

  return (
    <Modal
      {...{ title, text, text2, open, onClose, isCrossIconVisible, cancelText }}
      hideOnOutsideClick
      hideOnEsc
    ></Modal>
  );
};


================================================
FILE: src/components/FilterForm/filterFormFields.ts
================================================
import { TFilterForm } from 'types';
import { InputFieldProps } from '../../components/InputField';

export const filterFormFields: InputFieldProps[] = [
  {
    name: 'discord',
    labelText: 'Discord',
    placeholder: 'Enter discord name',
    register: {
      pattern: {
        value: /^[A-Za-z0-9@#-_() ]+$/i,
        message: 'This input is letters and digits only.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'github',
    labelText: 'GitHub',
    placeholder: 'Enter github name',
    register: {
      pattern: {
        value: /^[A-Za-z0-9-_ ]+$/i,
        message: 'This input is letters and digits only.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'location',
    labelText: 'Location',
    placeholder: 'Enter location',
    register: {
      pattern: {
        value: /^[A-Za-z\- ]+$/i,
        message: 'This input is letters only.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'courseName',
    labelText: 'Course',
    placeholder: 'Enter course name',
    register: {
      pattern: {
        value: /^[A-Za-z\- ]+$/i,
        message: 'This input is letters only.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
];

export const filterSelectFields: [string, [string, string | boolean][], string, string][] = [
  [
    'Sort by score',
    [
      ['Max score', 'DESC'],
      ['Min score', 'ASC'],
    ],
    '100%',
    'sortingOrder',
  ],
  [
    'Sort by team',
    [
      ['All', false],
      ['Without team', true],
    ],
    '100%',
    'teamFilter',
  ],
];

export const defaultFilterData: TFilterForm = {
  discord: null,
  github: null,
  location: null,
  courseName: null,
  sortingOrder: filterSelectFields[0][1][0][0],
  teamFilter: filterSelectFields[1][1][0][0],
};


================================================
FILE: src/components/FilterForm/index.tsx
================================================
import React, { FC } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { FieldError, FieldErrors } from 'react-hook-form';
import { FilterSelect, InputField } from 'components';
import { InputsWrapper } from 'modules/EditProfile/styled';
import { TFilterForm } from 'types';
import { FilterFormBase, FilterButtonsWrapper, FilterButton } from './styled';
import { filterFormFields, filterSelectFields, defaultFilterData } from './filterFormFields';
import { DARK_TEXT_COLOR } from 'appConstants/colors';
import { Button } from 'typography';
import crossIcon from 'assets/svg/cross.svg';
import { selectFilterData } from 'modules/StudentsTable/selectors';
import { useTranslation } from 'react-i18next';
import { setFilterData } from 'modules/StudentsTable/studentsTableReducer';

type TFilter = {
  inputValues: TFilterForm;
  setInputValues: (data: TFilterForm) => void;
  setIsFilterOpen: (data: boolean) => void;
  setPage: (page: number) => void;
  register: any;
  handleSubmit: any;
  errors: FieldErrors;
  reset: any;
};

export const FilterForm: FC<TFilter> = ({
  inputValues,
  setInputValues,
  setIsFilterOpen,
  setPage,
  register,
  handleSubmit,
  errors,
  reset,
}) => {
  const filterData = useSelector(selectFilterData);
  const dispatch = useDispatch();
  const { t } = useTranslation();

  const changeInputValue = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>): void => {
    const { name, value } = e.target;
    setInputValues({
      ...inputValues,
      [name]: value.trim(),
    });
  };

  const onFilterFormSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
  };

  const isValuesInnerEqual =
    Object.values(defaultFilterData).toString() !== Object.values(inputValues).toString();
  const isValuesOuterEqual =
    Object.values(filterData).toString() !== Object.values(inputValues).toString();

  return (
    <FilterFormBase onSubmit={handleSubmit(onFilterFormSubmit)}>
      <InputsWrapper>
        {filterSelectFields.map((item: [string, [string, string | boolean][], string, string]) => {
          return (
            <FilterSelect
              key={JSON.stringify(item)}
              name={item[3]}
              labelText={t(item[0])}
              placeholder={t(item[0])}
              register={register}
              options={item[1].map((it) => it[0])}
              onChange={changeInputValue}
              currentOption={inputValues[item[3] as keyof TFilterForm] as string}
              color={DARK_TEXT_COLOR}
            />
          );
        })}
        {filterFormFields.map((item) => {
          return (
            <InputField
              key={JSON.stringify(item)}
              name={item.name}
              value={filterData[item.name as keyof TFilterForm] ?? ''}
              labelText={item.labelText}
              placeholder={item.placeholder}
              aria-invalid={
                (errors[item.name as keyof TFilterForm] as FieldError) ? 'true' : 'false'
              }
              message={(errors[item.name as keyof TFilterForm] as FieldError)?.message}
              onChange={changeInputValue}
              register={register(item.register)}
            />
          );
        })}
      </InputsWrapper>
      <FilterButtonsWrapper>
        {isValuesInnerEqual && (
          <FilterButton
            clearBtn
            type="button"
            onClick={() => {
              reset(defaultFilterData);
              setInputValues(defaultFilterData);
            }}
          >
            {<img src={crossIcon} alt="clear filter icon" />}
            {t('Clear filter')}
          </FilterButton>
        )}
        <Button
          className="SecondButtonForm"
          type="button"
          onClick={() => {
            if (isValuesOuterEqual) {
              dispatch(setFilterData(inputValues));
              setPage(0);
            }
            setIsFilterOpen(false);
          }}
        >
          {t('Apply')}
        </Button>
      </FilterButtonsWrapper>
    </FilterFormBase>
  );
};


================================================
FILE: src/components/FilterForm/styled.ts
================================================
import styled from 'styled-components';
import { MAIN1_COLOR } from 'appConstants/colors';
import { EditProfileWrapper } from 'modules/EditProfile/styled';
import { Button } from 'typography';

type TFilerButtonProps = {
  bgColor?: string | undefined;
  clearBtn?: boolean;
  outerBtn?: boolean;
};

export const FilterFormBase = styled(EditProfileWrapper)`
  z-index: 2;
  position: absolute;
  top: 25px;
  right: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 412px;
  @media screen and (max-width: 768px) {
    height: auto;
  }
  @media (max-width: 440px) {
    top: 5px;
    right: -13px;
    width: 320px;
  }
`;

export const FilterButton = styled(Button)<TFilerButtonProps>`
  background-color: ${({ bgColor }) => bgColor ?? 'transparent'};
  color: ${MAIN1_COLOR};
  display: flex;
  align-items: center;
  gap: ${({ clearBtn = false }) => (clearBtn ? '11px' : '20px')};
  margin-left: ${({ outerBtn = false }) => (outerBtn ? 'auto' : '0')};
  padding: ${({ clearBtn = false }) => (clearBtn ? '13px 20px 13px 0' : '20px 30px')};

  @media (max-width: 1200px) {
    padding: ${({ clearBtn = false }) => (clearBtn ? '12px 16px 12px 0' : '18px 28px')};
    gap: ${({ clearBtn = false }) => (clearBtn ? '10px' : '18px')};
  }
  @media (max-width: 992px) {
    padding: ${({ clearBtn = false }) => (clearBtn ? '13px 12px 13px 0' : '14px 26px')};
    gap: ${({ clearBtn = false }) => (clearBtn ? '10px' : '17px')};
  }
  @media (max-width: 768px) {
    padding: ${({ clearBtn = false }) => (clearBtn ? '13px 8px 13px 0' : '8px 26px')};
    gap: ${({ clearBtn = false }) => (clearBtn ? '10px' : '16px')};
  }
  @media (max-width: 550px) {
    padding: ${({ clearBtn = false }) => (clearBtn ? '11px 5px 11px 0' : '5px 25px')};
    gap: ${({ clearBtn = false }) => (clearBtn ? '8px' : '13px')};
  }
  @media (max-width: 440px) {
    padding: ${({ clearBtn = false }) => (clearBtn ? '9px 5px 9px 0' : '5px 20px')};
    gap: ${({ clearBtn = false }) => (clearBtn ? '6px' : '10px')};
  }

  img {
    filter: invert(100%) sepia() saturate(10000%) hue-rotate(-110deg);

    @media (max-width: 992px) {
      width: 15px;
    }
    @media (max-width: 768px) {
      width: 14px;
    }
    @media (max-width: 550px) {
      width: 12px;
    }
    @media (max-width: 440px) {
      width: 10px;
    }
  }
`;

export const FilterButtonsWrapper = styled.div`
  width: 100%;
  display: flex;
  align-items: center;

  .SecondButtonForm {
    margin-left: auto;
  }
`;


================================================
FILE: src/components/FilterSelect/index.tsx
================================================
import React, { FC, SelectHTMLAttributes } from 'react';
import { Label, Select, SelectInner } from 'typography';
import { FieldWrapper, SelectCourse } from 'components/CourseField/styled';
import { useTranslation } from 'react-i18next';
interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElement> {
  labelText?: string;
  placeholder: string;
  register: any;
  options: string[];
  currentOption: string;
}

export const FilterSelect: FC<SelectFieldProps> = ({
  labelText,
  placeholder,
  register,
  options,
  currentOption,
  ...rest
}) => {
  const { t } = useTranslation();
  const filterFieldOptions =
    options.map((option: string) => {
      return (
        <option key={option} value={option}>
          {t(option)}
        </option>
      );
    }) ?? null;
  return (
    <FieldWrapper>
      {labelText && <Label>{labelText}</Label>}
      <SelectCourse>
        <Select>
          <SelectInner placeholder={t(placeholder)} ref={register} value={currentOption} {...rest}>
            {filterFieldOptions}
          </SelectInner>
        </Select>
      </SelectCourse>
    </FieldWrapper>
  );
};


================================================
FILE: src/components/Footer/components/FooterContent/index.tsx
================================================
import React, { FC } from 'react';
import { FooterContentBlock, FooterContentWrapper, FooterTitle } from 'components/Footer/styled';
import { FOOTER_INFO, LINK_TO_DESIGN_BLOCK } from 'appConstants';
import { useTranslation } from 'react-i18next';

export const FooterContent: FC = () => {
  const { t } = useTranslation();
  return (
    <FooterContentWrapper>
      {FOOTER_INFO.map((item, index) => {
        return (
          <FooterContentBlock key={JSON.stringify(item)}>
            <FooterTitle>{t(item.title)}</FooterTitle>
            <div className={`contentBlock${!!index ? ' designBlock' : ''}`}>
              {item.members.map((item: string) => {
                return (
                  <a
                    href={!!index ? LINK_TO_DESIGN_BLOCK : `https://github.com/${item}`}
                    className={`contentItem${!!index ? ' designItem' : ''}`}
                    key={item}
                    target="_blank"
                    rel="noreferrer"
                  >
                    {item}
                  </a>
                );
              })}
            </div>
          </FooterContentBlock>
        );
      })}
    </FooterContentWrapper>
  );
};


================================================
FILE: src/components/Footer/components/index.ts
================================================
export { FooterContent } from './FooterContent';


================================================
FILE: src/components/Footer/index.tsx
================================================
import React, { FC } from 'react';
import { RSLogo } from 'typography';
import { StyledFooter, FooterWrapper, FooterContentBlockLogo } from './styled';
import { Link } from 'react-router-dom';
import { FooterContent } from './components';

export const Footer: FC = () => {
  return (
    <StyledFooter>
      <FooterWrapper>
        <FooterContentBlockLogo>
          <Link to="/">
            <RSLogo login=" " />
          </Link>
        </FooterContentBlockLogo>
        <FooterContent />
      </FooterWrapper>
    </StyledFooter>
  );
};


================================================
FILE: src/components/Footer/styled.ts
================================================
import styled from 'styled-components';
import { DARK_TEXT_COLOR, FOOTER_NAMES_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont } from 'typography';

export const StyledFooter = styled.footer`
  position: sticky;
  top: 100%;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 110px;
  padding: 0 4.2%;
  background-color: ${DARK_TEXT_COLOR};

  @media (max-width: 992px) {
    height: 100px;
  }
  @media (max-width: 880px) {
    height: 80px;
  }
  @media (max-width: 768px) {
    height: 65px;
  }
  @media (max-width: 550px) {
    height: 60px;
  }
  @media (max-width: 440px) {
    height: 50px;
  }
`;

export const FooterWrapper = styled.div`
  display: flex;
  justify-content: space-between;
  width: 100%;
  max-width: 1320px;
  height: 100%;
`;

export const FooterContentWrapper = styled.div`
  display: flex;
  justify-content: flex-end;
  width: 100%;
  gap: 5.6%;

  @media (max-width: 880px) {
    display: none;
  }
`;

export const FooterContentBlock = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 13px;

  .contentBlock {
    display: flex;
    flex-wrap: wrap;
    min-height: 24px;
    gap: 30px;

    @media (max-width: 992px) {
      gap: 20px;
    }

    .contentItem {
      height: 100%;
      margin-bottom: -20px;
      font: 400 1rem/24px 'Poppins', sans-serif;
      color: ${FOOTER_NAMES_COLOR};
      text-decoration: none;
      outline: none;
      ${GeneralAdaptiveFont};

      &:hover {
        color: ${WHITE_COLOR};
      }

      @media (max-width: 992px) {
        margin-bottom: 15px;
      }
    }
  }

  .contentBlock.designBlock {
    width: auto;
  }

  .contentItem.designItem {
    width: 140px;
  }
`;

export const FooterContentBlockLogo = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;

  a {
    height: 100%;
    display: flex;
    align-items: center;
  }
`;

export const FooterTitle = styled.h1`
  font: 600 1rem/24px 'Poppins', sans-serif;
  color: ${WHITE_COLOR};
  margin: 0;
  ${GeneralAdaptiveFont};
`;


================================================
FILE: src/components/Header/components/BurgerMenu/index.tsx
================================================
import React, { FC } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { NavLink } from 'react-router-dom';
import { selectIsBurgerMenuOpen } from 'modules/LoginPage/selectors';
import {
  BurgerMenuWrapper,
  BurgerMenuLayout,
  CrossButton,
  BurgerMenuNavList,
  BurgerMenuNavListItem,
  BurgerMenuOverlay,
} from './styled';
import { setBurgerMenuOpen } from 'modules/LoginPage/loginPageReducer';
import { APP_NAVIGATION_LINKS } from 'appConstants';
import { useTranslation } from 'react-i18next';
import { TNavLink } from 'types';
import { LangSelect } from '../MenuWrapper/components/LangSelect';

type BurgerMenuProps = {
  newUserCheck: boolean;
  navOnClickHandler: (e: React.MouseEvent<HTMLElement>, path: string) => void;
};

export const BurgerMenu: FC<BurgerMenuProps> = ({ newUserCheck, navOnClickHandler }) => {
  const dispatch = useDispatch();
  const { t } = useTranslation();
  const isBurgerMenuOpen = useSelector(selectIsBurgerMenuOpen);

  const onClickMenuToggle = () => {
    dispatch(setBurgerMenuOpen(!isBurgerMenuOpen));
  };

  return (
    <BurgerMenuWrapper {...{ isBurgerMenuOpen }}>
      <BurgerMenuOverlay {...{ isBurgerMenuOpen }} onClick={onClickMenuToggle} />
      <BurgerMenuLayout>
        <CrossButton onClick={onClickMenuToggle} />
        <BurgerMenuNavList>
          {Object.values(APP_NAVIGATION_LINKS).map((link: TNavLink, index: number) => {
            if (+newUserCheck + +link.isAlwaysVisible) {
              return (
                <BurgerMenuNavListItem key={JSON.stringify(link)}>
                  <NavLink
                    to={Object.keys(APP_NAVIGATION_LINKS)[index]}
                    exact
                    activeClassName="activeNavLink"
                    onClick={(e) => {
                      onClickMenuToggle();
                      navOnClickHandler(e, Object.keys(APP_NAVIGATION_LINKS)[index]);
                    }}
                  >
                    {t(link.name)}
                  </NavLink>
                </BurgerMenuNavListItem>
              );
            }
          })}
        </BurgerMenuNavList>
        <LangSelect menuToggle customStyle />
      </BurgerMenuLayout>
    </BurgerMenuWrapper>
  );
};


================================================
FILE: src/components/Header/components/BurgerMenu/styled.ts
================================================
import styled from 'styled-components';
import { DARK_TEXT_COLOR, OVERLAY_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { ReactComponent as IconClose } from 'assets/svg/cross.svg';

type BurgerMenuProps = {
  isBurgerMenuOpen: boolean;
};

export const BurgerMenuWrapper = styled.div<BurgerMenuProps>`
  position: fixed;
  z-index: 3;
  top: 0;
  display: flex;
  width: 100vw;
  height: 100vh;
  transition: transform 0.6s ease-in-out;
  transform: ${({ isBurgerMenuOpen }) => (isBurgerMenuOpen ? 'translateX(0)' : 'translateX(100%)')};
`;

export const BurgerMenuOverlay = styled.div<BurgerMenuProps>`
  width: calc(100% - 250px);
  height: 100%;
  background-color: ${({ isBurgerMenuOpen }) => (isBurgerMenuOpen ? OVERLAY_COLOR : 'none')};
  transition: background-color 0.6s ease-in-out;

  @media (max-width: 440px) {
    width: calc(100% - 180px);
  }
`;

export const BurgerMenuLayout = styled.nav`
  display: flex;
  flex-direction: column;
  gap: 40px;
  width: 250px;
  height: 100%;
  padding: 20px 20px 20px 40px;
  background: ${WHITE_COLOR};

  @media (max-width: 440px) {
    width: 180px;
    padding-left: 20px;
  }
`;

export const CrossButton = styled(IconClose)`
  width: 16px;
  height: 16px;
  align-self: flex-end;
  cursor: pointer;
`;

export const BurgerMenuNavList = styled.ul`
  display: flex;
  flex-direction: column;
  gap: 40px;
  margin: 0;
  padding-inline-start: 0;
`;

export const BurgerMenuNavListItem = styled.li`
  list-style-type: none;

  a {
    text-decoration: none;
    color: ${DARK_TEXT_COLOR};
  }

  a.activeNavLink,
  a:hover {
    font-weight: 700;
  }
`;


================================================
FILE: src/components/Header/components/MenuWrapper/components/CoursesSelect/index.tsx
================================================
import React, { FC, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { selectCurrCourse } from 'modules/LoginPage/selectors';
import { selectUserData } from 'modules/StudentsTable/selectors';
import { Course } from 'types';
import { CommonSelectList } from 'components';
import { setCourse } from 'modules/LoginPage/loginPageMiddleware';

export const CoursesSelect: FC = () => {
  const [isCourseSelectOpen, setCourseSelectOpen] = useState(false);
  const dispatch = useDispatch();
  const currCourse = useSelector(selectCurrCourse);
  const userData = useSelector(selectUserData);

  const userCourses = userData.courses.filter((item) => item.id !== currCourse.id) ?? null;

  const onCourseChange = (course: Course) => {
    setCourseSelectOpen(false);
    dispatch(setCourse(course));
  };

  return (
    <CommonSelectList
      title="Course"
      listItems={userCourses}
      onClickHandler={onCourseChange}
      currItem={currCourse.name}
      displayList={isCourseSelectOpen}
      setDisplayList={setCourseSelectOpen}
    />
  );
};


================================================
FILE: src/components/Header/components/MenuWrapper/components/LangSelect/index.tsx
================================================
import React, { FC, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { LANGUAGES } from 'appConstants';
import { selectCurrLanguage } from 'modules/LoginPage/selectors';
import i18n from 'translation/resources';
import { CommonSelectList } from 'components';
import { setLanguage } from 'modules/LoginPage/loginPageMiddleware';

type LangSelectProps = {
  menuToggle?: boolean;
  customStyle?: boolean;
};

export const LangSelect: FC<LangSelectProps> = ({ menuToggle, customStyle }) => {
  const [displayLangList, setDisplayLangList] = useState(false);
  const dispatch = useDispatch();
  const currentLanguage = useSelector(selectCurrLanguage);

  const onLangChange = (item: string) => {
    setDisplayLangList(false);
    dispatch(setLanguage(item));
    i18n.changeLanguage(item);
  };

  const languages: string[] = LANGUAGES.filter((lang) => lang !== currentLanguage);

  return (
    <CommonSelectList
      listItems={languages}
      onClickHandler={onLangChange}
      currItem={currentLanguage.toUpperCase()}
      setDisplayList={setDisplayLangList}
      displayList={displayLangList}
      isLang
      {...{ menuToggle, customStyle }}
    />
  );
};


================================================
FILE: src/components/Header/components/MenuWrapper/components/Nav/index.tsx
================================================
import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { APP_NAVIGATION_LINKS } from 'appConstants';
import { NavLink } from 'react-router-dom';
import { StyledNav, StyledNavList, StyledNavListItem, StyledHeaderActiveElement } from './styled';
import { TNavLink } from 'types';

type NavProps = {
  newUserCheck: boolean;
  navOnClickHandler: (e: React.MouseEvent<HTMLElement>, path: string) => void;
  isUserAdmin: boolean;
};

export const Nav: FC<NavProps> = ({ newUserCheck, navOnClickHandler, isUserAdmin }) => {
  const { t } = useTranslation();

  return (
    <StyledNav>
      <StyledNavList>
        {Object.values(APP_NAVIGATION_LINKS).map((link: TNavLink, index: number) => {
          const isNavLinkAvailable = !!(+newUserCheck + +link.isAlwaysVisible);
          if (isNavLinkAvailable) {
            if (link.name === 'Admin' && !isUserAdmin) return null;
            return (
              <StyledNavListItem key={JSON.stringify(link)} newUserCheck={newUserCheck}>
                <NavLink
                  to={Object.keys(APP_NAVIGATION_LINKS)[index]}
                  exact
                  activeClassName="activeNavLink"
                  onClick={(e) => navOnClickHandler(e, Object.keys(APP_NAVIGATION_LINKS)[index])}
                >
                  {t(link.name)}
                  <StyledHeaderActiveElement />
                </NavLink>
              </StyledNavListItem>
            );
          }
        })}
      </StyledNavList>
    </StyledNav>
  );
};


================================================
FILE: src/components/Header/components/MenuWrapper/components/Nav/styled.ts
================================================
import { WHITE_COLOR } from 'appConstants/colors';
import styled, { keyframes } from 'styled-components';
import { ReactComponent as HeaderActiveElement } from 'assets/svg/headerActiveElement.svg';

type TStyledNavListItemProps = {
  newUserCheck: boolean;
};

const open = keyframes`
  from: { height: 0 }
  to: { height: 100%}
`;

export const StyledNav = styled.nav`
  display: flex;
  justify-content: center;
  align-items: center;
  align-self: flex-end;
  margin-right: 60px;
  font: 400 1rem/24px 'Poppins', sans-serif;
`;

export const StyledNavList = styled.ul`
  @media (max-width: 1430px) {
    display: none;
  }

  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  padding-inline-start: 0;
  gap: 60px;
`;

export const StyledHeaderActiveElement = styled(HeaderActiveElement)`
  width: 87px;
  height: 0;
`;

export const StyledNavListItem = styled.li<TStyledNavListItemProps>`
  list-style-type: none;

  a {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    height: 52px;
    color: ${WHITE_COLOR};
    text-decoration: none;

    &:hover {
      font-weight: 700;
    }

    svg {
      height: 0;
      margin-bottom: -5px;
      transition: all 0.5s ease-in-out;
      animation: ${open} 0.5s ease-in-out;
    }
  }

  a.activeNavLink {
    font-weight: 700;

    svg {
      height: 22px;
      margin-bottom: 0;
    }
  }
`;


================================================
FILE: src/components/Header/components/MenuWrapper/index.tsx
================================================
import React, { FC } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { selectUserData } from 'modules/StudentsTable/selectors';
import { CoursesSelect } from './components/CoursesSelect';
import { Nav } from './components/Nav';
import { MenuButton, StyledMenuWrapper } from './styled';
import { LangSelect } from './components/LangSelect';
import { setBurgerMenuOpen } from 'modules/LoginPage/loginPageReducer';
import { selectIsBurgerMenuOpen } from 'modules/LoginPage/selectors';

type MenuWrapperProps = {
  navOnClickHandler: (e: React.MouseEvent<HTMLElement>, path: string) => void;
};

export const MenuWrapper: FC<MenuWrapperProps> = ({ navOnClickHandler }) => {
  const dispatch = useDispatch();
  const userData = useSelector(selectUserData);
  const isBurgerMenuOpen = useSelector(selectIsBurgerMenuOpen);

  const newUserCheck = !!userData?.courses.length;
  const isUserAdmin = !!userData?.isAdmin;

  const onClickMenuToggle = () => {
    dispatch(setBurgerMenuOpen(!isBurgerMenuOpen));
  };

  return (
    <StyledMenuWrapper>
      <Nav {...{ newUserCheck, navOnClickHandler, isUserAdmin }} />
      {newUserCheck && <CoursesSelect />}
      <LangSelect />
      <MenuButton onClick={onClickMenuToggle} />
    </StyledMenuWrapper>
  );
};


================================================
FILE: src/components/Header/components/MenuWrapper/styled.ts
================================================
import styled from 'styled-components';
import { ReactComponent as MenuToggle } from 'assets/svg/menuToggle.svg';

export const StyledMenuWrapper = styled.div`
  display: flex;
  height: 60px;

  @media (max-width: 1260px) {
    height: 40px;
  }
  @media (max-width: 550px) {
    margin-left: -30px;
  }
  @media (max-width: 440px) {
    margin-left: -50px;
  }
`;

export const MenuButton = styled(MenuToggle)`
  width: 0;
  height: 0;
  cursor: pointer;

  @media (max-width: 1430px) {
    width: 24px;
    height: 24px;
    margin: 8px 0 0 40px;
  }
  @media (max-width: 700px) {
    width: 20px;
    height: 20px;
    margin: 10px 0 0 30px;
  }
  @media (max-width: 600px) {
    margin-left: 0;
  }
  @media (max-width: 440px) {
    width: 16px;
    height: 16px;
    margin-top: 12px;
  }
`;


================================================
FILE: src/components/Header/components/index.ts
================================================
export { MenuWrapper } from './MenuWrapper';
export { BurgerMenu } from './BurgerMenu';


================================================
FILE: src/components/Header/index.tsx
================================================
import React, { FC } from 'react';
import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { RSLogo } from 'typography';
import { StyledHeader, Container } from './styled';
import { selectIsEditProfileDataChange, selectToken } from 'modules/LoginPage/selectors';
import { MenuWrapper, BurgerMenu } from './components';
import { selectUserData } from 'modules/StudentsTable/selectors';
import { activeModalLeavePage } from 'modules/TeamsList/teamsListReducer';
import { setPathToThePage } from 'modules/LoginPage/loginPageReducer';

export const Header: FC = () => {
  const dispatch = useDispatch();
  const userData = useSelector(selectUserData);
  const loginToken = useSelector(selectToken);
  const isEditProfileDataChange = useSelector(selectIsEditProfileDataChange);
  const newUserCheck = !!userData?.courses.length;

  const navOnClickHandler = (e: React.MouseEvent<HTMLElement>, path: string) => {
    if (isEditProfileDataChange) {
      e.preventDefault();
      dispatch(activeModalLeavePage(true));
      dispatch(setPathToThePage(path));
    }
  };

  return (
    <>
      <StyledHeader login={loginToken}>
        <Container>
          <Link to="/">
            <RSLogo login={loginToken} />
          </Link>
          {loginToken && <MenuWrapper {...{ navOnClickHandler }} />}
        </Container>
      </StyledHeader>
      <BurgerMenu {...{ newUserCheck, navOnClickHandler }} />
    </>
  );
};


================================================
FILE: src/components/Header/styled.ts
================================================
import styled from 'styled-components';
import { MAIN1_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont } from 'typography';

type TStyledHeaderProps = {
  login: string | null;
};

export const StyledHeader = styled.header<TStyledHeaderProps>`
  position: sticky;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  height: 80px;
  padding: ${({ login }) => (login ? '1.4% 4.2% 0' : '2.8% 4.2% 0 2.8%')};
  background-color: ${({ login }) => (login ? MAIN1_COLOR : 'transparent')};
  width: 100%;
  z-index: 1;

  @media (max-width: 1260px) {
    align-items: center;
  }
`;

export const Container = styled.div`
  display: flex;
  justify-content: space-between;
  width: 100%;
  max-width: 1320px;
  ${GeneralAdaptiveFont};
`;


================================================
FILE: src/components/InputField/index.tsx
================================================
import React, { FC, InputHTMLAttributes } from 'react';
import { Input } from 'typography';
import { FieldWrapper, ValidationAlert, FLabel } from './styled';
import { useTranslation } from 'react-i18next';
export interface InputFieldProps extends InputHTMLAttributes<HTMLInputElement> {
  labelText?: string;
  placeholder?: string;
  register?: any;
  name: string;
  message?: string | undefined;
  onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

export const InputField: FC<InputFieldProps> = ({
  labelText,
  placeholder,
  register,
  name,
  message,
  onChange,
}) => {
  const { t } = useTranslation();
  return (
    <FieldWrapper>
      <FLabel htmlFor={name}>{labelText ? t(labelText) : ''}</FLabel>
      <Input
        id={`id-${name}`}
        name={name}
        placeholder={placeholder ? t(placeholder) : ''}
        ref={register}
        autoComplete="off"
        onChange={onChange}
      />
      <ValidationAlert>{message ? t(message) : ''}</ValidationAlert>
    </FieldWrapper>
  );
};


================================================
FILE: src/components/InputField/styled.ts
================================================
import styled from 'styled-components';
import { ALERT_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont, Label } from 'typography';

export const FieldWrapper = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
`;

export const ValidationAlert = styled.div`
  ${GeneralAdaptiveFont}
  color: ${ALERT_COLOR};
  font-size: 14px;
  height: 22px;
`;

export const FLabel = styled(Label)`
  margin-bottom: 8px;
`;


================================================
FILE: src/components/Loader/index.tsx
================================================
import React, { FC } from 'react';
import { LoaderStyled, LoaderWrapper } from './styled';

export const Loader: FC = () => {
  return (
    <LoaderWrapper>
      <LoaderStyled>
        <div className="loader">
          <div className="loader-child loader-child-1"></div>
          <div className="loader-child loader-child-2"></div>
          <div className="loader-child loader-child-3"></div>
        </div>
      </LoaderStyled>
    </LoaderWrapper>
  );
};


================================================
FILE: src/components/Loader/styled.ts
================================================
import styled from 'styled-components';
import { MAIN1_COLOR } from 'appConstants/colors';
import { MainComponentHeight } from 'typography';

export const LoaderWrapper = styled.div`
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  transform: translate(-50%, -50%);
  ${MainComponentHeight};
`;

export const LoaderStyled = styled.div`
  width: 25%;
  .loader {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 2.5em;
    gap: 12px;
    animation-duration: 1.4s;
    animation-delay: 0.32s;
    margin: auto;
    text-align: center;

    @media (max-width: 440px) {
      gap: 9px;
    }

    .loader-child {
      width: 1.8em;
      height: 1.8em;
      background-color: ${MAIN1_COLOR};

      border-radius: 100%;
      display: inline-block;
      animation: loader-in 1.6s ease-in-out 0s infinite both;

      @media (max-width: 1200px) {
        width: 1.7em;
        height: 1.7em;
      }
      @media (max-width: 550px) {
        width: 1.4em;
        height: 1.4em;
      }
      @media (max-width: 440px) {
        width: 1em;
        height: 1em;
      }
    }

    .loader-child-1 {
      animation-delay: -0.6s;
    }
    .loader-child-2 {
      animation-delay: -0.4s;
    }
    .loader-child-3 {
      animation-delay: -0.2s;
    }
  }

  @keyframes loader-in {
    0%,
    80%,
    100% {
      transform: scale(0);
    }
    40% {
      transform: scale(1);
    }
  }
`;


================================================
FILE: src/components/Modal/index.module.css
================================================
/* setting absolute can break other modals */
.overlay {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 999;
  text-align: center;
  background: var(--OVERLAY_COLOR);

  overscroll-behavior: contain;
}

/* setting max width to container can break other modals */
.container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 440px;
  margin: 11vh auto;
  padding: 30px 40px;
  text-align: center;
  background: var(--WHITE_COLOR);
  border: none;
  border-radius: 20px;
}

.icon {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 1;
  width: 25px;
  height: 25px;
  cursor: pointer;
}

@media (max-width: 550px) {
  .container {
    width: 350px;
  }

  .icon {
    top: 15px;
    right: 20px;
    width: 22px;
    height: 22px;
  }
}

@media (max-width: 440px) {
  .container {
    width: 300px;
  }

  .icon {
    top: 15px;
    right: 20px;
    width: 20px;
    height: 20px;
  }
}


================================================
FILE: src/components/Modal/index.tsx
================================================
import React, { FC, SyntheticEvent, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';

import { ReactComponent as IconClose } from 'assets/svg/cross.svg';
import styled from 'styled-components';
import styles from './index.module.css';
import { PageTitle, Label, Button, InvertedButton, ButtonsBlock } from 'typography';
import { useTranslation } from 'react-i18next';

type ModalProps = {
  title: string;
  text: string;
  text2?: string;
  open: boolean;
  hideOnOutsideClick?: boolean;
  hideOnEsc?: boolean;
  children?: React.ReactNode;
  onClose(): void;
  onSubmit?: (e: SyntheticEvent) => void;
  okText?: string;
  cancelText?: string;
  isCrossIconVisible?: boolean;
} & typeof defaultProps;

const defaultProps = {
  hideOnOutsideClick: true,
  hideOnEsc: true,
};

const ModalWindow = styled.div`
  left: 500px;
  top: 315px;
  background: #ffffff;
  border-radius: 20px;
`;

export const Modal: FC<ModalProps> = ({
  title,
  text,
  text2,
  open,
  children,
  hideOnOutsideClick,
  hideOnEsc,
  onClose,
  onSubmit,
  isCrossIconVisible = true,
  okText,
  cancelText,
}) => {
  const insideRef = useRef<HTMLDivElement>(null);
  const { t } = useTranslation();

  const close = (e: React.MouseEvent | MouseEvent) => {
    e.stopPropagation();
    onClose();
  };

  const onOutClick: React.MouseEventHandler<HTMLDivElement> = (e) => {
    const curRef = insideRef.current;
    if (hideOnOutsideClick && curRef && !curRef.contains(e.target as Node)) {
      onClose();
    }
  };

  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === 'Escape' || (!onSubmit && e.key === 'Enter')) {
        onClose();
      }
    };

    if (open && hideOnEsc) {
      document.addEventListener('keydown', listener);
    }

    return () => document.removeEventListener('keydown', listener);
  }, [open, onClose, hideOnEsc, onSubmit]);

  useEffect(() => {
    if (open) {
      document.body.style.overflow = 'hidden';
    } else {
      document.body.style.overflow = '';
    }

    return () => {
      document.body.style.overflow = '';
    };
  }, [open]);

  if (!open) {
    return null;
  }

  return ReactDOM.createPortal(
    <div className={styles.overlay} onClick={onOutClick}>
      <div className={styles.container} ref={insideRef}>
        {isCrossIconVisible && <IconClose className={styles.icon} onClick={close} />}
        <ModalWindow>
          <PageTitle>{t(title)}</PageTitle>
          <Label>{t(text)}</Label>
          <p>
            <Label>{text2 ? t(text2) : ''}</Label>
          </p>
          {children}
          <ButtonsBlock>
            {onSubmit ? (
              cancelText ? (
                <>
                  <InvertedButton onClick={onClose}>{t(cancelText)}</InvertedButton>
                  <Button
                    onClick={(e) => {
                      onSubmit(e);
                    }}
                  >
                    {okText ? t(okText) : ''}
                  </Button>
                </>
              ) : (
                <Button
                  onClick={(e) => {
                    onSubmit(e);
                  }}
                >
                  {okText ? t(okText) : ''}
                </Button>
              )
            ) : (
              <Button onClick={onClose}>{cancelText ? t(cancelText) : ''}</Button>
            )}
          </ButtonsBlock>
        </ModalWindow>
      </div>
    </div>,
    document.body
  );
};

Modal.defaultProps = defaultProps;


================================================
FILE: src/components/ModalCreateEditTeam/index.tsx
================================================
import React, { FC, useState, useEffect, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { Modal } from 'components';
import { ModalInput } from 'typography';
import { ValidationAlert } from '../InputField/styled';
import { useTranslation } from 'react-i18next';
import { setSocialLink } from 'modules/TeamsList/teamsListReducer';
import { isFieldValid } from 'utils/isFieldValid';

type Props = {
  title: string;
  text: string;
  open: boolean;
  onSubmit?: () => void;
  onClose: () => void;
  value: string;
  okText?: string;
  validateRules?: any;
} & typeof defaultProps;

const defaultProps = {
  open: false,
  okText: 'Create team',
};

export const ModalCreateEditTeam: FC<Props> = ({
  title,
  text,
  open,
  okText,
  value,
  onClose,
  onSubmit,
  validateRules,
}) => {
  const dispatch = useDispatch();
  const { t } = useTranslation();
  const [isInputValid, setInputValid] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');

  const onSubmitModal = useCallback(() => {
    if (isInputValid && onSubmit) {
      onSubmit();
      onClose();
    } else {
      setErrorMessage('Please, enter link');
    }
  }, [onClose, onSubmit, isInputValid]);

  const onChangeModal = (e: React.ChangeEvent<HTMLInputElement>) => {
    dispatch(setSocialLink(e.target.value.trim()));
    isFieldValid(
      e.target.value.trim(),
      validateRules,
      !!validateRules,
      setInputValid,
      setErrorMessage
    );
  };

  const onCloseModal = () => {
    onClose();
    setErrorMessage('');
  };

  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === 'Enter') {
        onSubmitModal();
      }
    };
    if (open) {
      document.addEventListener('keydown', listener);
    }
    return () => document.removeEventListener('keydown', listener);
  }, [onSubmitModal, open]);

  return (
    <Modal
      {...{ title, text, open, okText }}
      onClose={onCloseModal}
      onSubmit={onSubmitModal}
      hideOnOutsideClick
      hideOnEsc
    >
      <ModalInput
        name="inputValue"
        required
        value={value.trim()}
        autoComplete={'off'}
        onChange={onChangeModal}
        placeholder={t('Enter group link')}
      />
      {!isInputValid && <ValidationAlert>{t(errorMessage)}</ValidationAlert>}
    </Modal>
  );
};


================================================
FILE: src/components/ModalCreated/index.tsx
================================================
import React, { FC, useState } from 'react';
import styled from 'styled-components';
import { Modal } from 'components';
import { ModalInput, InvertedButton } from 'typography';
import { BG_COLOR } from 'appConstants/colors';
import CopyIcon from 'assets/svg/copy2clip.svg';

const InputWithCopy = styled.div`
  position: relative;
`;

const CopyButton = styled(InvertedButton)`
  right: 40px;
  bottom: 0;
  padding: 19px 15px;
  position: absolute;
  background: ${BG_COLOR} url(${CopyIcon}) no-repeat center center;
`;

type Props = {
  title: string;
  text: string;
  text2?: string;
  open: boolean;
  onClose: () => void;
  cancelText?: string;
  password: string;
} & typeof defaultProps;

const defaultProps = {
  text2: '',
};

export const ModalCreated: FC<Props> = ({
  title,
  text,
  text2,
  open,
  cancelText,
  onClose,
  password,
}) => {
  const [isCopy, setIsCopy] = useState(false);

  const CopyToClipboard = (text: string) => {
    navigator.clipboard
      .writeText(text)
      .then(() => {
        setIsCopy(true);
        setTimeout(() => {
          setIsCopy(false);
        }, 1000);
      })
      .catch((err) => {
        console.log('Something went wrong', err);
      });
  };
  const onClickCopyButton = () => CopyToClipboard(password);

  return (
    <Modal {...{ title, text, text2, open, onClose, cancelText }} hideOnOutsideClick hideOnEsc>
      <InputWithCopy>
        <ModalInput name="InputValue" value={password} readOnly blink={isCopy} />
        <CopyButton onClick={onClickCopyButton} />
      </InputWithCopy>
    </Modal>
  );
};


================================================
FILE: src/components/ModalEditCourse/index.tsx
================================================
import React, { FC, useState, useEffect, useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { Modal } from 'components';
import { TeamButton } from 'typography';
import { useTranslation } from 'react-i18next';
import { activeModalEditCourse } from 'modules/TeamsList/teamsListReducer';
import { InputBlock } from 'modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock';
import { Course } from 'types';
import { COURSE_NAME_VALIDATION, TEAM_SIZE_VALIDATION } from 'appConstants';
import { onChangeField } from 'modules/AdminPage/components/ContentWrapper/components/AddCourseBlock';
import { DASHBOARD_HEADER_BG_COLOR, MAIN1_COLOR } from 'appConstants/colors';
import { useUpdateCourseMutation } from 'hooks/graphql';
import { ErrorModal } from 'components/ErrorModal';

type Props = {
  title: string;
  text: string;
  open: boolean;
  okText?: string;
  cancelText?: string;
  courseEditMeta: Course;
  checkIsCourseNameUniq: (courseName: string) => boolean;
  setCourseEditMeta: (course: Course | null) => void;
};

const isCourseInfoChanged = (
  { name, teamSize, isActive }: Course,
  newName: string,
  newTeamSize: string,
  newStatus: boolean
) => name !== newName || `${teamSize}` !== newTeamSize || isActive !== newStatus;

export const ModalEditCourse: FC<Props> = ({
  title,
  text,
  open,
  okText,
  cancelText,
  courseEditMeta,
  checkIsCourseNameUniq,
  setCourseEditMeta,
}) => {
  const { t } = useTranslation();
  const dispatch = useDispatch();

  const [isCourseNameFieldValid, setIsCourseNameFieldValid] = useState(true);
  const [isTeamSizeFieldValid, setIsTeamSizeFieldValid] = useState(true);
  const [courseName, setCourseName] = useState(courseEditMeta.name);
  const [teamSize, setTeamSize] = useState(`${courseEditMeta.teamSize ?? ''}`);
  const [isCourseActive, setIsCourseActive] = useState(courseEditMeta.isActive);
  const [courseNameErrorMessage, setCourseNameErrorMessage] = useState('');
  const [teamSizeErrorMessage, setTeamSizeErrorMessage] = useState('');

  const { updateCourse, errorM: errorUpdateCourse } = useUpdateCourseMutation({
    course: {
      id: courseEditMeta?.id || '',
      name: courseName,
      teamSize: +teamSize,
      isActive: isCourseActive,
    },
  });

  const onCloseModal = useCallback(() => {
    setCourseEditMeta(null);
    setCourseNameErrorMessage('');
    setTeamSizeErrorMessage('');
    dispatch(activeModalEditCourse(false));
  }, [dispatch, setCourseEditMeta]);

  const onSubmitModal = useCallback(() => {
    if (isCourseNameFieldValid && isTeamSizeFieldValid) {
      if (courseName && teamSize) {
        const isCourseChanged = courseEditMeta
          ? isCourseInfoChanged(courseEditMeta, courseName, teamSize, isCourseActive)
          : true;
        isCourseChanged && updateCourse();
        onCloseModal();
      } else {
        if (!courseName) {
          setIsCourseNameFieldValid(false);
          setCourseNameErrorMessage(COURSE_NAME_VALIDATION.minLength.message);
        }
        if (!teamSize) {
          setIsTeamSizeFieldValid(false);
          setTeamSizeErrorMessage(TEAM_SIZE_VALIDATION.minLength.message);
        }
      }
    }
  }, [
    onCloseModal,
    courseEditMeta,
    courseName,
    isCourseActive,
    isCourseNameFieldValid,
    isTeamSizeFieldValid,
    teamSize,
    updateCourse,
  ]);

  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === 'Enter') {
        onSubmitModal();
      }
    };
    if (open) {
      document.addEventListener('keydown', listener);
    }
    return () => document.removeEventListener('keydown', listener);
  }, [onSubmitModal, open]);

  const changeCourseStateButtonText = isCourseActive ? 'Terminate course' : 'Activate course';
  const onChangeCourseState = () => setIsCourseActive(!isCourseActive);

  if (errorUpdateCourse) return <ErrorModal error={errorUpdateCourse} />;

  return (
    <Modal
      {...{ title, text, open, okText, cancelText }}
      onClose={onCloseModal}
      onSubmit={onSubmitModal}
      hideOnOutsideClick
      hideOnEsc
    >
      <InputBlock
        inputLabel="New course name"
        value={courseName}
        placeholder="Enter new course name"
        onChangeHandler={onChangeField(
          COURSE_NAME_VALIDATION,
          setIsCourseNameFieldValid,
          setCourseNameErrorMessage,
          setCourseName,
          checkIsCourseNameUniq
        )}
        isFieldValid={isCourseNameFieldValid}
        errorMessage={courseNameErrorMessage}
        isModal
      />
      <InputBlock
        inputLabel="New team size"
        value={teamSize}
        placeholder="Enter new team size"
        onChangeHandler={onChangeField(
          TEAM_SIZE_VALIDATION,
          setIsTeamSizeFieldValid,
          setTeamSizeErrorMessage,
          setTeamSize
        )}
        isFieldValid={isTeamSizeFieldValid}
        errorMessage={teamSizeErrorMessage}
        isModal
      />
      <TeamButton
        bgc={DASHBOARD_HEADER_BG_COLOR}
        color={MAIN1_COLOR}
        type="button"
        onClick={onChangeCourseState}
      >
        {t(changeCourseStateButtonText)}
      </TeamButton>
    </Modal>
  );
};


================================================
FILE: src/components/ModalExpel/index.tsx
================================================
import React, { FC, useEffect, useCallback } from 'react';
import { Modal } from 'components';

type Props = {
  title: string;
  text: string;
  open: boolean;
  onSubmit?: () => void;
  onClose: () => void;
  okText?: string;
  isCrossIconVisible?: boolean;
  cancelText?: string;
};

export const ModalExpel: FC<Props> = ({
  title,
  text,
  open,
  okText,
  cancelText,
  isCrossIconVisible = true,
  onClose,
  onSubmit,
}) => {
  const onSubmitModal = useCallback(() => {
    onClose();
    if (onSubmit) {
      onSubmit();
    }
  }, [onClose, onSubmit]);

  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === 'Enter') {
        onSubmitModal();
      }
    };
    if (open) {
      document.addEventListener('keydown', listener);
    }
    return () => document.removeEventListener('keydown', listener);
  }, [onSubmitModal, open]);

  return (
    <Modal
      {...{
        title,
        text,
        open,
        onClose,
        okText,
        isCrossIconVisible,
        cancelText,
      }}
      onSubmit={onSubmitModal}
      hideOnOutsideClick
      hideOnEsc
    />
  );
};


================================================
FILE: src/components/ModalJoin/index.tsx
================================================
import React, { FC, useCallback, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { Modal } from 'components';
import { ModalInput } from 'typography';
import { useTranslation } from 'react-i18next';
import { setTeamPassword } from 'modules/TeamsList/teamsListReducer';

type Props = {
  title: string;
  text: string;
  open: boolean;
  okText?: string;
  value: string;
  cancelText?: string;
  onClose: () => void;
  onSubmit?: (e: string) => void;
  onChange?: () => void;
};

export const ModalJoin: FC<Props> = ({
  title,
  text,
  open,
  okText,
  value,
  cancelText,
  onClose,
  onSubmit,
  onChange,
}) => {
  const dispatch = useDispatch();
  const { t } = useTranslation();

  const onSubmitModal = useCallback(() => {
    if (onSubmit && value) {
      onSubmit(value);
    }
  }, [value, onSubmit]);

  const onChangeModal = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (onChange) {
      onChange();
    }
    dispatch(setTeamPassword(e.target.value));
  };

  useEffect(() => {
    const listener = (e: KeyboardEvent) => {
      if (e.key === 'Enter') {
        onSubmitModal();
      }
    };
    if (open) {
      document.addEventListener('keydown', listener);
    }
    return () => document.removeEventListener('keydown', listener);
  }, [onSubmitModal, open]);

  return (
    <Modal
      {...{ title, text, open, onClose, okText, cancelText }}
      onSubmit={onSubmitModal}
      hideOnOutsideClick
      hideOnEsc
    >
      <ModalInput
        placeholder={t('Enter team password')}
        name="InputValue"
        required
        value={value}
        onChange={onChangeModal}
        type="password"
      />
    </Modal>
  );
};


================================================
FILE: src/components/Pagination/index.tsx
================================================
import React, { FC } from 'react';
import ReactPaginate from 'react-paginate';
import './style.css';
import leftArrow from 'assets/svg/paginateArrowLeft.svg';
import rightArrow from 'assets/svg/paginateArrowRight.svg';

type PaginationProps = {
  pageCount: number;
  changePage: (page: number) => void;
  page: number;
};

export const Pagination: FC<PaginationProps> = ({ pageCount, changePage, page }) => {
  return (
    <ReactPaginate
      previousLabel={<img src={leftArrow} alt="Previous" />}
      nextLabel={<img src={rightArrow} alt="Next" />}
      breakLabel={'...'}
      pageCount={pageCount}
      initialPage={page}
      marginPagesDisplayed={1}
      pageRangeDisplayed={2}
      containerClassName={'pagination'}
      pageClassName={'pageContainer'}
      pageLinkClassName={'pageLink'}
      activeClassName={'activePageContainer'}
      activeLinkClassName={'activePageLink'}
      onPageChange={(page) => changePage(page.selected)}
    />
  );
};


================================================
FILE: src/components/Pagination/style.css
================================================
.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 40px auto 0;

  gap: 10px;
  padding-inline-start: 0;
}

.pagination li {
  list-style: none;
}

.pagination li a {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 40px;
  height: 40px;
  padding: 8px;
  outline: none;
}

.pageContainer,
.previous,
.next,
.break {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #ffffff;
  border-radius: 10px;
  cursor: pointer;
}

.previous a img,
.next a img {
  width: 12px;
  height: 12px;
}

.previous.disabled,
.next.disabled {
  cursor: unset;
  opacity: 0.7;
}

.activePageContainer {
  background-color: #6550f6;
  cursor: unset;
}

.pageLink,
.break > a {
  display: flex;
  justify-content: center;
  align-items: center;
  font: 400 1rem/24px "Poppins", sans-serif;
  color: #7e96c2;
  text-decoration: none;
}

.activePageLink {
  color: #ffffff;
}

@media (max-width: 1200px) and (min-width: 992px) {
  .pagination {
    margin: 35px auto 0;
  }

  .pageLink,
  .break > a {
    font-size: 0.95rem;
  }
}
@media (max-width: 992px) {
  .pagination {
    margin: 30px auto 0;
  }

  .pageLink,
  .break > a {
    font-size: 0.9rem;
  }

  .pagination li a {
    width: 35px;
    height: 35px;
  }
}
@media (max-width: 768px) {
  .pagination {
    margin: 30px auto 0;
  }

  .pageLink,
  .break > a {
    font-size: 0.825rem;
  }

  .pagination li a {
    width: 30px;
    height: 30px;
  }

  .previous a img,
  .next a img {
    width: 10px;
    height: 10px;
  }
}
@media (max-width: 550px) {
  .pagination {
    margin: 25px auto 0;
  }

  .pageLink,
  .break > a {
    font-size: 0.8rem;
  }

  .pagination li a {
    width: 30px;
    height: 30px;
  }

  .previous a img,
  .next a img {
    width: 10px;
    height: 10px;
  }
}
@media (max-width: 440px) {
  .pagination {
    margin: 20px auto 0;
  }

  .pageLink,
  .break > a {
    font-size: 0.68rem;
  }

  .pagination li a {
    width: 25px;
    height: 25px;
  }

  .previous a img,
  .next a img {
    width: 9px;
    height: 9px;
  }
}


================================================
FILE: src/components/PrivateRoute/index.tsx
================================================
import React, { FC } from 'react';
import { Redirect, Route } from 'react-router-dom';

type Props = {
  isLoggedIn: boolean;
  path: string;
  component: FC<any>;
  exact?: boolean;
  newUserCheck?: boolean;
};

export const PrivateRoute: FC<Props> = ({
  component: Component,
  isLoggedIn,
  newUserCheck,
  path,
  exact,
}) => {
  return (
    <Route
      exact={exact}
      path={path}
      render={(props) => {
        if (isLoggedIn && newUserCheck) {
          return <Component {...props} />;
        }
        if (isLoggedIn && !newUserCheck) {
          return <Redirect to={'/edit-profile'} />;
        }
        if (!isLoggedIn) {
          return <Redirect to={{ pathname: '/login', state: { from: props.location } }} />;
        }
      }}
    />
  );
};


================================================
FILE: src/components/SelectField/index.tsx
================================================
import React, { FC, SelectHTMLAttributes } from 'react';
import { Label, Select, SelectInner } from 'typography';
import { FieldWrapper } from './styled';
//
// for future
// TODO: make separate SelectField component for other screens
// now is not used
//
interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElement> {
  labelText: string;
  placeholder: string;
  multi?: boolean;
  register: any;
}

const SelectField: FC<SelectFieldProps> = ({ labelText, placeholder, register, ...rest }) => {
  return (
    <FieldWrapper>
      <Label>{labelText}</Label>
      <Select>
        <SelectInner placeholder={placeholder} ref={register} defaultValue="0" {...rest}>
          <option disabled hidden value="0">
            Select course
          </option>
          <option value="111">222</option>
          <option value="333">444</option>
        </SelectInner>
      </Select>
    </FieldWrapper>
  );
};


================================================
FILE: src/components/SelectField/styled.ts
================================================
import styled from 'styled-components';

export const FieldWrapper = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 20px;
`;

export const PlaceholderOption = styled.option`
  display: none;
`;


================================================
FILE: src/components/TablePopup/index.tsx
================================================
import React, { FC } from 'react';
import { StyledPopup, StyledPopupItem } from './styled';

type TablePopupProps = {
  dataLength: number;
  popupElements: string[];
};

export const TablePopup: FC<TablePopupProps> = ({ popupElements, dataLength }) => {
  return (
    <StyledPopup dataLength={dataLength}>
      {popupElements?.map((element: string) => (
        <StyledPopupItem key={element}>{element}</StyledPopupItem>
      ))}
    </StyledPopup>
  );
};


================================================
FILE: src/components/TablePopup/styled.ts
================================================
import { WHITE_COLOR, DARK_TEXT_COLOR, TABLE_POPUP_BORDER_COLOR } from 'appConstants/colors';
import styled from 'styled-components';
import { GeneralAdaptiveFont } from 'typography';

type TStyledPopup = {
  dataLength: number;
};

export const StyledPopup = styled.div<TStyledPopup>`
  position: absolute;
  top: ${({ dataLength }) => dataLength < 0.5 && '95%'};
  bottom: ${({ dataLength }) => dataLength > 0.5 && '95%'};
  right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 10px;
  font-size: 1rem;
  color: ${DARK_TEXT_COLOR};
  background-color: ${WHITE_COLOR};
  border: 1px solid ${TABLE_POPUP_BORDER_COLOR};
  border-radius: 10px;
  ${GeneralAdaptiveFont};
  @media (max-width: 440px) {
    left: -5px;
    padding: 5px;
  }
`;

export const StyledPopupItem = styled.p`
  margin: 0;
  line-height: 17px;
  text-align: justify;
`;


================================================
FILE: src/components/TourGuide/index.tsx
================================================
import React, { FC, useCallback, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { selectIsTourOpen } from 'modules/LoginPage/selectors';
import Tour, { ReactourStep } from 'reactour';
import { tourConfig } from './tourConfig';
import { setIsTourOpen } from 'modules/LoginPage/loginPageReducer';
import { MAIN1_COLOR } from 'appConstants/colors';
import leftArrow from 'assets/svg/paginateArrowLeft.svg';
import rightArrow from 'assets/svg/paginateArrowRight.svg';
import './style.css';
import { useHistory } from 'react-router';
import { useTranslation } from 'react-i18next';

export const TourGuide: FC = () => {
  const [isButtonsVisible, setIsButtonsVisible] = useState(false);
  const dispatch = useDispatch();
  const isTourOpen = useSelector(selectIsTourOpen);
  const history = useHistory();
  const { t } = useTranslation();

  const onRequestCloseHandler = () => dispatch(setIsTourOpen(false));

  const tourConfigInfo = useCallback(
    () => tourConfig(history, dispatch, t),
    [history, dispatch, t]
  );

  return (
    <Tour
      onRequestClose={onRequestCloseHandler}
      steps={tourConfigInfo() as ReactourStep[]}
      isOpen={isTourOpen}
      prevButton={<img src={leftArrow} alt="Previous" />}
      nextButton={<img src={rightArrow} alt="Next" />}
      accentColor={MAIN1_COLOR}
      maskClassName="mask"
      disableDotsNavigation
      disableKeyboardNavigation
      showNavigationNumber={false}
      showButtons={isButtonsVisible}
      disableInteraction
      lastStepNextButton={<div className="LastStepNextButton" />}
      getCurrentStep={(currStep) => setIsButtonsVisible(!!currStep)}
      closeWithMask={false}
      className="helper"
      rounded={20}
    />
  );
};


================================================
FILE: src/components/TourGuide/style.css
================================================
span[data-tour-elem="badge"] {
  top: 20px;
  left: 20px;
  width: 30px;
  height: 30px;
  padding: 0;
  font-weight: bold;
  font-family: "Poppins", sans-serif;
  border-radius: 50%;
  box-shadow: none;
}

.reactour__helper.helper {
  width: 440px;
  max-width: 440px;
  padding: 64px 20px 20px;
  font-family: "Poppins", sans-serif;
  text-align: justify;
  box-shadow: none;
}

.reactour__helper.helper p {
  text-align: center;
}

.reactour__helper.helper > .reactour__close {
  top: 18px;
  right: 18px;
  width: 18px;
  height: 18px;
  color: #7e96c2;
  background: center / contain url("../../assets/svg/cross.svg") no-repeat;
}

.reactour__close > svg {
  display: none;
}

button[data-tour-elem="right-arrow"] {
  order: 2;
  margin-left: 0;
}

button[data-tour-elem="left-arrow"] {
  order: 1;
  margin-right: 10px;
  margin-left: auto;
}

button[data-tour-elem="right-arrow"],
button[data-tour-elem="left-arrow"],
.LastStepNextButton {
  width: 40px;
  height: 40px;
  border-radius: 10px;
}

button[data-tour-elem="right-arrow"],
button[data-tour-elem="left-arrow"] {
  background-color: #f2f8fd;
}

.LastStepNextButton {
  background-color: #ffffff;
  cursor: default;
}

button[data-tour-elem="right-arrow"] > img,
button[data-tour-elem="left-arrow"] > img {
  margin: 0 auto;
  background-color: transparent;
}

div[data-tour-elem="controls"] {
  align-items: flex-end;
}

nav > .reactour__dot {
  background-color: #e1eefa;
  border: none;
}

nav > .reactour__dot:disabled {
  cursor: unset;
}

nav > .reactour__dot--is-active {
  background-color: #6550f6;
}

.mask {
  color: #363d48;
  opacity: 0.4;
}

.linkToRepo {
  font-weight: bold;
  color: #6550f6;
  text-decoration: none;
  outline: none;
}

.linkToRepo:hover {
  text-decoration: underline;
}

@media (max-width: 550px) {
  .reactour__helper.helper {
    width: 320px;
    font-size: 0.9rem;
    line-height: 1.1rem;
  }
}

@media (max-width: 440px) {
  .reactour__helper.helper {
    width: 280px;
    font-size: 0.8rem;
    line-height: 1rem;
  }
  span[data-tour-elem="badge"] {
    line-height: 2.5;
  }
  div[data-tour-elem="controls"] {
    flex-wrap: wrap;
    justify-content: center;
  }
  div[data-tour-elem="controls"] > nav {
    width: 100%;
    margin-bottom: 10px;
  }
  button[data-tour-elem="left-arrow"] {
    margin-left: unset;
  }
}



================================================
FILE: src/components/TourGuide/styled.ts
================================================
import styled from 'styled-components';
import { MAIN1_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { TextSemiBold, GeneralAdaptiveFont, GeneralButtonPadding } from 'typography';

export const LinkButton = styled.a`
  ${TextSemiBold};
  margin-right: 0;
  border-radius: 20px;
  border: none;
  text-decoration: none;
  outline: none;
  cursor: pointer;
  background-color: ${MAIN1_COLOR};
  color: ${WHITE_COLOR};
  ${GeneralAdaptiveFont};
  ${GeneralButtonPadding}
`;


================================================
FILE: src/components/TourGuide/tourConfig.tsx
================================================
import { Button, InvertedButton, ButtonsBlock } from 'typography';
import { setIsTourOpen } from 'modules/LoginPage/loginPageReducer';
import { LINK_TO_REPO } from 'appConstants';
import { LinkButton } from './styled';
import { Dispatch } from 'redux';
import { History, LocationState } from 'history';

export const tourConfig = (
  history: History<LocationState>,
  dispatch: Dispatch,
  t: (text: string) => string
) => [
  {
    content: ({ goTo }: { goTo: (step: number) => void }) => (
      <div>
        <p>{t('Welcome to RSS Teams')}</p>
        <ButtonsBlock>
          <InvertedButton onClick={() => goTo(9)}>{t('Skip')}</InvertedButton>
          <Button onClick={() => goTo(1)}>{t('Next')}</Button>
        </ButtonsBlock>
      </div>
    ),
    action: () => history.push('/'),
  },
  {
    selector: '.secondStep',
    content: t('You can create new team'),
    action: () => history.push('/'),
  },
  {
    selector: '.thirdStep',
    content: t('Or join existing team'),
    action: () => history.push('/'),
  },
  {
    selector: '.fourthStep',
    content: t('You can always leave the course'),
    action: () => history.push('/'),
  },
  {
    content: t('On Teams page you can see other teams'),
    action: () => history.push('/'),
  },
  {
    content: t('On Dashboard page'),
    action: () => history.push('/students'),
  },
  {
    selector: '.seventhStep',
    content: t('With filter usage'),
    position: 'bottom',
    action: () => history.push('/students'),
  },
  {
    selector: '.eighthStep',
    content: t('With dropdown you can switch the course'),
    position: 'bottom',
    action: () => history.push('/students'),
  },
  {
    content: t('On Edit profile page'),
    action: () => history.push('/edit-profile'),
  },
  {
    content: t('If you forget something'),
    action: () => history.push('/tutorial'),
  },
  {
    content: () => (
      <div>
        <p>
          {t('Support us')}{' '}
          <a href={LINK_TO_REPO} className="linkToRepo" target="_blank" rel="noreferrer">
            {t('our repo')}
          </a>
          !
        </p>
        <ButtonsBlock>
          <LinkButton
            onClick={() => {
              dispatch(setIsTourOpen(false));
            }}
            href={LINK_TO_REPO}
            target="_blank"
            rel="noreferrer"
          >
            {t('Got it')}
          </LinkButton>
        </ButtonsBlock>
      </div>
    ),
    action: () => history.push('/'),
  },
];


================================================
FILE: src/components/index.ts
================================================
export { App } from './App';
export { Loader } from './Loader';
export { PrivateRoute } from './PrivateRoute';
export { Header } from './Header';
export { InputField } from './InputField';
export { CourseField } from './CourseField';
export { Pagination } from './Pagination';
export { Modal } from './Modal';
export { ModalExpel } from './ModalExpel';
export { ModalJoin } from './ModalJoin';
export { ModalCreateEditTeam } from './ModalCreateEditTeam';
export { ModalCreated } from './ModalCreated';
export { TablePopup } from './TablePopup';
export { FilterForm } from './FilterForm';
export { FilterSelect } from './FilterSelect';
export { Footer } from './Footer';
export { ErrorModal } from './ErrorModal';
export { CommonSelectList } from './CommonSelectList';
export { TourGuide } from './TourGuide';
export { ModalEditCourse } from './ModalEditCourse';


================================================
FILE: src/graphql/mutations/addUserToTeamMutation.ts
================================================
import { gql } from '@apollo/client';

export const ADD_USER_TO_TEAM_MUTATION = gql`
  mutation addUserToTeam($data: AddUserToTeamInput!) {
    addUserToTeam(data: $data) {
      id
      firstName
      lastName
      github
      telegram
      discord
      score
      country
      city
      isAdmin
      courses {
        id
        name
      }
      teams {
        id
        password
        number
        courseId
        socialLink
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/mutations/createCourseMutation.ts
================================================
import { gql } from '@apollo/client';

export const CREATE_COURSE_MUTATION = gql`
  mutation createCourse($course: CreateCourseInput!) {
    createCourse(course: $course) {
      id
      name
      teamSize
      isActive
    }
  }
`;


================================================
FILE: src/graphql/mutations/createTeamMutation.ts
================================================
import { gql } from '@apollo/client';

export const CREATE_TEAM_MUTATION = gql`
  mutation createTeam($team: CreateTeamInput!) {
    createTeam(team: $team) {
      id
      password
      number
      courseId
      socialLink
      memberIds
      members {
        id
        firstName
        lastName
        github
        telegram
        discord
        score
        country
        city
      }
    }
  }
`;


================================================
FILE: src/graphql/mutations/index.ts
================================================
export { UPD_USER_MUTATION } from './updUserMutation';
export { ADD_USER_TO_TEAM_MUTATION } from './addUserToTeamMutation';
export { REMOVE_USER_FROM_TEAM_MUTATION } from './removeUserFromTeamMutation';
export { CREATE_TEAM_MUTATION } from './createTeamMutation';
export { UPDATE_TEAM_MUTATION } from './updateTeamMutation';
export { SORT_STUDENTS_MUTATION } from './sortStudentsMutation';
export { REMOVE_USER_FROM_COURSE_MUTATION } from './removeUserFromCourseMutation';
export { CREATE_COURSE_MUTATION } from './createCourseMutation';
export { UPDATE_COURSE_MUTATION } from './updateCourseMutation';


================================================
FILE: src/graphql/mutations/removeUserFromCourseMutation.ts
================================================
import { gql } from '@apollo/client';

export const REMOVE_USER_FROM_COURSE_MUTATION = gql`
  mutation removeUserFromCourse($data: RemoveUserFromCourseInput!) {
    removeUserFromCourse(data: $data) {
      id
      firstName
      lastName
      github
      telegram
      discord
      score
      country
      city
      isAdmin
      courses {
        id
        name
      }
      teams {
        id
        password
        number
        courseId
        socialLink
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/mutations/removeUserFromTeamMutation.ts
================================================
import { gql } from '@apollo/client';

export const REMOVE_USER_FROM_TEAM_MUTATION = gql`
  mutation removeUserFromTeam($data: RemoveUserFromTeamInput!) {
    removeUserFromTeam(data: $data) {
      id
      firstName
      lastName
      github
      telegram
      discord
      score
      country
      city
      avatar
      isAdmin
      courses {
        id
        name
      }
      email
      courseIds
      teamIds
      teams {
        id
        password
        number
        courseId
        socialLink
        memberIds
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/mutations/sortStudentsMutation.ts
================================================
import { gql } from '@apollo/client';

export const SORT_STUDENTS_MUTATION = gql`
  mutation sortStudents($courseId: String!) {
    sortStudents(courseId: $courseId)
  }
`;


================================================
FILE: src/graphql/mutations/updUserMutation.ts
================================================
import { gql } from '@apollo/client';

export const UPD_USER_MUTATION = gql`
  mutation updateUser($user: UpdateUserInput!) {
    updateUser(user: $user) {
      id
      firstName
      lastName
      github
      telegram
      discord
      score
      country
      city
      isAdmin
      courses {
        id
        name
      }
      teams {
        id
        password
        number
        courseId
        socialLink
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/mutations/updateCourseMutation.ts
================================================
import { gql } from '@apollo/client';

export const UPDATE_COURSE_MUTATION = gql`
  mutation updateCourse($course: UpdateCourseInput!) {
    updateCourse(course: $course) {
      id
      name
      teamSize
      isActive
    }
  }
`;


================================================
FILE: src/graphql/mutations/updateTeamMutation.ts
================================================
import { gql } from '@apollo/client';

export const UPDATE_TEAM_MUTATION = gql`
  mutation updateTeam($team: UpdateTeamInput!) {
    updateTeam(team: $team) {
      id
      password
      number
      courseId
      socialLink
      memberIds
      members {
        id
        firstName
        lastName
        github
        telegram
        discord
        score
        country
        city
      }
    }
  }
`;


================================================
FILE: src/graphql/queries/coursesQuery.ts
================================================
import { gql } from '@apollo/client';

export const COURSES_QUERY = gql`
  query getCourses {
    courses {
      id
      name
      teamSize
      isActive
    }
  }
`;


================================================
FILE: src/graphql/queries/index.ts
================================================
export { TEAMS_QUERY } from './teamsQuery';
export { USERS_QUERY } from './usersQuery';
// export { USER_QUERY } from './userQuery';
export { WHOAMI_QUERY } from './whoAmIQuery';
export { COURSES_QUERY } from './coursesQuery';


================================================
FILE: src/graphql/queries/teamsQuery.ts
================================================
import { gql } from '@apollo/client';

export const TEAMS_QUERY = gql`
  query getTeams($courseId: String!, $pagination: PaginationInput!) {
    teams(courseId: $courseId, pagination: $pagination) {
      count
      results {
        id
        number
        courseId
        socialLink
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/queries/usersQuery.ts
================================================
import { gql } from '@apollo/client';

export const USERS_QUERY = gql`
  query getUsers($courseId: String!, $pagination: PaginationInput!, $filter: UserFilterInput) {
    users(courseId: $courseId, pagination: $pagination, filter: $filter) {
      count
      results {
        id
        firstName
        lastName
        github
        telegram
        discord
        score
        country
        city
        isAdmin
        courses {
          id
          name
        }
        teams {
          id
          number
          courseId
        }
      }
    }
  }
`;


================================================
FILE: src/graphql/queries/whoAmIQuery.ts
================================================
import { gql } from '@apollo/client';

export const WHOAMI_QUERY = gql`
  query getWhoAMi {
    whoAmI {
      id
      firstName
      lastName
      github
      telegram
      discord
      score
      country
      city
      isAdmin
      courses {
        id
        name
      }
      teams {
        id
        password
        number
        courseId
        socialLink
        members {
          id
          firstName
          lastName
          github
          telegram
          discord
          score
          country
          city
        }
      }
    }
  }
`;


================================================
FILE: src/hooks/graphql/index.ts
================================================
export { useTeamsQuery } from './queries/useTeamsQuery';
export { useUsersQuery } from './queries/useUsersQuery';
export { useWhoAmIQuery } from './queries/useWhoAmIQuery';
export { useCoursesQuery } from './queries/useCoursesQuery';
export { useUpdUserMutation } from './mutations/useUpdUserMutation';
export { useRemoveUserFromTeamMutation } from './mutations/useRemoveUserFromTeamMutation';
export { useExpelUserFromTeamMutation } from './mutations/useExpelUserFromTeamMutation';
export { useCreateTeamMutation } from './mutations/useCreateTeamMutation';
export { useAddUserToTeamMutation } from './mutations/useAddUserToTeamMutation';
export { useUpdateTeamMutation } from './mutations/useUpdateTeamMutation';
export { useSortStudentsMutation } from './mutations/useSortStudentsMutation';
export { useRemoveUserFromCourseMutation } from './mutations/useRemoveUserFromCourseMutation';
export { useCreateCourseMutation } from './mutations/useCreateCourseMutation';
export { useUpdateCourseMutation } from './mutations/useUpdateCourseMutation';


================================================
FILE: src/hooks/graphql/mutations/useAddUserToTeamMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { ADD_USER_TO_TEAM_MUTATION } from 'graphql/mutations';
import { WHOAMI_QUERY } from 'graphql/queries';
import { AddUserToTeamInput } from 'types';

type Props = {
  data: AddUserToTeamInput;
};

export const useAddUserToTeamMutation = ({ data }: Props) => {
  const [addUserToTeam, { loading, error }] = useMutation(ADD_USER_TO_TEAM_MUTATION, {
    variables: {
      data,
    },

    update(cache, { data: { addUserToTeam } }) {
      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          addUserToTeam,
        },
      });
    },
  });
  return {
    addUserToTeam,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useCreateCourseMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { Course, CreateCourseInput } from 'types';
import { COURSES_QUERY } from 'graphql/queries';
import { CREATE_COURSE_MUTATION } from 'graphql/mutations';

type Props = {
  course: CreateCourseInput;
};

export const useCreateCourseMutation = ({ course }: Props) => {
  const [createCourse, { loading, error }] = useMutation(CREATE_COURSE_MUTATION, {
    variables: {
      course,
    },

    update(cache, { data: { createCourse } }) {
      const data: { courses: Course[] } | null = cache.readQuery({
        query: COURSES_QUERY,
      });

      const updatedResults = data?.courses?.length
        ? [createCourse, ...data?.courses]
        : [createCourse];

      cache.writeQuery({
        query: COURSES_QUERY,
        data: {
          courses: updatedResults,
        },
      });
    },
  });
  return {
    createCourse,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useCreateTeamMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { CreateTeamInput, TeamList, User } from 'types';
import { TEAMS_QUERY, WHOAMI_QUERY } from 'graphql/queries';
import { CREATE_TEAM_MUTATION } from 'graphql/mutations';
import { TEAMS_PER_PAGE } from 'appConstants';

type Props = {
  team: CreateTeamInput;
};

export const useCreateTeamMutation = ({ team }: Props) => {
  const { courseId, ownerId, socialLink, page } = team;
  const dataForMutation = { courseId, ownerId, socialLink };
  const [createTeam, { loading, error }] = useMutation(CREATE_TEAM_MUTATION, {
    variables: {
      team: dataForMutation,
    },

    update(cache, { data: { createTeam } }) {
      const data: { teams: TeamList } | null = cache.readQuery({
        query: TEAMS_QUERY,
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });
      const userData: { whoAmI: User } | null = cache.readQuery({
        query: WHOAMI_QUERY,
      });

      const updatedResults = data?.teams?.results.length
        ? [...data?.teams?.results, createTeam]
        : [createTeam];

      const updatedUser = {
        ...userData?.whoAmI,
        teams: userData?.whoAmI?.teams.length
          ? [...userData?.whoAmI?.teams, createTeam]
          : [createTeam],
      };

      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          whoAmI: updatedUser,
        },
      });

      cache.writeQuery({
        query: TEAMS_QUERY,
        data: {
          teams: {
            count: updatedResults.length,
            results: updatedResults,
          },
        },
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });
    },
  });
  return {
    createTeam,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useExpelUserFromTeamMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { RemoveUserFromTeamInput, Team, TeamList, User } from 'types';
import { TEAMS_QUERY, WHOAMI_QUERY } from 'graphql/queries';
import { REMOVE_USER_FROM_TEAM_MUTATION } from 'graphql/mutations';
import { TEAMS_PER_PAGE } from 'appConstants';

type Props = {
  data: RemoveUserFromTeamInput;
};

export const useExpelUserFromTeamMutation = ({ data }: Props) => {
  const { teamId, page, userId, courseId } = data;
  const dataForMutation = { userId, teamId };
  const [expelUserFromTeam, { loading, error }] = useMutation(REMOVE_USER_FROM_TEAM_MUTATION, {
    variables: {
      data: dataForMutation,
    },

    update(cache, { data: {} }) {
      const data: { teams: TeamList } | null = cache.readQuery({
        query: TEAMS_QUERY,
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });

      const userData: { whoAmI: User } | null = cache.readQuery({
        query: WHOAMI_QUERY,
      });

      const updatedRemovedResults = data?.teams.results.map((team: Team) => {
        if (team.id === teamId) {
          return {
            ...team,
            members: team.members.filter((member: User) => member.id !== userId),
          };
        }
        return team;
      });

      const updatedTeams = (userData?.whoAmI.teams as Team[]).map((team: Team) => {
        if (team.id === teamId) {
          return {
            ...team,
            members: team.members.filter((member: User) => member.id !== userId),
          };
        }
        return team;
      });

      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          ...userData?.whoAmI,
          teams: updatedTeams,
        },
      });

      cache.writeQuery({
        query: TEAMS_QUERY,
        data: {
          teams: {
            count: data?.teams?.count,
            results: updatedRemovedResults,
          },
        },
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });
    },
  });
  return {
    expelUserFromTeam,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useRemoveUserFromCourseMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { CURRENT_COURSE, TEAMS_PER_PAGE } from 'appConstants';
import { REMOVE_USER_FROM_COURSE_MUTATION } from 'graphql/mutations';
import { TEAMS_QUERY, WHOAMI_QUERY } from 'graphql/queries';
import { setCourse } from 'modules/LoginPage/loginPageMiddleware';
import { setCommonError, setCurrCourse } from 'modules/LoginPage/loginPageReducer';
import { setUserData } from 'modules/StudentsTable/studentsTableReducer';
import { useDispatch } from 'react-redux';
import { RemoveUserFromCourseInput, Team, TeamList, User } from 'types';

type Props = {
  data: RemoveUserFromCourseInput;
};

export const useRemoveUserFromCourseMutation = ({
  data: { page, courseId, userId, teamId },
}: Props) => {
  const dataForMutation = { courseId, userId, teamId };
  const dispatch = useDispatch();
  const [removeUserFromCourse, { loading, error }] = useMutation(REMOVE_USER_FROM_COURSE_MUTATION, {
    variables: {
      data: dataForMutation,
    },

    update(cache, { data: { removeUserFromCourse } }) {
      const data: { teams: TeamList } | null = cache.readQuery({
        query: TEAMS_QUERY,
        variables: {
          courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });

      const updatedRemovedResults = data?.teams.results
        .map((team: Team) => {
          if (team.id === teamId) {
            if (team.members.length === 1) {
              return null;
            }
            return {
              ...team,
              members: team.members.filter((member: User) => member.id !== userId),
            };
          }
          return team;
        })
        .filter((team: Team | null) => !!team);

      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          removeUserFromCourse,
        },
      });

      cache.writeQuery({
        query: TEAMS_QUERY,
        data: {
          teams: {
            count: data?.teams?.count,
            results: updatedRemovedResults,
          },
        },
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });
    },

    onCompleted({ removeUserFromCourse }) {
      if (!!removeUserFromCourse.courses[0]) {
        dispatch(setCourse(removeUserFromCourse.courses[0]));
      } else {
        dispatch(setCurrCourse({ name: '', id: '' }));
        localStorage.removeItem(CURRENT_COURSE);
      }
      dispatch(setUserData(removeUserFromCourse));
    },
    onError() {
      dispatch(setCommonError(true));
    },
  });
  return {
    removeUserFromCourse,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useRemoveUserFromTeamMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { RemoveUserFromTeamInput, Team, TeamList, User } from 'types';
import { TEAMS_QUERY, WHOAMI_QUERY } from 'graphql/queries';
import { REMOVE_USER_FROM_TEAM_MUTATION } from 'graphql/mutations';
import { TEAMS_PER_PAGE } from 'appConstants';

type Props = {
  data: RemoveUserFromTeamInput;
};

export const useRemoveUserFromTeamMutation = ({ data }: Props) => {
  const { teamId, page, userId, courseId } = data;
  const dataForMutation = { userId, teamId };
  const [removeUserFromTeam, { loading, error }] = useMutation(REMOVE_USER_FROM_TEAM_MUTATION, {
    variables: {
      data: dataForMutation,
    },

    update(cache, { data: { removeUserFromTeam } }) {
      const data: { teams: TeamList } | null = cache.readQuery({
        query: TEAMS_QUERY,
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });

      const updatedRemovedResults = data?.teams.results
        .map((team: Team) => {
          if (team.id === teamId) {
            return {
              ...team,
              members: team.members.filter((member: User) => member.id !== userId),
            };
          }
          return team;
        })
        .filter((team: Team | undefined) => !!team?.members.length);

      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          removeUserFromTeam,
        },
      });

      cache.writeQuery({
        query: TEAMS_QUERY,
        data: {
          teams: {
            count: updatedRemovedResults?.length,
            results: updatedRemovedResults,
          },
        },
        variables: {
          courseId: courseId,
          pagination: { skip: page * TEAMS_PER_PAGE, take: TEAMS_PER_PAGE },
        },
      });
    },
  });
  return {
    removeUserFromTeam,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useSortStudentsMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { SORT_STUDENTS_MUTATION } from 'graphql/mutations';

type Props = {
  courseId: string;
};

export const useSortStudentsMutation = ({ courseId }: Props) => {
  const [sortStudents, { loading, error }] = useMutation(SORT_STUDENTS_MUTATION, {
    variables: {
      courseId,
    },
  });
  return {
    sortStudents,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useUpdUserMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { UPD_USER_MUTATION } from 'graphql/mutations';
import { WHOAMI_QUERY } from 'graphql/queries';
import { UpdateUserInput } from 'types';

type Props = {
  user: UpdateUserInput;
};

export const useUpdUserMutation = ({ user }: Props) => {
  const formattedUser = { ...user, score: Number(user.score) };
  const [updateUser, { loading, error }] = useMutation(UPD_USER_MUTATION, {
    variables: {
      user: formattedUser,
    },
    update(cache, { data: { updateUser } }) {
      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          updateUser,
        },
      });
    },
  });
  return {
    updateUser,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useUpdateCourseMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { UpdateCourseInput, Course } from 'types';
import { COURSES_QUERY } from 'graphql/queries';
import { UPDATE_COURSE_MUTATION } from 'graphql/mutations';

type Props = {
  course: UpdateCourseInput;
};

export const useUpdateCourseMutation = ({ course }: Props) => {
  const { id } = course;
  const [updateCourse, { loading, error }] = useMutation(UPDATE_COURSE_MUTATION, {
    variables: {
      course,
    },

    update(cache, { data: { updateCourse } }) {
      const data: { courses: Course[] } | null = cache.readQuery({
        query: COURSES_QUERY,
      });

      const updatedResults = data?.courses?.map((course: Course) => {
        if (course.id === id) {
          return updateCourse;
        }
        return course;
      });

      cache.writeQuery({
        query: COURSES_QUERY,
        data: {
          courses: updatedResults,
        },
      });
    },
  });
  return {
    updateCourse,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/mutations/useUpdateTeamMutation.ts
================================================
import { useMutation } from '@apollo/client';
import { UpdateTeamInput, User, Team } from 'types';
import { WHOAMI_QUERY } from 'graphql/queries';
import { UPDATE_TEAM_MUTATION } from 'graphql/mutations';

type Props = {
  team: UpdateTeamInput;
};

export const useUpdateTeamMutation = ({ team }: Props) => {
  const { id } = team;
  const [updateTeam, { loading, error }] = useMutation(UPDATE_TEAM_MUTATION, {
    variables: {
      team,
    },

    update(cache, { data: { updateTeam } }) {
      const userData: { whoAmI: User } | null = cache.readQuery({
        query: WHOAMI_QUERY,
      });

      const updatedUserTeam = (userData?.whoAmI.teams as Team[]).map((team: Team) => {
        if (team.id === id) {
          return updateTeam;
        }
        return team;
      });

      cache.writeQuery({
        query: WHOAMI_QUERY,
        data: {
          whoAmI: {
            ...userData?.whoAmI,
            teams: updatedUserTeam,
          },
        },
      });
    },
  });
  return {
    updateTeam,
    loadingM: loading,
    errorM: error,
  };
};


================================================
FILE: src/hooks/graphql/queries/useCoursesQuery.ts
================================================
import { useQuery } from '@apollo/client';

import { COURSES_QUERY } from 'graphql/queries';

export const useCoursesQuery = () => {
  const { data, loading, error } = useQuery(COURSES_QUERY);
  const isLoaded = !loading && data?.courses;

  return {
    loading: !isLoaded,
    error,
    courses: data?.courses,
  };
};


================================================
FILE: src/hooks/graphql/queries/useTeamsQuery.ts
================================================
import { useQuery } from '@apollo/client';
import { TEAMS_PER_PAGE } from 'appConstants';

import { TEAMS_QUERY } from 'graphql/queries';
type Props = {
  reactCourseId: string;
  skip?: boolean;
  page?: number;
};

export const useTeamsQuery = ({ reactCourseId, skip = false, page = 0 }: Props) => {
  const { data, loading, error } = useQuery(TEAMS_QUERY, {
    skip,
    variables: {
      courseId: reactCourseId,
      pagination: {
        skip: page * TEAMS_PER_PAGE,
        take: TEAMS_PER_PAGE,
      },
    },
  });
  const isLoaded = !loading && !!data;
  return {
    loadingT: !isLoaded,
    errorT: error,
    teams: data?.teams,
  };
};


================================================
FILE: src/hooks/graphql/queries/useUsersQuery.ts
================================================
import { useQuery } from '@apollo/client';
import { USERS_PER_PAGE } from 'appConstants';

import { USERS_QUERY } from 'graphql/queries';
import { UserFilterInput } from 'types';

type Props = {
  reactCourseId: string;
  skip?: boolean;
  page?: number;
  filter?: UserFilterInput;
};

export const useUsersQuery = ({ reactCourseId, skip = false, page = 0, filter }: Props) => {
  const { data, loading, error } = useQuery(USERS_QUERY, {
    skip,
    variables: {
      filter,
      courseId: reactCourseId,
      pagination: {
        skip: page * USERS_PER_PAGE,
        take: USERS_PER_PAGE,
      },
    },
  });
  const isLoaded = !loading && !!data;

  return {
    loadingU: !isLoaded,
    errorU: error,
    users: data?.users,
  };
};


================================================
FILE: src/hooks/graphql/queries/useWhoAmIQuery.ts
================================================
import { useQuery } from '@apollo/client';
import { WHOAMI_QUERY } from 'graphql/queries';

type Props = {
  skip: boolean;
};

export const useWhoAmIQuery = ({ skip = false }: Props) => {
  const {
    data,
    loading: loadingW,
    error,
  } = useQuery(WHOAMI_QUERY, {
    skip,
  });

  return {
    loadingW,
    errorW: error,
    whoAmI: data?.whoAmI,
  };
};


================================================
FILE: src/index.tsx
================================================
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { AppState } from 'store';
import { ApolloProvider, ApolloClient, createHttpLink, InMemoryCache, from } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import { App } from './components';
import { AUTH_TOKEN, BACKEND_LINK, UNAUTHORIZED_ERROR_MESSAGE } from 'appConstants';
import reportWebVitals from './reportWebVitals';
import 'typography/normalize.css';
import 'typography/fonts.css';
import 'typography/common.css';
import './translation/resources';
import ErrorBoundary from 'components/ErrorBoundary';
import { onError } from '@apollo/client/link/error';

const httpLink = createHttpLink({
  uri: BACKEND_LINK,
});

const unauthorizedLink = onError(({ graphQLErrors }) => {
  const isUserUnauthorized = !!graphQLErrors?.find(
    ({ message }) => message === UNAUTHORIZED_ERROR_MESSAGE
  );

  if (isUserUnauthorized) {
    location.reload();
    sessionStorage.removeItem(AUTH_TOKEN);
  }
});

const authLink = setContext((_, { headers }) => {
  const token = sessionStorage.getItem(AUTH_TOKEN);
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  };
});

const client = new ApolloClient({
  link: from([unauthorizedLink, authLink, httpLink]),
  cache: new InMemoryCache({
    typePolicies: {
      User: {
        fields: {
          teams: {
            merge(_, incoming) {
              return incoming;
            },
          },
          courses: {
            merge(_, incoming) {
              return incoming;
            },
          },
        },
      },
      Team: {
        fields: {
          members: {
            merge(_, incoming) {
              return incoming;
            },
          },
        },
      },
      Query: {
        fields: {
          teams: {
            merge(_, incoming) {
              return incoming;
            },
          },
        },
      },
    },
  }),
  connectToDevTools: true,
});

ReactDOM.render(
  <ErrorBoundary>
    <ApolloProvider client={client}>
      <Router>
        <AppState>
          <App />
        </AppState>
      </Router>
    </ApolloProvider>
  </ErrorBoundary>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock/index.tsx
================================================
import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { ModalInput, Label } from 'typography';
import { ValidationAlert } from 'components/InputField/styled';
import { InputWrapper, FieldWrapper } from './styled';

interface InputBlockProps {
  inputLabel: string;
  value: string;
  placeholder: string;
  onChangeHandler: (e: React.ChangeEvent<HTMLInputElement>) => void;
  isFieldValid: boolean;
  errorMessage: string;
  isModal?: boolean;
}

export const InputBlock: FC<InputBlockProps> = ({
  inputLabel,
  value,
  placeholder,
  onChangeHandler,
  isFieldValid,
  errorMessage,
  isModal,
}) => {
  const { t } = useTranslation();

  return (
    <InputWrapper isModal={isModal}>
      <Label marginBottom="0px">{t(inputLabel)}</Label>
      <FieldWrapper>
        <ModalInput
          name="inputValue"
          required
          value={value}
          mt="0px"
          autoComplete={'off'}
          onChange={onChangeHandler}
          placeholder={t(placeholder)}
        />
        {!isFieldValid && <ValidationAlert>{t(errorMessage)}</ValidationAlert>}
      </FieldWrapper>
    </InputWrapper>
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock/styled.ts
================================================
import styled from 'styled-components';

export const InputWrapper = styled.div<{ isModal?: boolean }>`
  display: flex;
  ${({ isModal }) => isModal && 'flex-direction: column;'}
  justify-content: space-between;
  align-items: center;
  width: 100%;
  height: fit-content;
  ${({ isModal }) => isModal && 'margin-bottom: 40px;'}
  gap: ${({ isModal }) => (isModal ? '5px' : '20px')};

  @media (max-width: 580px) {
    ${({ isModal }) => isModal && 'margin-bottom: 30px;'}
    label {
      ${({ isModal }) => !isModal && 'display: none;'}
    }
  }
`;

export const FieldWrapper = styled.div`
  position: relative;
  display: flex;
  flex-direction: column;

  & > div:nth-child(2) {
    position: absolute;
    top: 100%;
  }
`;


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/index.tsx
================================================
import React, { FC, useCallback, useState } from 'react';
import { MAIN2_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { useTranslation } from 'react-i18next';
import { TeamButton } from 'typography';
import { InputBlock } from './components/InputsBlock';
import { AddCourseBlockWrapper, InputsBlockWrapper } from './styled';
import { isFieldValid } from 'utils/isFieldValid';
import { COURSE_NAME_VALIDATION, TEAM_SIZE_VALIDATION } from 'appConstants';
import { useCreateCourseMutation } from 'hooks/graphql';
import { ErrorModal, Modal } from 'components';
import { activeModalCreatedCourse } from 'modules/TeamsList/teamsListReducer';
import { useDispatch, useSelector } from 'react-redux';
import { selectIsActiveModalCreatedCourse } from 'modules/TeamsList/selectors';

export const onChangeField =
  (
    validateRules: any,
    setInputValid: (isValid: boolean) => void,
    setErrorMessage: (errorMessage: string) => void,
    setInputValue: (value: string) => void,
    isValueUniq?: (value: string) => boolean
  ) =>
  (e: React.ChangeEvent<HTMLInputElement>) => {
    isFieldValid(
      e.target.value.trim(),
      validateRules,
      !!validateRules,
      setInputValid,
      setErrorMessage,
      isValueUniq
    );
    setInputValue(e.target.value);
  };

export const AddCourseBlock: FC<{ checkIsCourseNameUniq: (courseName: string) => boolean }> = ({
  checkIsCourseNameUniq,
}) => {
  const dispatch = useDispatch();
  const { t } = useTranslation();
  const isActiveModalCreatedCourse = useSelector(selectIsActiveModalCreatedCourse);
  const [isCourseNameFieldValid, setIsCourseNameFieldValid] = useState(true);
  const [isTeamSizeFieldValid, setIsTeamSizeFieldValid] = useState(true);
  const [courseName, setCourseName] = useState('');
  const [teamSize, setTeamSize] = useState('');
  const [courseNameErrorMessage, setCourseNameErrorMessage] = useState('');
  const [teamSizeErrorMessage, setTeamSizeErrorMessage] = useState('');

  const { createCourse, errorM: errorCreateCourse } = useCreateCourseMutation({
    course: {
      name: courseName,
      teamSize: +teamSize,
      isActive: true,
    },
  });

  const onAddNewCourse = useCallback(() => {
    if (isCourseNameFieldValid && isTeamSizeFieldValid) {
      if (courseName && teamSize) {
        createCourse().then(() => {
          dispatch(activeModalCreatedCourse(true));
        });
      } else {
        if (!courseName) {
          setIsCourseNameFieldValid(false);
          setCourseNameErrorMessage(COURSE_NAME_VALIDATION.minLength.message);
        }
        if (!teamSize) {
          setIsTeamSizeFieldValid(false);
          setTeamSizeErrorMessage(TEAM_SIZE_VALIDATION.minLength.message);
        }
      }
    }
  }, [isCourseNameFieldValid, isTeamSizeFieldValid, courseName, teamSize, createCourse, dispatch]);

  if (errorCreateCourse) return <ErrorModal error={errorCreateCourse} />;

  return (
    <>
      <AddCourseBlockWrapper>
        <InputsBlockWrapper>
          <InputBlock
            inputLabel="Course name"
            value={courseName}
            placeholder="Enter course name"
            onChangeHandler={onChangeField(
              COURSE_NAME_VALIDATION,
              setIsCourseNameFieldValid,
              setCourseNameErrorMessage,
              setCourseName,
              checkIsCourseNameUniq
            )}
            isFieldValid={isCourseNameFieldValid}
            errorMessage={courseNameErrorMessage}
          />
          <InputBlock
            inputLabel="Team size"
            value={teamSize}
            placeholder="Enter team size"
            onChangeHandler={onChangeField(
              TEAM_SIZE_VALIDATION,
              setIsTeamSizeFieldValid,
              setTeamSizeErrorMessage,
              setTeamSize
            )}
            isFieldValid={isTeamSizeFieldValid}
            errorMessage={teamSizeErrorMessage}
          />
        </InputsBlockWrapper>
        <TeamButton bgc={MAIN2_COLOR} color={WHITE_COLOR} type="button" onClick={onAddNewCourse}>
          {t('Add new course')}
        </TeamButton>
      </AddCourseBlockWrapper>
      <Modal
        title="Course was created"
        text="If you want to change something in new course"
        onClose={() => {
          setCourseName('');
          setTeamSize('');
          dispatch(activeModalCreatedCourse(false));
        }}
        cancelText="Got it!"
        open={isActiveModalCreatedCourse}
        hideOnOutsideClick
        hideOnEsc
      ></Modal>
    </>
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/styled.ts
================================================
import styled from 'styled-components';

export const AddCourseBlockWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 250px;
  gap: 4%;

  @media (max-width: 850px) {
    flex-direction: column;
  }
`;

export const InputsBlockWrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: fit-content;
  height: fit-content;
  gap: 20px;

  @media (max-width: 850px) {
    margin-bottom: 30px;
  }
`;


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/CoursesList/components/Course/index.tsx
================================================
import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch } from 'react-redux';
import { CourseButton } from 'typography';
import { CourseWrapper } from './styled';
import { activeModalEditCourse, activeModalSortStudents } from 'modules/TeamsList/teamsListReducer';
import { Course } from 'types';

interface ICourseItem {
  index: number;
  id: string;
  name: string;
  teamSize: number | null;
  isActive: boolean;
  setCourseInfoToSort: (course: Partial<Course>) => void;
  setCourseEditMeta: (course: Course | null) => void;
}

export const CourseItem: FC<ICourseItem> = ({
  index,
  id,
  name,
  teamSize,
  isActive,
  setCourseInfoToSort,
  setCourseEditMeta,
}) => {
  const dispatch = useDispatch();
  const { t } = useTranslation();
  const courseOrder = index + 1;
  const courseState = isActive ? 'Active(status)' : 'Terminate(status)';

  const onClickSortStudents = () => {
    setCourseInfoToSort({ id, name });
    dispatch(activeModalSortStudents(true));
  };

  const onClickEditCourse = () => {
    setCourseEditMeta({ id, name, isActive, teamSize });
    dispatch(activeModalEditCourse(true));
  };

  return (
    <CourseWrapper>
      <div className="TableItem--0">{courseOrder}</div>
      <div className="TableItem--1">{name}</div>
      <div className="TableItem--4">{teamSize ?? t('Unset')}</div>
      <div className="TableItem--9">{t(courseState)}</div>
      <CourseButton onClick={onClickEditCourse}>{t('Edit course')}</CourseButton>
      <CourseButton onClick={onClickSortStudents}>{t('Sort students')}</CourseButton>
    </CourseWrapper>
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/CoursesList/components/Course/styled.ts
================================================
import styled from 'styled-components';
import { BG_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont } from 'typography';

export const CourseWrapper = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 90%;
  background-color: ${BG_COLOR};
  padding: 20px;
  border-radius: 20px;

  & > div:nth-child(1) {
    font-weight: 600;
  }

  & > div {
    ${GeneralAdaptiveFont};
  }

  @media (max-width: 1100px) {
    flex-direction: column;
    width: 40%;
    gap: 10px;

    & > div:nth-child(1) {
      text-align: left;
    }

    button,
    div {
      width: 90%;
      text-align: center;
    }
  }

  @media (max-width: 768px) {
    width: 80%;
  }

  @media (max-width: 450px) {
    gap: 5px;
  }
`;


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/CoursesList/index.tsx
================================================
import React, { FC } from 'react';
import { CoursesListWrapper } from './styled';
import { CourseItem } from './components/Course';
import { Course } from 'types';
import { ErrorModal, ModalEditCourse, ModalExpel } from 'components';
import { useDispatch, useSelector } from 'react-redux';
import {
  selectIsActiveModalEditCourse,
  selectIsActiveModalSortStudents,
} from 'modules/TeamsList/selectors';
import { activeModalSortStudents } from 'modules/TeamsList/teamsListReducer';
import { useSortStudentsMutation } from 'hooks/graphql';
import { useState } from 'react';

export const CoursesList: FC<{
  courses: Course[];
  checkIsCourseNameUniq: (courseName: string) => boolean;
}> = ({ courses, checkIsCourseNameUniq }) => {
  const [courseInfoToSort, setCourseInfoToSort] = useState<Partial<Course> | null>(null);
  const [courseEditMeta, setCourseEditMeta] = useState<Course | null>(null);
  const dispatch = useDispatch();
  const isActiveModalSortStudents = useSelector(selectIsActiveModalSortStudents);
  const isActiveModalEditCourse = useSelector(selectIsActiveModalEditCourse);

  const { sortStudents, errorM: errorSortStudents } = useSortStudentsMutation({
    courseId: courseInfoToSort?.id || '',
  });

  const onSubmitSortStudents = () => {
    sortStudents();
  };

  if (errorSortStudents) return <ErrorModal error={errorSortStudents} />;

  return (
    <>
      <CoursesListWrapper>
        {courses.map((course: Course, index: number) => (
          <CourseItem
            key={course.id}
            id={course.id}
            name={course.name}
            index={index}
            isActive={course.isActive}
            teamSize={course.teamSize}
            setCourseInfoToSort={setCourseInfoToSort}
            setCourseEditMeta={setCourseEditMeta}
          />
        ))}
      </CoursesListWrapper>
      <ModalExpel
        title={courseInfoToSort?.name ?? 'Sort students'}
        text="Sort students?"
        open={isActiveModalSortStudents}
        onSubmit={onSubmitSortStudents}
        isCrossIconVisible={false}
        onClose={() => dispatch(activeModalSortStudents(false))}
        okText="Yes"
        cancelText="No"
      />
      {!!courseEditMeta && (
        <ModalEditCourse
          title="Edit course"
          text="Please, enter new course information"
          open={isActiveModalEditCourse}
          okText="Save"
          cancelText="Close"
          courseEditMeta={courseEditMeta}
          checkIsCourseNameUniq={checkIsCourseNameUniq}
          setCourseEditMeta={setCourseEditMeta}
        />
      )}
    </>
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/CoursesList/styled.ts
================================================
import styled from 'styled-components';

export const CoursesListWrapper = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  gap: 20px;

  @media (max-width: 1100px) and (min-width: 768px) {
    flex-wrap: wrap;
    flex-direction: row;
    align-items: stretch;
  }
`;


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/components/ShowCourseSelect/index.tsx
================================================
import React, { FC, useState } from 'react';
import { SHOW_COURSES_OPTIONS } from 'appConstants';
import { CommonSelectList } from 'components';

interface ShowCourseSelectProps {
  currentOption: string;
  setCurrentOption: (newOption: string) => void;
}

export const ShowCourseSelect: FC<ShowCourseSelectProps> = ({
  currentOption,
  setCurrentOption,
}) => {
  const [isSelectOpen, setIsSelectOpen] = useState(false);

  const onOptionChange = (item: { id: string; name: string }) => {
    setCurrentOption(item.name);
  };

  const options: { id: string; name: string }[] = SHOW_COURSES_OPTIONS.filter(
    (option) => option.name !== currentOption
  );

  return (
    <CommonSelectList
      title="Show"
      listItems={options}
      onClickHandler={onOptionChange}
      currItem={currentOption}
      displayList={isSelectOpen}
      setDisplayList={setIsSelectOpen}
      customStyle
      showOptionsSelect
    />
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/index.tsx
================================================
import React, { FC, useState, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { AdminPageContentWrapper, ListTitle, CourseListSettings } from './styled';
import { HeaderDecor } from 'modules/TeamsList/components/Teams/components/MyTeam/styled';
import { AddCourseBlock } from './components/AddCourseBlock';
import { CoursesList } from './components/CoursesList';
import { useCoursesQuery } from 'hooks/graphql';
import { ErrorModal, Loader } from 'components';
import { Course } from 'types';
import { ShowCourseSelect } from './components/ShowCourseSelect';
import { ModalInput } from 'typography';
import { SHOW_COURSES_OPTIONS } from 'appConstants';

const filterCourseList = (courses: Course[], filter: string, searchValue?: string) => {
  switch (filter) {
    case 'Active':
      return courses.filter(
        ({ isActive, name }) => isActive && (searchValue ? name.includes(searchValue) : true)
      );
    case 'Terminated':
      return courses.filter(
        ({ isActive, name }) => !isActive && (searchValue ? name.includes(searchValue) : true)
      );
    case 'All':
    default:
      return searchValue ? courses.filter(({ name }) => name.includes(searchValue)) : courses;
  }
};

export const AdminPageWrapper: FC = () => {
  const { t } = useTranslation();
  const { loading, courses, error } = useCoursesQuery();
  const [currentShowCoursesOption, setCurrentShowCoursesOption] = useState(
    SHOW_COURSES_OPTIONS[0].name
  );
  const [searchValue, setSearchValue] = useState('');

  const checkIsCourseNameUniq = (courseName: string) => {
    return !courses.find(({ name }: Course) => name === courseName);
  };

  const filteredCourseList = useMemo(
    () => filterCourseList(courses, currentShowCoursesOption, searchValue),
    [courses, currentShowCoursesOption, searchValue]
  );

  if (error) return <ErrorModal error={error} />;
  if (loading) return <Loader />;

  return (
    <AdminPageContentWrapper>
      <HeaderDecor />
      <AddCourseBlock checkIsCourseNameUniq={checkIsCourseNameUniq} />
      <ListTitle>{t('Courses list')}</ListTitle>
      <CourseListSettings>
        <ShowCourseSelect
          currentOption={currentShowCoursesOption}
          setCurrentOption={setCurrentShowCoursesOption}
        />
        <ModalInput
          name="inputValue"
          required
          value={searchValue}
          mt="0px"
          autoComplete={'off'}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
            setSearchValue(e.target.value.trimLeft())
          }
          placeholder={t('Search course')}
        />
      </CourseListSettings>
      <CoursesList courses={filteredCourseList} checkIsCourseNameUniq={checkIsCourseNameUniq} />
    </AdminPageContentWrapper>
  );
};


================================================
FILE: src/modules/AdminPage/components/ContentWrapper/styled.ts
================================================
import { DARK_TEXT_COLOR, WHITE_COLOR } from 'appConstants/colors';
import styled from 'styled-components';
import { H2AdaptiveFont } from 'typography';

export const AdminPageContentWrapper = styled.div`
  position: relative;
  z-index: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1320px;
  min-height: 75vh;
  padding: 20px 0;
  background-color: ${WHITE_COLOR};
  border-radius: 20px;
`;

export const ListTitle = styled.h4`
  ${H2AdaptiveFont}
  font-size: 25px;
  color: ${DARK_TEXT_COLOR};
  text-align: center;
`;

export const CourseListSettings = styled.div`
  position: relative;
  display: flex;
  justify-content: flex-end;
  padding: 10px 5% 30px;

  @media (max-width: 1100px) {
    justify-content: flex-start;
    padding: 10px 9% 80px;
  }
  @media (max-width: 768px) {
    padding: 10px 10% 80px;
  }
`;


================================================
FILE: src/modules/AdminPage/components/index.ts
================================================
export { AdminPageWrapper } from './ContentWrapper';


================================================
FILE: src/modules/AdminPage/index.tsx
================================================
import React, { FC } from 'react';
import { TeamsTitleWrapper } from 'modules/TeamsList/styled';
import { useTranslation } from 'react-i18next';
import { ContentPageWrapper } from 'typography';
import { StudentTableWrapper, TableTitle } from 'modules/StudentsTable/styled';
import { AdminPageWrapper } from './components';

export const AdminPage: FC = () => {
  const { t } = useTranslation();

  return (
    <ContentPageWrapper>
      <StudentTableWrapper>
        <TeamsTitleWrapper>
          <TableTitle>{t('Admin page')}</TableTitle>
        </TeamsTitleWrapper>
        <AdminPageWrapper />
      </StudentTableWrapper>
    </ContentPageWrapper>
  );
};


================================================
FILE: src/modules/EditProfile/components/UserCourseListItem/index.tsx
================================================
import React, { FC } from 'react';
import { useSelector } from 'react-redux';
import { MinusButton, UserCourseListItemStyled } from './styled';
import { Course, Team } from 'types';
import { ReactComponent as CrossSvgIcon } from 'assets/svg/cross.svg';
import { selectUserData } from 'modules/StudentsTable/selectors';
import { useRemoveUserFromCourseMutation } from 'hooks/graphql';

type TUserCourseListItem = {
  isUserRegisteredCourse: boolean;
  onSub: (c: IOldCourses) => void;
  course: Course;
};

export interface IOldCourses extends Course {
  isNew: boolean;
}

export const UserCourseListItem: FC<TUserCourseListItem> = ({
  children,
  isUserRegisteredCourse,
  onSub,
  course,
}) => {
  const userData = useSelector(selectUserData);

  const { removeUserFromCourse } = useRemoveUserFromCourseMutation({
    data: {
      courseId: course.id,
      userId: userData.id,
      teamId: userData.teams.find((team: Team) => team.courseId === course.id)?.id ?? null,
      page: 0,
    },
  });
  const onClickHandler = isUserRegisteredCourse
    ? () => {
        onSub({ ...course, isNew: false });
        removeUserFromCourse();
      }
    : () => {
        onSub({ ...course, isNew: true });
      };

  return (
    <UserCourseListItemStyled>
      <div>{children}</div>
      <MinusButton type="button" active={false} onClick={onClickHandler}>
        <CrossSvgIcon />
      </MinusButton>
    </UserCourseListItemStyled>
  );
};


================================================
FILE: src/modules/EditProfile/components/UserCourseListItem/styled.ts
================================================
import styled from 'styled-components';
import { BG_COLOR, DARK_TEXT_COLOR } from 'appConstants/colors';
import { PlusButton } from 'components/CourseField/styled';
import { GeneralAdaptiveFont } from 'typography';

export const UserCourseListItemStyled = styled.div`
  display: flex;

  div {
    flex-grow: 1;
    padding: 8px 15px;
    margin-bottom: 20px;
    border-radius: 10px;
    background-color: ${BG_COLOR};
    color: ${DARK_TEXT_COLOR};
    ${GeneralAdaptiveFont}
  }
`;

export const MinusButton = styled(PlusButton)`
  background-image: none;
  display: flex;
  align-items: center;
  justify-content: center;
`;


================================================
FILE: src/modules/EditProfile/formFields.ts
================================================
import { INPUT_VALUES_EDIT_PROFILE } from 'appConstants';
import { Course } from 'types';
import { InputFieldProps } from '../../components/InputField';

export const formFields: InputFieldProps[] = [
  {
    name: 'firstName',
    labelText: 'First Name',
    placeholder: 'Enter first name',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z]+$/i,
        message: 'This input is letters only.',
      },
      minLength: {
        value: 2,
        message: 'Minimal length is 2.',
      },
      maxLength: {
        value: 15,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'lastName',
    labelText: 'Last Name',
    placeholder: 'Enter last name',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z]+$/i,
        message: 'This input is letters only.',
      },
      minLength: {
        value: 2,
        message: 'Minimal length is 2.',
      },
      maxLength: {
        value: 20,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'discord',
    labelText: 'Discord',
    placeholder: 'Enter discord',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z0-9@#-_() ]+$/i,
        message: 'This input is letters and digits only.',
      },
      minLength: {
        value: 3,
        message: 'Minimal length is 3.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'telegram',
    labelText: 'Telegram',
    placeholder: 'Enter telegram',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z0-9-_ ]+$/i,
        message: 'This input is letters and digits only.',
      },
      minLength: {
        value: 3,
        message: 'Minimal length is 3.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'city',
    labelText: 'City',
    placeholder: 'Enter city',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z\- ]+$/i,
        message: 'This input is letters only.',
      },
      minLength: {
        value: 2,
        message: 'Minimal length is 2.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'country',
    labelText: 'Country',
    placeholder: 'Enter country',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[A-Za-z\- ]+$/i,
        message: 'This input is letters only.',
      },
      minLength: {
        value: 2,
        message: 'Minimal length is 2.',
      },
      maxLength: {
        value: 30,
        message: 'This input exceed maxLength.',
      },
    },
  },
  {
    name: 'score',
    labelText: 'Score',
    placeholder: 'Enter score',
    register: {
      required: 'This is required.',
      pattern: {
        value: /^[1-9]+\d*$/i,
        message: 'This input is number only.',
      },
      minLength: {
        value: 1,
        message: 'Minimal length is 1.',
      },
      maxLength: {
        value: 5,
        message: 'This input exceed maxLength.',
      },
    },
  },
];

export const checkIsCoursesEqual = (newCourses: Course[], userCourses: Course[]) => {
  return (
    JSON.stringify(newCourses.map((newCourse) => newCourse.name).sort()) ===
    JSON.stringify(userCourses.map((userCourse) => userCourse.name).sort())
  );
};

export const checkIsFormFieldsEqual = (inputValues: any, userData: any) => {
  let isEqual = true;
  INPUT_VALUES_EDIT_PROFILE.forEach((item: string) => {
    if (inputValues[item] !== userData[item]) {
      isEqual = false;
    }
  });
  return isEqual;
};


================================================
FILE: src/modules/EditProfile/index.tsx
================================================
import React, { FC, useEffect, useMemo, useState } from 'react';
import { Redirect, useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { FieldError, useForm } from 'react-hook-form';
import { Loader, InputField, CourseField, ErrorModal, ModalExpel } from 'components';
import { useCoursesQuery, useUpdUserMutation } from 'hooks/graphql';
import { Button, AdditionalWrapper } from 'typography';
import { selectUserData } from 'modules/StudentsTable/selectors';
import { selectIsCommonError, selectPathToThePage, selectToken } from 'modules/LoginPage/selectors';
import { Course, UpdateUserInput, User } from 'types';
import { checkIsCoursesEqual, formFields, checkIsFormFieldsEqual } from './formFields';
import {
  EditProfileWrapper,
  InputsWrapper,
  ButtonWrapper,
  FormWrapper,
  UserCoursesListTitle,
  FormTitle,
  CoursesWrapper,
  CommonWrapper,
} from './styled';
import { BG_COLOR, MAIN1_COLOR } from 'appConstants/colors';
import { INPUT_VALUES_EDIT_PROFILE } from 'appConstants';
import { IOldCourses, UserCourseListItem } from './components/UserCourseListItem';
import { useTranslation } from 'react-i18next';
import { setUserData } from 'modules/StudentsTable/studentsTableReducer';
import { setCourse } from 'modules/LoginPage/loginPageMiddleware';
import { setEditProfileDataChange } from 'modules/LoginPage/loginPageReducer';
import { activeModalLeavePage } from 'modules/TeamsList/teamsListReducer';
import { selectIsActiveModalLeavePage } from 'modules/TeamsList/selectors';

export const EditProfile: FC = () => {
  const history = useHistory();
  const loginToken = useSelector(selectToken);
  const userData = useSelector(selectUserData);
  const isCommonError = useSelector(selectIsCommonError);
  const { t } = useTranslation();
  const isActiveModalLeavePage = useSelector(selectIsActiveModalLeavePage);
  const pathToThePage = useSelector(selectPathToThePage);

  const oldCourses: IOldCourses[] = userData.courses.map((course: Course) => ({
    ...course,
    isNew: true,
  }));

  const [userCourses, setUserCourses] = useState<IOldCourses[]>(oldCourses);
  const { loading, courses, error } = useCoursesQuery();
  const defaultData = useMemo(
    () => ({
      id: userData.id,
      firstName: userData.firstName || '',
      lastName: userData.lastName || '',
      discord: userData.discord || '',
      telegram: userData.telegram || '',
      city: userData.city || '',
      country: userData.country || '',
      courseIds: [],
      score: userData.score || 9999,
    }),
    [userData]
  );
  const [inputValues, setInputValues] = useState<UpdateUserInput>(defaultData);

  const { updateUser, loadingM, errorM } = useUpdUserMutation({
    user: {
      ...inputValues,
      courseIds: userCourses.map(({ id }: Course) => id),
    },
  });

  const [isValidCoursesList, setValidCoursesList] = useState(true);

  const dispatch = useDispatch();

  const isUserNew = !!userData.courses.length;

  const currentCourses = courses?.filter(
    ({ isActive, name }: Course) =>
      isActive && !userCourses.find((uItem: Course) => uItem.name === name)
  );

  const { register, handleSubmit, errors, reset } = useForm<UpdateUserInput>({
    defaultValues: inputValues,
    mode: 'onChange',
  });

  const changeInputValue = (e: React.ChangeEvent<HTMLInputElement>): void => {
    const { name, value } = e.target;
    setInputValues({
      ...inputValues,
      [name]: value.trim(),
    });
    dispatch(
      setEditProfileDataChange(
        !checkIsFormFieldsEqual(
          {
            ...inputValues,
            [name]: value.trim(),
          },
          userData
        )
      )
    );
  };

  const onSubmit = () => {
    if (userCourses.length) {
      updateUser().then(({ data: { updateUser } }) => {
        const newCurrentCourse =
          updateUser.courses.find(
            (course: Course) => course.id === userCourses[userCourses.length - 1].id
          ) ?? updateUser.courses[0];
        dispatch(setCourse(newCurrentCourse));
        dispatch(setUserData(updateUser));
        history.push('/');
      });
    } else {
      setValidCoursesList(false);
    }
    dispatch(setEditProfileDataChange(false));
  };

  const localCourseUpdate = (course: IOldCourses) => {
    if (course) {
      setUserCourses([...userCourses, course]);
      setValidCoursesList(true);
      dispatch(setEditProfileDataChange(true));
    }
  };

  const localCourseSub = (course: IOldCourses) => {
    if (course) {
      const copyCourses: IOldCourses[] = [...userCourses];

      const index = copyCourses.findIndex((item: IOldCourses) => {
        return item.id === course.id;
      });

      if (index >= 0) {
        copyCourses.splice(index, 1);
      }

      if (checkIsCoursesEqual(copyCourses, userData.courses)) {
        dispatch(setEditProfileDataChange(false));
      }

      setUserCourses([...copyCourses]);
      setValidCoursesList(true);
    }
  };

  const onSubmitLeavePage = () => {
    history.push(pathToThePage);
    dispatch(setEditProfileDataChange(false));
  };

  useEffect(() => {
    if (userData.id !== '' && !inputValues.id) {
      setInputValues(defaultData);
      setUserCourses(oldCourses);
      reset(defaultData);
      dispatch(setEditProfileDataChange(false));
    }
  }, [reset, inputValues, defaultData, userData, oldCourses, dispatch]);

  if (!loginToken) return <Redirect to={'/login'} />;
  if (error || errorM || isCommonError) return <ErrorModal error={error || errorM} />;
  if (loading || loadingM) return <Loader />;

  return (
    <FormWrapper>
      <CommonWrapper>
        <EditProfileWrapper autoComplete="off" onSubmit={handleSubmit(onSubmit)}>
          <FormTitle>{t('Enter your profile information')}</FormTitle>
          <InputsWrapper>
            {formFields.map((item, index) => {
              return (
                <InputField
                  key={JSON.stringify(item)}
                  name={item.name}
                  value={userData[INPUT_VALUES_EDIT_PROFILE[index] as keyof User] as string}
                  labelText={item.labelText}
                  placeholder={item.placeholder}
                  aria-invalid={
                    (errors[
                      INPUT_VALUES_EDIT_PROFILE[index] as keyof UpdateUserInput
                    ] as FieldError)
                      ? 'true'
                      : 'false'
                  }
                  message={
                    (
                      errors[
                        INPUT_VALUES_EDIT_PROFILE[index] as keyof UpdateUserInput
                      ] as FieldError
                    )?.message
                  }
                  onChange={changeInputValue}
                  register={register(item.register)}
                />
              );
            })}
            <CoursesWrapper>
              <UserCoursesListTitle>{t('Course')}</UserCoursesListTitle>
              {userCourses.map((item: IOldCourses) => {
                return (
                  <UserCourseListItem
                    key={item.id}
                    isUserRegisteredCourse={item.isNew}
                    course={item}
                    onSub={localCourseSub}
                  >
                    {item.name}
                  </UserCourseListItem>
                );
              })}
              {currentCourses.length !== 0 && (
                <CourseField
                  name="courses"
                  placeholder={t('Select course')}
                  register={register}
                  multi
                  onAdd={localCourseUpdate}
                  courses={currentCourses}
                  isValid={isValidCoursesList}
                />
              )}
              {userCourses.length === 0 && currentCourses.length === 0 && (
                <span>No courses available, try again later</span>
              )}
            </CoursesWrapper>
          </InputsWrapper>
          <ButtonWrapper>
            {isUserNew && (
              <Button
                type="button"
                bgc={BG_COLOR}
                color={MAIN1_COLOR}
                mr="20px"
                onClick={history.goBack}
              >
                {t('Cancel')}
              </Button>
            )}
            <Button>{isUserNew ? t('Submit') : t('Save')}</Button>
          </ButtonWrapper>
        </EditProfileWrapper>
        <AdditionalWrapper />
      </CommonWrapper>
      <ModalExpel
        title="Data is unsaved"
        text="Are you sure want to leave page without saving data"
        open={isActiveModalLeavePage}
        onSubmit={onSubmitLeavePage}
        isCrossIconVisible={false}
        onClose={() => dispatch(activeModalLeavePage(false))}
        okText="Yes"
        cancelText="No"
      />
    </FormWrapper>
  );
};


================================================
FILE: src/modules/EditProfile/styled.ts
================================================
import styled from 'styled-components';
import { BG_COLOR, DARK_TEXT_COLOR, LIGHT_TEXT_COLOR, WHITE_COLOR } from 'appConstants/colors';
import {
  PageTitle,
  H1AdaptiveFont,
  GeneralAdaptiveFont,
  ScrollBar,
  MainComponentHeight,
} from 'typography';

export const EditProfileWrapper = styled.form`
  background-color: ${WHITE_COLOR};
  width: 680px;
  padding: 30px;
  border-radius: 20px;
  margin: 75px 0 15px;
  @media screen and (max-width: 768px) {
    width: 320px;
    padding: 15px 10px;
    flex-direction: column;
    margin: 50px 0 30px;
  }

  @media (max-width: 440px) {
    width: 280px;
  }
`;

export const FormWrapper = styled.div`
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  overflow-y: scroll;
  ${ScrollBar};
  ${MainComponentHeight};
`;

export const FormTitle = styled(PageTitle)`
  margin-top: 0;
  margin-bottom: 32px;
  ${H1AdaptiveFont};
`;

export const InputsWrapper = styled.div`
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  flex-wrap: wrap;
  margin-bottom: 10px;
  @media screen and (max-width: 768px) {
    flex-direction: column;
  }
`;

export const ButtonWrapper = styled.div`
  display: flex;
  justify-content: flex-end;
`;

export const CoursesWrapper = styled.div`
  max-width: 300px;
  width: 100%;
`;
export const UserCoursesListTitle = styled.div`
  color: ${LIGHT_TEXT_COLOR};
  margin-bottom: 10px;
  ${GeneralAdaptiveFont}
`;

export const UserCourseListItem = styled.div`
  padding: 8px 15px;
  margin-bottom: 20px;
  border-radius: 10px;
  background-color: ${BG_COLOR};
  color: ${DARK_TEXT_COLOR};
`;

export const CommonWrapper = styled.div`
  position: absolute;
  top: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
`;


================================================
FILE: src/modules/LoginPage/components/LoginInfoBlock/index.tsx
================================================
import React, { FC } from 'react';
import {
  StyledLoginInfoBlock,
  StyledLoginTitle,
  StyledLoginRegistrationLink,
  StyledLoginTextWrapper,
} from './styled';
import { AUTH_BACKEND_LINK } from 'appConstants';
import { useTranslation } from 'react-i18next';

export const LoginInfoBlock: FC = () => {
  const { t } = useTranslation();
  return (
    <StyledLoginInfoBlock>
      <StyledLoginTitle>{t('Sign in')}</StyledLoginTitle>
      <StyledLoginRegistrationLink href={AUTH_BACKEND_LINK}>
        {t('Sign in with Github')}
      </StyledLoginRegistrationLink>
      <StyledLoginTextWrapper>
        <p>{t('Don’t have github account?')}</p>
        <a href={AUTH_BACKEND_LINK}>{t('Sign up')}</a>
      </StyledLoginTextWrapper>
    </StyledLoginInfoBlock>
  );
};


================================================
FILE: src/modules/LoginPage/components/LoginInfoBlock/styled.ts
================================================
import styled from 'styled-components';
import { WHITE_COLOR, DARK_TEXT_COLOR, MAIN1_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont, GeneralButtonPadding, H1AdaptiveFont } from 'typography';

export const StyledLoginInfoBlock = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin-left: 12%;
  padding: 20px;
  font-size: 1rem;
  color: ${DARK_TEXT_COLOR};
  background-color: ${WHITE_COLOR};
  border-radius: 20px;
  gap: 30px;
  ${GeneralAdaptiveFont};

  @media (max-width: 992px) {
    margin: 0 auto;
  }
  @media (max-width: 768px) {
    padding: 20px 15px;
    gap: 25px;
  }
  @media (max-width: 550px) {
    gap: 20px;
  }
  @media (max-width: 440px) {
    gap: 15px;
  }
`;

export const StyledLoginTitle = styled.h2`
  margin: 0;
  font-weight: 600;
  ${H1AdaptiveFont};
`;

export const StyledLoginRegistrationLink = styled.a`
  display: inline-block;
  margin-top: 10px;
  text-align: center;
  color: ${WHITE_COLOR};
  text-decoration: none;
  background-color: ${MAIN1_COLOR};
  border-radius: 20px;
  ${GeneralButtonPadding}
`;

export const StyledLoginTextWrapper = styled.div`
  display: flex;
  font-weight: normal;
  line-height: 150%;
  gap: 10px;

  p {
    margin: 0;
  }

  a {
    font-weight: 500;
    color: ${MAIN1_COLOR};
    text-decoration: none;
  }
`;


================================================
FILE: src/modules/LoginPage/components/index.ts
================================================
export { LoginInfoBlock } from './LoginInfoBlock';


================================================
FILE: src/modules/LoginPage/index.tsx
================================================
import React, { FC } from 'react';
import { useSelector } from 'react-redux';
import { Redirect } from 'react-router-dom';
import { selectToken } from './selectors';
import { StyledLoginImage, StyledLoginPage, StyledLoginPageItemsWrapper } from './styled';
import { LoginInfoBlock } from './components';

export const LoginPage: FC = () => {
  const loginToken = useSelector(selectToken);

  if (loginToken) return <Redirect to="/" />;

  return (
    <StyledLoginPage>
      <StyledLoginPageItemsWrapper>
        <LoginInfoBlock />
      </StyledLoginPageItemsWrapper>
      <StyledLoginImage />
    </StyledLoginPage>
  );
};


================================================
FILE: src/modules/LoginPage/loginPageMiddleware.ts
================================================
import { CURRENT_LANG, CURRENT_COURSE, TOUR_OPENING } from 'appConstants';
import { Course } from 'types';
import { setCurrCourse, setCurrLang } from './loginPageReducer';

export const setLanguage = (currentLanguage: string) => {
  return (dispatch: (actionCreator: any) => void) => {
    localStorage.setItem(CURRENT_LANG, currentLanguage);
    dispatch(setCurrLang(currentLanguage));
  };
};

export const setCourse = (currentCourse: Course) => {
  return (dispatch: (actionCreator: any) => void) => {
    localStorage.setItem(CURRENT_COURSE, JSON.stringify(currentCourse));
    dispatch(setCurrCourse(currentCourse));
  };
};

export const setTourOpening = (tourOpening: string) => {
  return () => {
    localStorage.setItem(TOUR_OPENING, tourOpening);
  };
};


================================================
FILE: src/modules/LoginPage/loginPageReducer.ts
================================================
import {
  DEFAULT_LANGUAGE,
  SET_COMMON_ERROR,
  SET_CURR_COURSE,
  SET_CURR_LANG,
  SET_TOKEN,
  SET_BURGER_MENU_OPEN,
  SET_EDIT_PROFILE_DATA_CHANGE,
  SET_PATH_TO_THE_PAGE,
  SET_IS_TOUR_OPEN,
} from 'appConstants';
import { createActions, handleActions } from 'redux-actions';
import { StateLoginPage } from 'types';

export const loginPageState = {
  loginToken: null,
  currCourse: {
    id: '',
    name: '',
    teamSize: null,
    isActive: true,
  },
  currLanguage: DEFAULT_LANGUAGE,
  isCommonError: false,
  isBurgerMenuOpen: false,
  isEditProfileDataChange: false,
  pathToThePage: '',
  isTourOpen: false,
};

export const {
  setToken,
  setCurrCourse,
  setCurrLang,
  setCommonError,
  setBurgerMenuOpen,
  setEditProfileDataChange,
  setPathToThePage,
  setIsTourOpen,
} = createActions({
  SET_TOKEN: (loginToken) => ({ loginToken }),
  SET_CURR_COURSE: (currCourse) => ({ currCourse }),
  SET_CURR_LANG: (currLanguage) => ({ currLanguage }),
  SET_COMMON_ERROR: (isCommonError) => ({ isCommonError }),
  SET_BURGER_MENU_OPEN: (isBurgerMenuOpen) => ({ isBurgerMenuOpen }),
  SET_EDIT_PROFILE_DATA_CHANGE: (isEditProfileDataChange) => ({
    isEditProfileDataChange,
  }),
  SET_PATH_TO_THE_PAGE: (pathToThePage) => ({
    pathToThePage,
  }),
  SET_IS_TOUR_OPEN: (isTourOpen) => ({
    isTourOpen,
  }),
});

export const loginPageReducer = handleActions<StateLoginPage, any>(
  {
    [SET_TOKEN]: (state, { payload: { loginToken } }) => ({
      ...state,
      loginToken,
    }),
    [SET_CURR_COURSE]: (state, { payload: { currCourse } }) => ({
      ...state,
      currCourse,
    }),
    [SET_CURR_LANG]: (state, { payload: { currLanguage } }) => ({
      ...state,
      currLanguage,
    }),
    [SET_COMMON_ERROR]: (state, { payload: { isCommonError } }) => ({
      ...state,
      isCommonError,
    }),
    [SET_BURGER_MENU_OPEN]: (state, { payload: { isBurgerMenuOpen } }) => ({
      ...state,
      isBurgerMenuOpen,
    }),
    [SET_EDIT_PROFILE_DATA_CHANGE]: (state, { payload: { isEditProfileDataChange } }) => ({
      ...state,
      isEditProfileDataChange,
    }),
    [SET_PATH_TO_THE_PAGE]: (state, { payload: { pathToThePage } }) => ({
      ...state,
      pathToThePage,
    }),
    [SET_IS_TOUR_OPEN]: (state, { payload: { isTourOpen } }) => ({
      ...state,
      isTourOpen,
    }),
  },
  loginPageState
);


================================================
FILE: src/modules/LoginPage/selectors.ts
================================================
import { State } from 'types';

export const selectToken = (state: State) => state.loginPageReducer.loginToken;

export const selectCurrCourse = (state: State) => state.loginPageReducer.currCourse;

export const selectCurrLanguage = (state: State) => state.loginPageReducer.currLanguage;

export const selectIsCommonError = (state: State) => state.loginPageReducer.isCommonError;

export const selectIsBurgerMenuOpen = (state: State) => state.loginPageReducer.isBurgerMenuOpen;

export const selectIsEditProfileDataChange = (state: State) =>
  state.loginPageReducer.isEditProfileDataChange;

export const selectPathToThePage = (state: State) => state.loginPageReducer.pathToThePage;

export const selectIsTourOpen = (state: State) => state.loginPageReducer.isTourOpen;


================================================
FILE: src/modules/LoginPage/styled.ts
================================================
import styled from 'styled-components';
import { MAIN1_COLOR, WHITE_COLOR } from 'appConstants/colors';
import { ReactComponent as LoginImage } from 'assets/svg/loginImage.svg';

export const StyledLoginPage = styled.div`
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100vh;
  margin: 0 auto;
  background: linear-gradient(90deg, ${WHITE_COLOR} 75%, ${MAIN1_COLOR} 75%);
`;

export const StyledLoginPageItemsWrapper = styled.div`
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: 1440px;
  height: 100%;
  overflow: hidden;
`;

export const StyledLoginImage = styled(LoginImage)`
  position: absolute;
  top: 0;
  right: 0;
  z-index: -1;
  width: auto;
  height: 100%;

  @media (max-width: 991px) {
    left: 50%;
    transform: translate(-50%, 0%);
  }
`;


================================================
FILE: src/modules/NotFoundPage/index.tsx
================================================
import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { ContentPageWrapper, PageTitle } from 'typography';
import { NotFoundPageWrapper } from './styled';

export const NotFoundPage: FC = () => {
  const { t } = useTranslation();
  return (
    <ContentPageWrapper>
      <NotFoundPageWrapper>
        <PageTitle>{t('Not found!')}</PageTitle>
      </NotFoundPageWrapper>
    </ContentPageWrapper>
  );
};


================================================
FILE: src/modules/NotFoundPage/styled.ts
================================================
import styled from 'styled-components';

export const NotFoundPageWrapper = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
`;


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/index.tsx
================================================
import React, { FC, MouseEvent, useState } from 'react';
import { TablePopup } from 'components/TablePopup';
import { StyledTableItem } from './styled';

type TableItemProps = {
  item: string;
  index: number;
  dataLength: number;
};

export const TableItem: FC<TableItemProps> = ({ item, index, dataLength }) => {
  const [tableItemCursor, setTableItemCursor] = useState(false);
  const [showPopup, setShowPopup] = useState(false);
  const [popupElements, setPopupElements] = useState<string[]>([]);

  const mouseOverHandler = (event: MouseEvent<HTMLElement>) => {
    const target = event.target as HTMLDivElement;
    if (target.scrollWidth !== target.clientWidth) {
      setShowPopup(true);
      setPopupElements(target?.textContent?.split(',') as string[]);
      setTableItemCursor(true);
    }
  };

  const mouseLeaveHandler = () => {
    setShowPopup(false);
    setPopupElements([]);
    setTableItemCursor(false);
  };

  return (
    <StyledTableItem
      className={`TableItem--${index}`}
      onMouseOver={mouseOverHandler}
      onMouseOut={mouseLeaveHandler}
      tableItemCursor={tableItemCursor}
    >
      <div className={`TableItem__first-element`}>{item}</div>
      {showPopup && <TablePopup {...{ popupElements, dataLength }} />}
    </StyledTableItem>
  );
};


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/styled.ts
================================================
import styled from 'styled-components';

type TStyledTableItem = {
  tableItemCursor: boolean;
};

export const StyledTableItem = styled.div<TStyledTableItem>`
  position: relative;
  max-width: 140px;
  cursor: ${({ tableItemCursor }) => (tableItemCursor ? 'pointer' : 'unset')};
  .TableItem__first-element {
    width: 100%;
    margin: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
`;


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/index.tsx
================================================
import React, { FC } from 'react';
import { ListChildComponentProps } from 'react-window';
import { TableItem } from './components/TableItem';
import { StyledTableRow } from './styled';

export const TableRow: FC<ListChildComponentProps> = ({ data, index, style }) => {
  const optimalItemIndexCount = 2;
  return (
    <StyledTableRow style={style}>
      {data[index].map((item: string, ind: number) => (
        <TableItem
          item={item}
          index={ind}
          dataLength={index > optimalItemIndexCount ? index / (data.length - 1) : 0}
          key={`TableItemKey-${ind}`}
        />
      ))}
    </StyledTableRow>
  );
};


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/styled.ts
================================================
import { BG_COLOR, DARK_TEXT_COLOR } from 'appConstants/colors';
import styled from 'styled-components';

export const StyledTableRow = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px;
  font-weight: 400;
  line-height: 150%;
  color: ${DARK_TEXT_COLOR};
  border-radius: 10px;
  &:nth-child(2n) {
    background-color: ${BG_COLOR};
  }

  @media (max-width: 768px) {
    padding: 10px;
  }
  @media (max-width: 440px) {
    padding: 5px;
  }
`;


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/index.tsx
================================================
import React, { FC, useMemo, ReactText } from 'react';
import { useSelector } from 'react-redux';
import { FixedSizeList as List } from 'react-window';
import AutoSizer from 'react-virtualized-auto-sizer';
import { StyledTableBody } from './styled';
import './styles.css';
import { User, Course, Team } from 'types';
import { USERS_PER_PAGE } from 'appConstants';
import { TableRow } from './components/TableRow';
import { selectCurrCourse } from 'modules/LoginPage/selectors';
import { useTranslation } from 'react-i18next';

type TableBodyProps = {
  users: User[];
  page: number;
};

export const TableBody: FC<TableBodyProps> = ({ users, page }) => {
  const currCourse = useSelector(selectCurrCourse);
  const { t } = useTranslation();

  const usersData: Array<string[] | ReactText[]> = useMemo(
    () =>
      users.map((user: User, index: number) => {
        return [
          `${index + 1 + page * USERS_PER_PAGE}`,
          `${user.firstName} ${user.lastName || null}`,
          `${user.score}`,
          user.teams.find((team: Team) => team.courseId === currCourse.id)
            ? `${user.teams.find((team: Team) => team.courseId === currCourse.id)?.number}`
            : (t('No team yet.') as string),
          user.telegram || `${t('No')} telegram.`,
          user.discord || `${t('No')} discord.`,
          user.github || `${t('No')} GitHub.`,
          `${user.country},
          ${user.city}`,
          user.courses.length
            ? user.courses.map((course: Course) => course.name).join(', ')
            : (t('No courses.') as string),
        ];
      }),
    [users, page, currCourse.id, t]
  );

  return (
    <StyledTableBody>
      <AutoSizer>
        {({ height, width }) => (
          <List
            className="List"
            height={height}
            itemSize={64}
            itemCount={usersData.length}
            itemData={usersData}
            width={width}
          >
            {TableRow}
          </List>
        )}
      </AutoSizer>
    </StyledTableBody>
  );
};


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/styled.ts
================================================
import styled from 'styled-components';

export const StyledTableBody = styled.div`
  display: flex;
  width: 100%;
  height: 100%;
`;


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/styles.css
================================================
.List {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow-y: scroll !important;
}

.List::-webkit-scrollbar {
  width: 10px;
  background-color: var(--WHITE_COLOR);
}

.List::-webkit-scrollbar-thumb {
  background-color: var(--SCROLL_THUMB_COLOR);
  border-radius: 20px;
}

.TableItem--0 {
  width: 3.5%;
}

.TableItem--1 {
  width: 16%;
}

.TableItem--2 {
  width: 5%;
}

.TableItem--3 {
  width: 14%;
}

.TableItem--4,
.TableItem--5,
.TableItem--6 {
  width: 9.93%;
}

.TableItem--7, .TableItem--8 {
  width: 14%;
}

.TableItem--9 {
  width: 11%;
}

@media (max-width: 1320px) {
  .TableItem--0 {
    width: 4%;
  }

  .TableItem--1 {
    width: 16%;
  }

  .TableItem--2 {
    width: 6%;
  }

  .TableItem--3 {
    width: 14%;
  }

  .TableItem--8 {
    width: 15%;
  }
}

@media (max-width: 1200px) {
  .TableRow {
    font-size: 0.95rem;
  }

  .TableItem--0 {
    width: 4.5%;
  }

  .TableItem--1 {
    width: 18%;
  }

  .TableItem--2 {
    width: 6%;
  }

  .TableItem--3 {
    width: 15%;
  }

  .TableItem--7 {
    display: none;
  }

  .TableItem--8 {
    width: 15%;
  }
}

@media (max-width: 992px) {
  .TableRow {
    font-size: 0.9rem;
  }

  .TableItem--0 {
    width: 6%;
  }

  .TableItem--1 {
    width: 20.5%;
  }

  .TableItem--2 {
    width: 7%;
  }

  .TableItem--3 {
    width: 17%;
  }

  .TableItem--4 {
    width: 11%;
  }

  .TableItem--5,
  .TableItem--7 {
    display: none;
  }

  .TableItem--8 {
    width: 20%;
  }
}

@media (max-width: 768px) {
  .TableRow {
    padding: 10px;
    font-size: 0.825rem;
  }

  .TableItem--0 {
    width: 9%;
  }

  .TableItem--1 {
    width: 28%;
  }

  .TableItem--3 {
    width: 25%;
  }

  .TableItem--4 {
    width: 17.5%;
  }

  .TableItem--2,
  .TableItem--5,
  .TableItem--7,
  .TableItem--6 {
    display: none;
  }

  .TableItem--8 {
    width: 20.5%;
  }
}

@media (max-width: 550px) {
  .TableRow {
    padding: 10px;
    font-size: 0.8rem;
  }

  .TableItem--0 {
    width: 11%;
  }

  .TableItem--1 {
    width: 33%;
  }

  .TableItem--4 {
    width: 21.5%;
  }

  .TableItem--2,
  .TableItem--3,
  .TableItem--5,
  .TableItem--7,
  .TableItem--6 {
    display: none;
  }

  .TableItem--8 {
    width: 27.5%;
  }
}

@media (max-width: 440px) {
  .TableRow {
    padding: 5px;
    font-size: 0.68rem;
  }

  .TableItem--0 {
    width: 12%;
  }

  .TableItem--1 {
    width: 36%;
  }

  .TableItem--4 {
    width: 23%;
  }

  .TableItem--2,
  .TableItem--3,
  .TableItem--5,
  .TableItem--7,
  .TableItem--6 {
    display: none;
  }

  .TableItem--8 {
    width: 24.5%;
  }
}


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableHead/index.tsx
================================================
import React, { FC } from 'react';
import { TABLE_HEADERS } from 'appConstants';
import { StyledTableHead, StyledTableHeadRow, StyledTableHeader } from './styled';
import { useTranslation } from 'react-i18next';

export const TableHead: FC = () => {
  const { t } = useTranslation();
  return (
    <StyledTableHead>
      <StyledTableHeadRow>
        {TABLE_HEADERS.map((tableHeader: string, index: number) => (
          <StyledTableHeader className={`TableItem--${index}`} key={tableHeader}>
            {t(tableHeader)}
          </StyledTableHeader>
        ))}
      </StyledTableHeadRow>
    </StyledTableHead>
  );
};


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/TableHead/styled.ts
================================================
import styled from 'styled-components';
import { LIGHT_TEXT_COLOR, DASHBOARD_HEADER_BG_COLOR } from 'appConstants/colors';

export const StyledTableHead = styled.div`
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin-right: 10px;
  padding: 10px 20px;
  color: ${LIGHT_TEXT_COLOR};
  background-color: ${DASHBOARD_HEADER_BG_COLOR};
  border-radius: 10px;
  @media (max-width: 768px) {
    padding: 10px;
  }
  @media (max-width: 440px) {
    padding: 5px;
  }
`;

export const StyledTableHeadRow = styled.div`
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
`;

export const StyledTableHeader = styled.div`
  max-width: 140px;
  height: auto;
  margin: 0;
  font-weight: 600;
  line-height: 150%;
  text-align: start;
`;


================================================
FILE: src/modules/StudentsTable/components/Dashboard/components/index.ts
================================================
export { TableBody } from './TableBody';
export { TableHead } from './TableHead';


================================================
FILE: src/modules/StudentsTable/components/Dashboard/index.tsx
================================================
import React, { FC } from 'react';
import { TableBody, TableHead } from './components';
import { StyledTable } from './styled';
import { User } from 'types';

type DashboardProps = {
  users: User[];
  page: number;
};

export const Dashboard: FC<DashboardProps> = ({ users, page }) => {
  return (
    <StyledTable>
      <TableHead />
      <TableBody {...{ users, page }} />
    </StyledTable>
  );
};


================================================
FILE: src/modules/StudentsTable/components/Dashboard/styled.ts
================================================
import styled from 'styled-components';
import { WHITE_COLOR } from 'appConstants/colors';
import { GeneralAdaptiveFont } from 'typography';

export const StyledTable = styled.div`
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1320px;
  height: 75vh;
  margin: 0 auto;
  padding: 10px;
  padding-right: 0;
  font-size: 1rem;
  background-color: ${WHITE_COLOR};
  border-radius: 20px;
  ${GeneralAdaptiveFont};
`;


================================================
FILE: src/modules/StudentsTable/index.tsx
================================================
import React, { FC, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { USERS_PER_PAGE } from 'appConstants';
import { Loader, Pagination, FilterForm, ErrorModal } from 'components';
import { useUsersQuery } from 'hooks/graphql';
import { selectCurrCourse } from 'modules/LoginPage/selectors';
import { Dashboard } from './components/Dashboard';
import { StudentTableWrapper, TableTitle } from './styled';
import { TeamsTitleWrapper } from 'modules/TeamsList/styled';
import { FilterButton } from 'components/FilterForm/styled';
import filterIcon from 'assets/svg/filterIcon.svg';
import crossIcon from 'assets/svg/cross.svg';
import { WHITE_COLOR } from 'appConstants/colors';
import { defaultFilterData, filterSelectFields } from 'components/FilterForm/filterFormFields';
import { selectFilterData } from './selectors';
import { TFilterForm } from 'types';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { setFilterData } from './studentsTableReducer';
import { ContentPageWrapper } from 'typography';

export const StudentsTable: FC = () => {
  const [page, setPage] = useState<number>(0);
  const [isFilterOpen, setIsFilterOpen] = useState(false);
  const [inputValues, setInputValues] = useState<TFilterForm>(defaultFilterData);
  const { t } = useTranslation();
  const { register, handleSubmit, errors, reset } = useForm<TFilterForm>({
    defaultValues: inputValues,
    mode: 'onChange',
  });

  const dispatch = useDispatch();

  const currCourse = useSelector(selectCurrCourse);
  const filterData = useSelector(selectFilterData);

  const { loadingU, errorU, users } = useUsersQuery({
    filter: {
      ...filterData,
      sortingOrder: (
        filterSelectFields[0][1].find((item) => item[0] === filterData.sortingOrder) as string[]
      )[1],
      teamFilter: (
        filterSelectFields[1][1].find((item) => item[0] === filterData.teamFilter) as [
          string,
          boolean
        ]
      )[1],
    },
    reactCourseId: currCourse.id,
    page,
  });

  const loading = loadingU;
  const error = errorU;

  if (error) return <ErrorModal error={error} />;
  if (loading) return <Loader />;

  const pageCount: number = Math.ceil(users.count / USERS_PER_PAGE);
  const isValuesEqual =
    Object.values(defaultFilterData).toString() !== Object.values(filterData).toString();
  const onClickClearBtnHandler = () => {
    setInputValues(defaultFilterData);
    dispatch(setFilterData(defaultFilterData));
    setPage(0);
    setIsFilterOpen(false);
  };
  const onClickOpenFilterBtnHandler = () => {
    setIsFilterOpen(!isFilterOpen);
    reset(filterData);
    setInputValues(filterData);
  };

  return (
    <ContentPageWrapper>
      <StudentTableWrapper>
        <TeamsTitleWrapper>
          <TableTitle>{t('Dashboard')}</TableTitle>
          {isValuesEqual && !isFilterOpen && (
            <FilterButton clearBtn outerBtn onClick={onClickClearBtnHandler}>
              {<img src={crossIcon} alt="clear filter icon" />}
              {t('Clear filter')}
            </FilterButton>
          )}
          <FilterButton
            onClick={onClickOpenFilterBtnHandler}
            bgColor={WHITE_COLOR}
            className="seventhStep"
          >
            {<img src={filterIcon} alt="Filter icon" />} {t('Filter')}
          </FilterButton>
          {isFilterOpen && (
            <FilterForm
              {...{
                inputValues,
                setInputValues,
                setIsFilterOpen,
                setPage,
                register,
                handleSubmit,
                errors,
                reset,
              }}
            />
          )}
        </TeamsTitleWrapper>
        <Dashboard users={users.results} page={page} />
        {!!users.results.length && (
          <Pagination pageCount={pageCount} changePage={setPage} page={page} />
        )}
      </StudentTableWrapper>
    </ContentPageWrapper>
  );
};


================================================
FILE: src/modules/StudentsTable/selectors.ts
================================================
import { State } from 'types';

export const selectUserData = (state: State) => state.studentsTableReducer.userData;

export const selectFilterData = (state: State) => state.studentsTableReducer.filterData;


================================================
FILE: src/modules/StudentsTable/studentsTableReducer.ts
================================================
import { SET_USER_DATA, SET_FILTER_DATA } from 'appConstants';
import { StateStudentsTable } from 'types';
import { defaultFilterData } from 'components/FilterForm/filterFormFields';
import { createActions, handleActions } from 'redux-actions';

export const studentsTableState = {
  userData: {
    id: '',
    firstName: '',
    lastName: '',
    github: '',
    telegram: null,
    discord: '',
    score: 1000,
    country: '',
    city: '',
    avatar: '',
    isAdmin: false,
    courses: [],
    email: '',
    courseIds: [''],
    teamIds: [''],
    teams: [],
  },
  filterData: defaultFilterData,
};

export const { setUserData, setFilterData } = createActions({
  SET_USER_DATA: (userData) => ({ userData }),
  SET_FILTER_DATA: (filterData) => ({ filterData }),
});

export const studentsTableReducer = handleActions<StateStudentsTable, any>(
  {
    [SET_USER_DATA]: (state, { payload: { userData } }) => ({
      ...state,
      userData,
    }),
    [SET_FILTER_DATA]: (state, { payload: { filterData } }) => ({
      ...state,
      filterData,
    }),
  },
  studentsTableState
);


================================================
FILE: src/modules/StudentsTable/styled.ts
================================================
import styled from 'styled-components';
import { DARK_TEXT_COLOR } from 'appConstants/colors';
import { ScrollBar } from 'typography';

export const StudentTableWrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  height: fit-content;
  max-width: 1440px;
  padding: 0 4% 60px;
  overflow-y: scroll;
  ${ScrollBar};
  @media screen and (max-width: 768px) {
    padding-bottom: 50px;
  }
`;

export const TableTitle = styled.h1`
  align-self: flex-start;
  width: 80%;
  margin: 40px 0;
  font: 700 30px/45px 'Poppins', sans-serif;
  color: ${DARK_TEXT_COLOR};

  @media (max-width: 1200px) {
    font-size: 26px;
    line-height: 35px;
  }
  @media (max-width: 992px) {
    margin: 35px 0;
    font-size: 24px;
    line-height: 30px;
  }
  @media (max-width: 768px) {
    margin: 30px 0;
    font-size: 22px;
    line-height: 25px;
  }
  @media (max-width: 550px) {
    margin: 30px 0;
    font-size: 20px;
    line-height: 25px;
  }
  @media (max-width: 440px) {
    margin: 20px 0;
    font-size: 17px;
    line-height: 20px;
  }
`;


================================================
FILE: src/modules/TeamsList/components/TeamListModals/index.tsx
================================================
import React, { FC, useState } from 'react';
impor
Download .txt
gitextract_043m4_he/

├── .eslintrc.js
├── .firebaserc
├── .github/
│   └── workflows/
│       └── deploy-client.yml
├── .gitignore
├── .prettierrc
├── README.md
├── firebase.json
├── package.json
├── pre-build.js
├── public/
│   ├── index.html
│   ├── manifest.json
│   └── robots.txt
├── src/
│   ├── appConstants/
│   │   ├── api.ts
│   │   ├── colors.ts
│   │   └── index.ts
│   ├── assets/
│   │   └── fonts/
│   │       ├── Poppins-Bold-700.otf
│   │       ├── Poppins-Medium-500.otf
│   │       ├── Poppins-Regular-400.otf
│   │       └── Poppins-SemiBold-600.otf
│   ├── components/
│   │   ├── App/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── CommonSelectList/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── CourseField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── ErrorBoundary/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── ErrorModal/
│   │   │   └── index.tsx
│   │   ├── FilterForm/
│   │   │   ├── filterFormFields.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── FilterSelect/
│   │   │   └── index.tsx
│   │   ├── Footer/
│   │   │   ├── components/
│   │   │   │   ├── FooterContent/
│   │   │   │   │   └── index.tsx
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Header/
│   │   │   ├── components/
│   │   │   │   ├── BurgerMenu/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   ├── MenuWrapper/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── CoursesSelect/
│   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   ├── LangSelect/
│   │   │   │   │   │   │   └── index.tsx
│   │   │   │   │   │   └── Nav/
│   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │       └── styled.ts
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── InputField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Loader/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── Modal/
│   │   │   ├── index.module.css
│   │   │   └── index.tsx
│   │   ├── ModalCreateEditTeam/
│   │   │   └── index.tsx
│   │   ├── ModalCreated/
│   │   │   └── index.tsx
│   │   ├── ModalEditCourse/
│   │   │   └── index.tsx
│   │   ├── ModalExpel/
│   │   │   └── index.tsx
│   │   ├── ModalJoin/
│   │   │   └── index.tsx
│   │   ├── Pagination/
│   │   │   ├── index.tsx
│   │   │   └── style.css
│   │   ├── PrivateRoute/
│   │   │   └── index.tsx
│   │   ├── SelectField/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── TablePopup/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── TourGuide/
│   │   │   ├── index.tsx
│   │   │   ├── style.css
│   │   │   ├── styled.ts
│   │   │   └── tourConfig.tsx
│   │   └── index.ts
│   ├── graphql/
│   │   ├── mutations/
│   │   │   ├── addUserToTeamMutation.ts
│   │   │   ├── createCourseMutation.ts
│   │   │   ├── createTeamMutation.ts
│   │   │   ├── index.ts
│   │   │   ├── removeUserFromCourseMutation.ts
│   │   │   ├── removeUserFromTeamMutation.ts
│   │   │   ├── sortStudentsMutation.ts
│   │   │   ├── updUserMutation.ts
│   │   │   ├── updateCourseMutation.ts
│   │   │   └── updateTeamMutation.ts
│   │   └── queries/
│   │       ├── coursesQuery.ts
│   │       ├── index.ts
│   │       ├── teamsQuery.ts
│   │       ├── usersQuery.ts
│   │       └── whoAmIQuery.ts
│   ├── hooks/
│   │   └── graphql/
│   │       ├── index.ts
│   │       ├── mutations/
│   │       │   ├── useAddUserToTeamMutation.ts
│   │       │   ├── useCreateCourseMutation.ts
│   │       │   ├── useCreateTeamMutation.ts
│   │       │   ├── useExpelUserFromTeamMutation.ts
│   │       │   ├── useRemoveUserFromCourseMutation.ts
│   │       │   ├── useRemoveUserFromTeamMutation.ts
│   │       │   ├── useSortStudentsMutation.ts
│   │       │   ├── useUpdUserMutation.ts
│   │       │   ├── useUpdateCourseMutation.ts
│   │       │   └── useUpdateTeamMutation.ts
│   │       └── queries/
│   │           ├── useCoursesQuery.ts
│   │           ├── useTeamsQuery.ts
│   │           ├── useUsersQuery.ts
│   │           └── useWhoAmIQuery.ts
│   ├── index.tsx
│   ├── modules/
│   │   ├── AdminPage/
│   │   │   ├── components/
│   │   │   │   ├── ContentWrapper/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── AddCourseBlock/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── InputsBlock/
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── CoursesList/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── Course/
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   └── ShowCourseSelect/
│   │   │   │   │   │       └── index.tsx
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   └── index.tsx
│   │   ├── EditProfile/
│   │   │   ├── components/
│   │   │   │   └── UserCourseListItem/
│   │   │   │       ├── index.tsx
│   │   │   │       └── styled.ts
│   │   │   ├── formFields.ts
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── LoginPage/
│   │   │   ├── components/
│   │   │   │   ├── LoginInfoBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── loginPageMiddleware.ts
│   │   │   ├── loginPageReducer.ts
│   │   │   ├── selectors.ts
│   │   │   └── styled.ts
│   │   ├── NotFoundPage/
│   │   │   ├── index.tsx
│   │   │   └── styled.ts
│   │   ├── StudentsTable/
│   │   │   ├── components/
│   │   │   │   └── Dashboard/
│   │   │   │       ├── components/
│   │   │   │       │   ├── TableBody/
│   │   │   │       │   │   ├── components/
│   │   │   │       │   │   │   └── TableRow/
│   │   │   │       │   │   │       ├── components/
│   │   │   │       │   │   │       │   └── TableItem/
│   │   │   │       │   │   │       │       ├── index.tsx
│   │   │   │       │   │   │       │       └── styled.ts
│   │   │   │       │   │   │       ├── index.tsx
│   │   │   │       │   │   │       └── styled.ts
│   │   │   │       │   │   ├── index.tsx
│   │   │   │       │   │   ├── styled.ts
│   │   │   │       │   │   └── styles.css
│   │   │   │       │   ├── TableHead/
│   │   │   │       │   │   ├── index.tsx
│   │   │   │       │   │   └── styled.ts
│   │   │   │       │   └── index.ts
│   │   │   │       ├── index.tsx
│   │   │   │       └── styled.ts
│   │   │   ├── index.tsx
│   │   │   ├── selectors.ts
│   │   │   ├── studentsTableReducer.ts
│   │   │   └── styled.ts
│   │   ├── TeamsList/
│   │   │   ├── components/
│   │   │   │   ├── TeamListModals/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── useCommonMutations.ts
│   │   │   │   ├── Teams/
│   │   │   │   │   ├── components/
│   │   │   │   │   │   ├── MemberListToggle/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── MyTeam/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── MyTeamInfoBlock/
│   │   │   │   │   │   │   │       ├── components/
│   │   │   │   │   │   │   │       │   ├── MyTeamInfoLine/
│   │   │   │   │   │   │   │       │   │   ├── index.tsx
│   │   │   │   │   │   │   │       │   │   └── styled.tsx
│   │   │   │   │   │   │   │       │   └── NotificationPopup/
│   │   │   │   │   │   │   │       │       ├── index.tsx
│   │   │   │   │   │   │   │       │       └── styled.ts
│   │   │   │   │   │   │   │       ├── index.tsx
│   │   │   │   │   │   │   │       └── styled.ts
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   ├── TeamItem/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.tsx
│   │   │   │   │   │   ├── TeamUserTable/
│   │   │   │   │   │   │   ├── components/
│   │   │   │   │   │   │   │   └── TableRow/
│   │   │   │   │   │   │   │       ├── components/
│   │   │   │   │   │   │   │       │   ├── ExpelButton/
│   │   │   │   │   │   │   │       │   │   ├── index.tsx
│   │   │   │   │   │   │   │       │   │   └── styled.ts
│   │   │   │   │   │   │   │       │   ├── TableCell/
│   │   │   │   │   │   │   │       │   │   └── index.tsx
│   │   │   │   │   │   │   │       │   └── index.ts
│   │   │   │   │   │   │   │       └── index.tsx
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.tsx
│   │   │   │   │   │   ├── TeamsHeader/
│   │   │   │   │   │   │   ├── index.tsx
│   │   │   │   │   │   │   └── styled.ts
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   └── index.tsx
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── selectors.ts
│   │   │   ├── styled.ts
│   │   │   └── teamsListReducer.ts
│   │   ├── TokenPage/
│   │   │   └── index.tsx
│   │   ├── TutorialPage/
│   │   │   ├── components/
│   │   │   │   ├── NoteBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   ├── StepBlock/
│   │   │   │   │   ├── index.tsx
│   │   │   │   │   └── styled.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.tsx
│   │   │   ├── styled.ts
│   │   │   └── tutorialPageInfo.tsx
│   │   └── index.ts
│   ├── react-app-env.d.ts
│   ├── reportWebVitals.ts
│   ├── setupTests.ts
│   ├── store/
│   │   └── index.tsx
│   ├── translation/
│   │   ├── en/
│   │   │   └── en.json
│   │   ├── resources.ts
│   │   └── ru/
│   │       └── ru.json
│   ├── types.ts
│   ├── typography/
│   │   ├── common.css
│   │   ├── fonts.css
│   │   ├── index.ts
│   │   └── normalize.css
│   └── utils/
│       └── isFieldValid.ts
└── tsconfig.json
Download .txt
SYMBOL INDEX (193 symbols across 88 files)

FILE: pre-build.js
  constant BACKEND_LINK (line 5) | const BACKEND_LINK = `export const BACKEND_LINK = 'https://rss-teams.her...
  constant AUTH_BACKEND_LINK (line 8) | const AUTH_BACKEND_LINK = `export const AUTH_BACKEND_LINK = 'https://rss...

FILE: src/appConstants/api.ts
  constant BACKEND_LINK (line 1) | const BACKEND_LINK = 'https://rss-teams-dev.herokuapp.com/graphql';
  constant AUTH_BACKEND_LINK (line 2) | const AUTH_BACKEND_LINK = 'https://rss-teams-dev.herokuapp.com/auth/gith...

FILE: src/appConstants/colors.ts
  constant WHITE_COLOR (line 1) | const WHITE_COLOR = '#FFFFFF';
  constant BG_COLOR (line 2) | const BG_COLOR = '#F2F8FD';
  constant MAIN1_COLOR (line 3) | const MAIN1_COLOR = '#6550F6';
  constant MAIN1_DARK_COLOR (line 4) | const MAIN1_DARK_COLOR = '#5039EF';
  constant MAIN2_COLOR (line 5) | const MAIN2_COLOR = '#FA6678';
  constant MAIN2_LIGHT_COLOR (line 6) | const MAIN2_LIGHT_COLOR = '#FE7888';
  constant LIGHT_TEXT_COLOR (line 7) | const LIGHT_TEXT_COLOR = '#7E96C2';
  constant DARK_TEXT_COLOR (line 8) | const DARK_TEXT_COLOR = '#363D48';
  constant OVERLAY_COLOR (line 9) | const OVERLAY_COLOR = '#363D4866';
  constant DASHBOARD_HEADER_BG_COLOR (line 10) | const DASHBOARD_HEADER_BG_COLOR = '#E1EEFA';
  constant TABLE_SCROLLBAR_BG_COLOR (line 11) | const TABLE_SCROLLBAR_BG_COLOR = '#F9F9FD';
  constant TABLE_SCROLLBAR_THUMB_COLOR (line 12) | const TABLE_SCROLLBAR_THUMB_COLOR = '#1E33570D';
  constant TABLE_POPUP_BORDER_COLOR (line 13) | const TABLE_POPUP_BORDER_COLOR = '#363D4833';
  constant FOOTER_NAMES_COLOR (line 14) | const FOOTER_NAMES_COLOR = '#9CA5B5';
  constant ALERT_COLOR (line 16) | const ALERT_COLOR = '#FA6678';

FILE: src/appConstants/index.ts
  constant SET_USER_DATA (line 3) | const SET_USER_DATA = 'SET_USER_DATA';
  constant AUTH_TOKEN (line 4) | const AUTH_TOKEN = 'AUTH_TOKEN';
  constant SET_TOKEN (line 5) | const SET_TOKEN = 'SET_TOKEN';
  constant SET_CURR_COURSE (line 6) | const SET_CURR_COURSE = 'SET_CURR_COURSE';
  constant SET_COMMON_ERROR (line 7) | const SET_COMMON_ERROR = 'SET_COMMON_ERROR';
  constant SET_BURGER_MENU_OPEN (line 8) | const SET_BURGER_MENU_OPEN = 'SET_BURGER_MENU_OPEN';
  constant ACTIVE_MODAL_EXPEL (line 9) | const ACTIVE_MODAL_EXPEL = 'ACTIVE_MODAL_EXPEL';
  constant ACTIVE_MODAL_LEAVE (line 10) | const ACTIVE_MODAL_LEAVE = 'ACTIVE_MODAL_LEAVE';
  constant ACTIVE_MODAL_JOIN (line 11) | const ACTIVE_MODAL_JOIN = 'ACTIVE_MODAL_JOIN';
  constant ACTIVE_MODAL_CREATE_TEAM (line 12) | const ACTIVE_MODAL_CREATE_TEAM = 'ACTIVE_MODAL_CREATE_TEAM';
  constant ACTIVE_MODAL_CREATED (line 13) | const ACTIVE_MODAL_CREATED = 'ACTIVE_MODAL_CREATED';
  constant ACTIVE_MODAL_UPDATE_SOCIAL_LINK (line 14) | const ACTIVE_MODAL_UPDATE_SOCIAL_LINK = 'ACTIVE_MODAL_UPDATE_SOCIAL_LINK';
  constant ACTIVE_MODAL_REMOVE_COURSE (line 15) | const ACTIVE_MODAL_REMOVE_COURSE = 'ACTIVE_MODAL_REMOVE_COURSE';
  constant ACTIVE_MODAL_SORT_STUDENTS (line 16) | const ACTIVE_MODAL_SORT_STUDENTS = 'ACTIVE_MODAL_SORT_STUDENTS';
  constant ACTIVE_MODAL_LEAVE_PAGE (line 17) | const ACTIVE_MODAL_LEAVE_PAGE = 'ACTIVE_MODAL_LEAVE_PAGE';
  constant ACTIVE_MODAL_CREATED_COURSE (line 18) | const ACTIVE_MODAL_CREATED_COURSE = 'ACTIVE_MODAL_CREATED_COURSE';
  constant ACTIVE_MODAL_EDIT_COURSE (line 19) | const ACTIVE_MODAL_EDIT_COURSE = 'ACTIVE_MODAL_EDIT_COURSE';
  constant SET_TEAM_MEMBER_EXPEL_ID (line 20) | const SET_TEAM_MEMBER_EXPEL_ID = 'SET_TEAM_MEMBER_EXPEL_ID';
  constant SET_TEAM_PASSWORD (line 21) | const SET_TEAM_PASSWORD = 'SET_TEAM_PASSWORD';
  constant SET_SOCIAL_LINK (line 22) | const SET_SOCIAL_LINK = 'SET_SOCIAL_LINK';
  constant SET_FILTER_DATA (line 23) | const SET_FILTER_DATA = 'SET_FILTER_DATA';
  constant SET_CURR_LANG (line 24) | const SET_CURR_LANG = 'SET_CURR_LANG';
  constant SET_EDIT_PROFILE_DATA_CHANGE (line 25) | const SET_EDIT_PROFILE_DATA_CHANGE = 'SET_EDIT_PROFILE_DATA_CHANGE';
  constant SET_PATH_TO_THE_PAGE (line 26) | const SET_PATH_TO_THE_PAGE = 'SET_PATH_TO_THE_PAGE';
  constant SET_IS_TOUR_OPEN (line 27) | const SET_IS_TOUR_OPEN = 'SET_IS_TOUR_OPEN';
  constant USERS_PER_PAGE (line 29) | const USERS_PER_PAGE = 20;
  constant TEAMS_PER_PAGE (line 30) | const TEAMS_PER_PAGE = 10;
  constant CURRENT_YEAR (line 31) | const CURRENT_YEAR = new Date(Date.now()).getFullYear();
  constant CURRENT_COURSE (line 33) | const CURRENT_COURSE = 'currentCourse';
  constant CURRENT_LANG (line 34) | const CURRENT_LANG = 'currentLanguage';
  constant TOUR_OPENING (line 35) | const TOUR_OPENING = 'tourOpening';
  constant TABLE_HEADERS (line 37) | const TABLE_HEADERS = [
  constant TABLE_TEAMS_HEADERS (line 49) | const TABLE_TEAMS_HEADERS = [
  constant INPUT_VALUES_EDIT_PROFILE (line 60) | const INPUT_VALUES_EDIT_PROFILE: string[] = [
  constant MODAL_INPUT_VALIDATION (line 70) | const MODAL_INPUT_VALIDATION = {
  constant COURSE_NAME_VALIDATION (line 82) | const COURSE_NAME_VALIDATION = {
  constant TEAM_SIZE_VALIDATION (line 100) | const TEAM_SIZE_VALIDATION = {
  constant APP_NAVIGATION_LINKS (line 115) | const APP_NAVIGATION_LINKS = {
  constant DEFAULT_LANGUAGE (line 138) | const DEFAULT_LANGUAGE = 'en';
  constant LANGUAGES (line 139) | const LANGUAGES: string[] = [DEFAULT_LANGUAGE, 'ru'];
  constant FOOTER_INFO (line 146) | const FOOTER_INFO = [
  constant LINK_TO_DESIGN_BLOCK (line 157) | const LINK_TO_DESIGN_BLOCK = 'https://www.linkedin.com/in/nastya-kapylov...
  constant LINK_TO_REPO (line 159) | const LINK_TO_REPO = 'https://github.com/rolling-scopes-school/RSS-Teams...
  constant SHOW_COURSES_OPTIONS (line 166) | const SHOW_COURSES_OPTIONS = [
  constant UNAUTHORIZED_ERROR_MESSAGE (line 172) | const UNAUTHORIZED_ERROR_MESSAGE = 'Unauthorized';

FILE: src/components/CommonSelectList/index.tsx
  type CommonSelectProps (line 13) | type CommonSelectProps = {

FILE: src/components/CommonSelectList/styled.ts
  type TStyledCoursesSelectInfo (line 13) | type TStyledCoursesSelectInfo = {
  type TStyledCoursesSelectList (line 17) | type TStyledCoursesSelectList = {
  type TFooterProp (line 22) | type TFooterProp = {

FILE: src/components/CourseField/index.tsx
  type Course (line 7) | type Course = {
  type SelectFieldProps (line 12) | interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElemen...

FILE: src/components/CourseField/styled.ts
  type TPlusButton (line 5) | type TPlusButton = {

FILE: src/components/ErrorBoundary/index.tsx
  type ErrorBoundaryState (line 4) | interface ErrorBoundaryState {
  class ErrorBoundary (line 9) | class ErrorBoundary extends Component<any, ErrorBoundaryState> {
    method getDerivedStateFromError (line 12) | static getDerivedStateFromError(error: any, errorInfo: any) {
    method componentDidCatch (line 16) | componentDidCatch(error: any, errorInfo: any) {
    method handleReload (line 25) | handleReload() {
    method render (line 29) | render() {

FILE: src/components/ErrorModal/index.tsx
  type Props (line 6) | type Props = {

FILE: src/components/FilterForm/index.tsx
  type TFilter (line 16) | type TFilter = {

FILE: src/components/FilterForm/styled.ts
  type TFilerButtonProps (line 6) | type TFilerButtonProps = {

FILE: src/components/FilterSelect/index.tsx
  type SelectFieldProps (line 5) | interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElemen...

FILE: src/components/Header/components/BurgerMenu/index.tsx
  type BurgerMenuProps (line 19) | type BurgerMenuProps = {

FILE: src/components/Header/components/BurgerMenu/styled.ts
  type BurgerMenuProps (line 5) | type BurgerMenuProps = {

FILE: src/components/Header/components/MenuWrapper/components/LangSelect/index.tsx
  type LangSelectProps (line 9) | type LangSelectProps = {

FILE: src/components/Header/components/MenuWrapper/components/Nav/index.tsx
  type NavProps (line 8) | type NavProps = {

FILE: src/components/Header/components/MenuWrapper/components/Nav/styled.ts
  type TStyledNavListItemProps (line 5) | type TStyledNavListItemProps = {

FILE: src/components/Header/components/MenuWrapper/index.tsx
  type MenuWrapperProps (line 11) | type MenuWrapperProps = {

FILE: src/components/Header/styled.ts
  type TStyledHeaderProps (line 5) | type TStyledHeaderProps = {

FILE: src/components/InputField/index.tsx
  type InputFieldProps (line 5) | interface InputFieldProps extends InputHTMLAttributes<HTMLInputElement> {

FILE: src/components/Modal/index.tsx
  type ModalProps (line 10) | type ModalProps = {

FILE: src/components/ModalCreateEditTeam/index.tsx
  type Props (line 10) | type Props = {

FILE: src/components/ModalCreated/index.tsx
  type Props (line 20) | type Props = {

FILE: src/components/ModalEditCourse/index.tsx
  type Props (line 15) | type Props = {

FILE: src/components/ModalExpel/index.tsx
  type Props (line 4) | type Props = {

FILE: src/components/ModalJoin/index.tsx
  type Props (line 8) | type Props = {

FILE: src/components/Pagination/index.tsx
  type PaginationProps (line 7) | type PaginationProps = {

FILE: src/components/PrivateRoute/index.tsx
  type Props (line 4) | type Props = {

FILE: src/components/SelectField/index.tsx
  type SelectFieldProps (line 9) | interface SelectFieldProps extends SelectHTMLAttributes<HTMLSelectElemen...

FILE: src/components/TablePopup/index.tsx
  type TablePopupProps (line 4) | type TablePopupProps = {

FILE: src/components/TablePopup/styled.ts
  type TStyledPopup (line 5) | type TStyledPopup = {

FILE: src/graphql/mutations/addUserToTeamMutation.ts
  constant ADD_USER_TO_TEAM_MUTATION (line 3) | const ADD_USER_TO_TEAM_MUTATION = gql`

FILE: src/graphql/mutations/createCourseMutation.ts
  constant CREATE_COURSE_MUTATION (line 3) | const CREATE_COURSE_MUTATION = gql`

FILE: src/graphql/mutations/createTeamMutation.ts
  constant CREATE_TEAM_MUTATION (line 3) | const CREATE_TEAM_MUTATION = gql`

FILE: src/graphql/mutations/removeUserFromCourseMutation.ts
  constant REMOVE_USER_FROM_COURSE_MUTATION (line 3) | const REMOVE_USER_FROM_COURSE_MUTATION = gql`

FILE: src/graphql/mutations/removeUserFromTeamMutation.ts
  constant REMOVE_USER_FROM_TEAM_MUTATION (line 3) | const REMOVE_USER_FROM_TEAM_MUTATION = gql`

FILE: src/graphql/mutations/sortStudentsMutation.ts
  constant SORT_STUDENTS_MUTATION (line 3) | const SORT_STUDENTS_MUTATION = gql`

FILE: src/graphql/mutations/updUserMutation.ts
  constant UPD_USER_MUTATION (line 3) | const UPD_USER_MUTATION = gql`

FILE: src/graphql/mutations/updateCourseMutation.ts
  constant UPDATE_COURSE_MUTATION (line 3) | const UPDATE_COURSE_MUTATION = gql`

FILE: src/graphql/mutations/updateTeamMutation.ts
  constant UPDATE_TEAM_MUTATION (line 3) | const UPDATE_TEAM_MUTATION = gql`

FILE: src/graphql/queries/coursesQuery.ts
  constant COURSES_QUERY (line 3) | const COURSES_QUERY = gql`

FILE: src/graphql/queries/teamsQuery.ts
  constant TEAMS_QUERY (line 3) | const TEAMS_QUERY = gql`

FILE: src/graphql/queries/usersQuery.ts
  constant USERS_QUERY (line 3) | const USERS_QUERY = gql`

FILE: src/graphql/queries/whoAmIQuery.ts
  constant WHOAMI_QUERY (line 3) | const WHOAMI_QUERY = gql`

FILE: src/hooks/graphql/mutations/useAddUserToTeamMutation.ts
  type Props (line 6) | type Props = {
  method update (line 16) | update(cache, { data: { addUserToTeam } }) {

FILE: src/hooks/graphql/mutations/useCreateCourseMutation.ts
  type Props (line 6) | type Props = {
  method update (line 16) | update(cache, { data: { createCourse } }) {

FILE: src/hooks/graphql/mutations/useCreateTeamMutation.ts
  type Props (line 7) | type Props = {
  method update (line 19) | update(cache, { data: { createTeam } }) {

FILE: src/hooks/graphql/mutations/useExpelUserFromTeamMutation.ts
  type Props (line 7) | type Props = {
  method update (line 19) | update(cache, { data: {} }) {

FILE: src/hooks/graphql/mutations/useRemoveUserFromCourseMutation.ts
  type Props (line 11) | type Props = {
  method update (line 25) | update(cache, { data: { removeUserFromCourse } }) {
  method onCompleted (line 71) | onCompleted({ removeUserFromCourse }) {
  method onError (line 80) | onError() {

FILE: src/hooks/graphql/mutations/useRemoveUserFromTeamMutation.ts
  type Props (line 7) | type Props = {
  method update (line 19) | update(cache, { data: { removeUserFromTeam } }) {

FILE: src/hooks/graphql/mutations/useSortStudentsMutation.ts
  type Props (line 4) | type Props = {

FILE: src/hooks/graphql/mutations/useUpdUserMutation.ts
  type Props (line 6) | type Props = {
  method update (line 16) | update(cache, { data: { updateUser } }) {

FILE: src/hooks/graphql/mutations/useUpdateCourseMutation.ts
  type Props (line 6) | type Props = {
  method update (line 17) | update(cache, { data: { updateCourse } }) {

FILE: src/hooks/graphql/mutations/useUpdateTeamMutation.ts
  type Props (line 6) | type Props = {
  method update (line 17) | update(cache, { data: { updateTeam } }) {

FILE: src/hooks/graphql/queries/useTeamsQuery.ts
  type Props (line 5) | type Props = {

FILE: src/hooks/graphql/queries/useUsersQuery.ts
  type Props (line 7) | type Props = {

FILE: src/hooks/graphql/queries/useWhoAmIQuery.ts
  type Props (line 4) | type Props = {

FILE: src/index.tsx
  method merge (line 49) | merge(_, incoming) {
  method merge (line 54) | merge(_, incoming) {
  method merge (line 63) | merge(_, incoming) {
  method merge (line 72) | merge(_, incoming) {

FILE: src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock/index.tsx
  type InputBlockProps (line 7) | interface InputBlockProps {

FILE: src/modules/AdminPage/components/ContentWrapper/components/CoursesList/components/Course/index.tsx
  type ICourseItem (line 9) | interface ICourseItem {

FILE: src/modules/AdminPage/components/ContentWrapper/components/ShowCourseSelect/index.tsx
  type ShowCourseSelectProps (line 5) | interface ShowCourseSelectProps {

FILE: src/modules/EditProfile/components/UserCourseListItem/index.tsx
  type TUserCourseListItem (line 9) | type TUserCourseListItem = {
  type IOldCourses (line 15) | interface IOldCourses extends Course {

FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/index.tsx
  type TableItemProps (line 5) | type TableItemProps = {

FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/styled.ts
  type TStyledTableItem (line 3) | type TStyledTableItem = {

FILE: src/modules/StudentsTable/components/Dashboard/components/TableBody/index.tsx
  type TableBodyProps (line 13) | type TableBodyProps = {

FILE: src/modules/StudentsTable/components/Dashboard/index.tsx
  type DashboardProps (line 6) | type DashboardProps = {

FILE: src/modules/TeamsList/components/TeamListModals/index.tsx
  type TeamListModalsProps (line 30) | type TeamListModalsProps = {

FILE: src/modules/TeamsList/components/Teams/components/MemberListToggle/index.tsx
  type MembersListToggle (line 6) | type MembersListToggle = {

FILE: src/modules/TeamsList/components/Teams/components/MemberListToggle/styled.ts
  type ChevronProps (line 5) | type ChevronProps = {

FILE: src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/MyTeamInfoLine/index.tsx
  type MyTeamInfoLine (line 5) | type MyTeamInfoLine = {

FILE: src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/MyTeamInfoLine/styled.tsx
  type TInfoLineStyled (line 6) | type TInfoLineStyled = {

FILE: src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/index.tsx
  type MyTeamInfoBlockProps (line 11) | type MyTeamInfoBlockProps = {

FILE: src/modules/TeamsList/components/Teams/components/MyTeam/index.tsx
  type MyTeamProps (line 14) | type MyTeamProps = {

FILE: src/modules/TeamsList/components/Teams/components/MyTeam/styled.ts
  type StyledMyTeamProps (line 6) | type StyledMyTeamProps = {
  type TableWrapperProps (line 10) | type TableWrapperProps = {

FILE: src/modules/TeamsList/components/Teams/components/TeamItem/index.tsx
  type TeamItemProps (line 8) | type TeamItemProps = {

FILE: src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/ExpelButton/index.tsx
  type ExpelButtonProps (line 4) | type ExpelButtonProps = {

FILE: src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/ExpelButton/styled.ts
  type StyledExpelButtonProps (line 6) | type StyledExpelButtonProps = {

FILE: src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/TableCell/index.tsx
  type TTableCell (line 3) | type TTableCell = {

FILE: src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/index.tsx
  type TableRowProps (line 8) | type TableRowProps = {

FILE: src/modules/TeamsList/components/Teams/components/TeamUserTable/index.tsx
  type TeamUserTableProps (line 8) | type TeamUserTableProps = {

FILE: src/modules/TeamsList/components/Teams/index.tsx
  type TeamsProps (line 9) | type TeamsProps = {

FILE: src/modules/TokenPage/index.tsx
  type ParamsType (line 8) | type ParamsType = {

FILE: src/modules/TutorialPage/components/NoteBlock/index.tsx
  type NoteBlockProps (line 5) | type NoteBlockProps = {

FILE: src/modules/TutorialPage/components/NoteBlock/styled.ts
  type NoteProps (line 9) | type NoteProps = {

FILE: src/modules/TutorialPage/components/StepBlock/index.tsx
  type StepBlockProps (line 6) | type StepBlockProps = {

FILE: src/types.ts
  type User (line 1) | type User = {
  type Course (line 20) | interface Course {
  type Team (line 31) | type Team = {
  type TeamList (line 42) | type TeamList = {
  type TFilterForm (line 47) | type TFilterForm = {
  type UpdateUserInput (line 56) | type UpdateUserInput = {
  type AddUserToTeamInput (line 69) | type AddUserToTeamInput = {
  type RemoveUserFromTeamInput (line 75) | type RemoveUserFromTeamInput = {
  type CreateTeamInput (line 82) | type CreateTeamInput = {
  type CreateCourseInput (line 89) | type CreateCourseInput = {
  type UpdateCourseInput (line 95) | type UpdateCourseInput = {
  type UpdateTeamInput (line 102) | type UpdateTeamInput = {
  type StateTeamsList (line 107) | type StateTeamsList = {
  type UserFilterInput (line 124) | type UserFilterInput = {
  type RemoveUserFromCourseInput (line 133) | type RemoveUserFromCourseInput = {
  type StateStudentsTable (line 140) | type StateStudentsTable = {
  type StateLoginPage (line 145) | type StateLoginPage = {
  type State (line 156) | type State = {
  type TNavLink (line 162) | type TNavLink = {

FILE: src/typography/index.ts
  type StyledTextProps (line 12) | interface StyledTextProps {
  type ButtonProps (line 19) | type ButtonProps = {
  type TRSLogoProps (line 25) | type TRSLogoProps = {
  type ModalInputProps (line 29) | type ModalInputProps = {
Condensed preview — 199 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (306K chars).
[
  {
    "path": ".eslintrc.js",
    "chars": 1204,
    "preview": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  extends: [\n    'plugin:react/recommended',\n    'plugin:@type"
  },
  {
    "path": ".firebaserc",
    "chars": 51,
    "preview": "{\n  \"projects\": {\n    \"default\": \"rss-teams\"\n  }\n}\n"
  },
  {
    "path": ".github/workflows/deploy-client.yml",
    "chars": 655,
    "preview": "name: Build and Deploy\non:\n  push:\n    branches:\n      - master\n\njobs:\n  admin:\n    name: Deploy PROD\n    runs-on: ubunt"
  },
  {
    "path": ".gitignore",
    "chars": 350,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": ".prettierrc",
    "chars": 129,
    "preview": "\n{\n  \"endOfLine\": \"auto\",\n  \"semi\": true,\n  \"singleQuote\": true,\n  \"tabWidth\": 2,\n  \"trailingComma\": \"es5\",\n  \"printWidt"
  },
  {
    "path": "README.md",
    "chars": 3224,
    "preview": "# RSS-Teams-FE - Deprecated and no longer maintained. The latest deployed version will become unavailable from 28/10/202"
  },
  {
    "path": "firebase.json",
    "chars": 235,
    "preview": "{\n  \"hosting\": {\n    \"public\": \"build\",\n    \"ignore\": [\n      \"firebase.json\",\n      \"**/.*\",\n      \"**/node_modules/**\""
  },
  {
    "path": "package.json",
    "chars": 2469,
    "preview": "{\n  \"name\": \"rss-teams-fe\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@apollo/client\": \"^3.3.7\","
  },
  {
    "path": "pre-build.js",
    "chars": 401,
    "preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nrequire('dotenv').config();\n\nconst BAC"
  },
  {
    "path": "public/index.html",
    "chars": 1759,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.i"
  },
  {
    "path": "public/manifest.json",
    "chars": 500,
    "preview": "{\n  \"short_name\": \"RSS Teams\",\n  \"name\": \"The Rolling Scopes School Teams\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico"
  },
  {
    "path": "public/robots.txt",
    "chars": 67,
    "preview": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "src/appConstants/api.ts",
    "chars": 160,
    "preview": "export const BACKEND_LINK = 'https://rss-teams-dev.herokuapp.com/graphql';\nexport const AUTH_BACKEND_LINK = 'https://rss"
  },
  {
    "path": "src/appConstants/colors.ts",
    "chars": 711,
    "preview": "export const WHITE_COLOR = '#FFFFFF';\nexport const BG_COLOR = '#F2F8FD';\nexport const MAIN1_COLOR = '#6550F6'; // violet"
  },
  {
    "path": "src/appConstants/index.ts",
    "chars": 4706,
    "preview": "export { BACKEND_LINK, AUTH_BACKEND_LINK } from './api';\n\nexport const SET_USER_DATA = 'SET_USER_DATA';\nexport const AUT"
  },
  {
    "path": "src/components/App/index.tsx",
    "chars": 2870,
    "preview": "import React, { FC, useEffect, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport {"
  },
  {
    "path": "src/components/App/styled.ts",
    "chars": 207,
    "preview": "import styled from 'styled-components';\n\nexport const AppStyled = styled.div`\n  position: relative;\n  height: 100vh;\n  m"
  },
  {
    "path": "src/components/CommonSelectList/index.tsx",
    "chars": 2680,
    "preview": "import React, { FC, useEffect, useRef } from 'react';\nimport { Course } from 'types';\nimport {\n  StyledCoursesSelectWrap"
  },
  {
    "path": "src/components/CommonSelectList/styled.ts",
    "chars": 4176,
    "preview": "import {\n  MAIN1_DARK_COLOR,\n  WHITE_COLOR,\n  MAIN1_COLOR,\n  DARK_TEXT_COLOR,\n  BG_COLOR,\n  LIGHT_TEXT_COLOR,\n} from 'ap"
  },
  {
    "path": "src/components/CourseField/index.tsx",
    "chars": 1662,
    "preview": "import React, { FC, SelectHTMLAttributes } from 'react';\nimport { Label, Select, SelectInner } from 'typography';\nimport"
  },
  {
    "path": "src/components/CourseField/styled.ts",
    "chars": 1530,
    "preview": "import styled from 'styled-components';\nimport { BG_COLOR, LIGHT_TEXT_COLOR, MAIN1_COLOR, WHITE_COLOR } from 'appConstan"
  },
  {
    "path": "src/components/ErrorBoundary/index.tsx",
    "chars": 1056,
    "preview": "import React, { Component } from 'react';\nimport { BoundryContainer } from './styled';\n\ninterface ErrorBoundaryState {\n "
  },
  {
    "path": "src/components/ErrorBoundary/styled.ts",
    "chars": 276,
    "preview": "import styled from 'styled-components';\nimport { PageTitle } from 'typography';\n\nexport const BoundryContainer = styled("
  },
  {
    "path": "src/components/ErrorModal/index.tsx",
    "chars": 980,
    "preview": "import React, { FC } from 'react';\nimport { Modal } from 'components';\nimport { ApolloError } from '@apollo/client';\nimp"
  },
  {
    "path": "src/components/FilterForm/filterFormFields.ts",
    "chars": 2044,
    "preview": "import { TFilterForm } from 'types';\nimport { InputFieldProps } from '../../components/InputField';\n\nexport const filter"
  },
  {
    "path": "src/components/FilterForm/index.tsx",
    "chars": 4067,
    "preview": "import React, { FC } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { FieldError, FieldErr"
  },
  {
    "path": "src/components/FilterForm/styled.ts",
    "chars": 2503,
    "preview": "import styled from 'styled-components';\nimport { MAIN1_COLOR } from 'appConstants/colors';\nimport { EditProfileWrapper }"
  },
  {
    "path": "src/components/FilterSelect/index.tsx",
    "chars": 1133,
    "preview": "import React, { FC, SelectHTMLAttributes } from 'react';\nimport { Label, Select, SelectInner } from 'typography';\nimport"
  },
  {
    "path": "src/components/Footer/components/FooterContent/index.tsx",
    "chars": 1193,
    "preview": "import React, { FC } from 'react';\nimport { FooterContentBlock, FooterContentWrapper, FooterTitle } from 'components/Foo"
  },
  {
    "path": "src/components/Footer/components/index.ts",
    "chars": 49,
    "preview": "export { FooterContent } from './FooterContent';\n"
  },
  {
    "path": "src/components/Footer/index.tsx",
    "chars": 545,
    "preview": "import React, { FC } from 'react';\nimport { RSLogo } from 'typography';\nimport { StyledFooter, FooterWrapper, FooterCont"
  },
  {
    "path": "src/components/Footer/styled.ts",
    "chars": 2131,
    "preview": "import styled from 'styled-components';\nimport { DARK_TEXT_COLOR, FOOTER_NAMES_COLOR, WHITE_COLOR } from 'appConstants/c"
  },
  {
    "path": "src/components/Header/components/BurgerMenu/index.tsx",
    "chars": 2229,
    "preview": "import React, { FC } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { NavLink } from 'reac"
  },
  {
    "path": "src/components/Header/components/BurgerMenu/styled.ts",
    "chars": 1618,
    "preview": "import styled from 'styled-components';\nimport { DARK_TEXT_COLOR, OVERLAY_COLOR, WHITE_COLOR } from 'appConstants/colors"
  },
  {
    "path": "src/components/Header/components/MenuWrapper/components/CoursesSelect/index.tsx",
    "chars": 1086,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { selectCurr"
  },
  {
    "path": "src/components/Header/components/MenuWrapper/components/LangSelect/index.tsx",
    "chars": 1205,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { LANGUAGES "
  },
  {
    "path": "src/components/Header/components/MenuWrapper/components/Nav/index.tsx",
    "chars": 1526,
    "preview": "import React, { FC } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { APP_NAVIGATION_LINKS } from "
  },
  {
    "path": "src/components/Header/components/MenuWrapper/components/Nav/styled.ts",
    "chars": 1438,
    "preview": "import { WHITE_COLOR } from 'appConstants/colors';\nimport styled, { keyframes } from 'styled-components';\nimport { React"
  },
  {
    "path": "src/components/Header/components/MenuWrapper/index.tsx",
    "chars": 1283,
    "preview": "import React, { FC } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { selectUserData } fro"
  },
  {
    "path": "src/components/Header/components/MenuWrapper/styled.ts",
    "chars": 798,
    "preview": "import styled from 'styled-components';\nimport { ReactComponent as MenuToggle } from 'assets/svg/menuToggle.svg';\n\nexpor"
  },
  {
    "path": "src/components/Header/components/index.ts",
    "chars": 88,
    "preview": "export { MenuWrapper } from './MenuWrapper';\nexport { BurgerMenu } from './BurgerMenu';\n"
  },
  {
    "path": "src/components/Header/index.tsx",
    "chars": 1464,
    "preview": "import React, { FC } from 'react';\nimport { Link } from 'react-router-dom';\nimport { useDispatch, useSelector } from 're"
  },
  {
    "path": "src/components/Header/styled.ts",
    "chars": 765,
    "preview": "import styled from 'styled-components';\nimport { MAIN1_COLOR } from 'appConstants/colors';\nimport { GeneralAdaptiveFont "
  },
  {
    "path": "src/components/InputField/index.tsx",
    "chars": 1027,
    "preview": "import React, { FC, InputHTMLAttributes } from 'react';\nimport { Input } from 'typography';\nimport { FieldWrapper, Valid"
  },
  {
    "path": "src/components/InputField/styled.ts",
    "chars": 450,
    "preview": "import styled from 'styled-components';\nimport { ALERT_COLOR } from 'appConstants/colors';\nimport { GeneralAdaptiveFont,"
  },
  {
    "path": "src/components/Loader/index.tsx",
    "chars": 463,
    "preview": "import React, { FC } from 'react';\nimport { LoaderStyled, LoaderWrapper } from './styled';\n\nexport const Loader: FC = ()"
  },
  {
    "path": "src/components/Loader/styled.ts",
    "chars": 1525,
    "preview": "import styled from 'styled-components';\nimport { MAIN1_COLOR } from 'appConstants/colors';\nimport { MainComponentHeight "
  },
  {
    "path": "src/components/Modal/index.module.css",
    "chars": 951,
    "preview": "/* setting absolute can break other modals */\n.overlay {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0"
  },
  {
    "path": "src/components/Modal/index.tsx",
    "chars": 3494,
    "preview": "import React, { FC, SyntheticEvent, useEffect, useRef } from 'react';\nimport ReactDOM from 'react-dom';\n\nimport { ReactC"
  },
  {
    "path": "src/components/ModalCreateEditTeam/index.tsx",
    "chars": 2352,
    "preview": "import React, { FC, useState, useEffect, useCallback } from 'react';\nimport { useDispatch } from 'react-redux';\nimport {"
  },
  {
    "path": "src/components/ModalCreated/index.tsx",
    "chars": 1584,
    "preview": "import React, { FC, useState } from 'react';\nimport styled from 'styled-components';\nimport { Modal } from 'components';"
  },
  {
    "path": "src/components/ModalEditCourse/index.tsx",
    "chars": 5225,
    "preview": "import React, { FC, useState, useEffect, useCallback } from 'react';\nimport { useDispatch } from 'react-redux';\nimport {"
  },
  {
    "path": "src/components/ModalExpel/index.tsx",
    "chars": 1131,
    "preview": "import React, { FC, useEffect, useCallback } from 'react';\nimport { Modal } from 'components';\n\ntype Props = {\n  title: "
  },
  {
    "path": "src/components/ModalJoin/index.tsx",
    "chars": 1701,
    "preview": "import React, { FC, useCallback, useEffect } from 'react';\nimport { useDispatch } from 'react-redux';\nimport { Modal } f"
  },
  {
    "path": "src/components/Pagination/index.tsx",
    "chars": 971,
    "preview": "import React, { FC } from 'react';\nimport ReactPaginate from 'react-paginate';\nimport './style.css';\nimport leftArrow fr"
  },
  {
    "path": "src/components/Pagination/style.css",
    "chars": 2106,
    "preview": ".pagination {\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  margin: 40px auto 0;\n\n  gap: 10px;\n  "
  },
  {
    "path": "src/components/PrivateRoute/index.tsx",
    "chars": 774,
    "preview": "import React, { FC } from 'react';\nimport { Redirect, Route } from 'react-router-dom';\n\ntype Props = {\n  isLoggedIn: boo"
  },
  {
    "path": "src/components/SelectField/index.tsx",
    "chars": 924,
    "preview": "import React, { FC, SelectHTMLAttributes } from 'react';\nimport { Label, Select, SelectInner } from 'typography';\nimport"
  },
  {
    "path": "src/components/SelectField/styled.ts",
    "chars": 219,
    "preview": "import styled from 'styled-components';\n\nexport const FieldWrapper = styled.div`\n  display: flex;\n  flex-direction: colu"
  },
  {
    "path": "src/components/TablePopup/index.tsx",
    "chars": 461,
    "preview": "import React, { FC } from 'react';\nimport { StyledPopup, StyledPopupItem } from './styled';\n\ntype TablePopupProps = {\n  "
  },
  {
    "path": "src/components/TablePopup/styled.ts",
    "chars": 893,
    "preview": "import { WHITE_COLOR, DARK_TEXT_COLOR, TABLE_POPUP_BORDER_COLOR } from 'appConstants/colors';\nimport styled from 'styled"
  },
  {
    "path": "src/components/TourGuide/index.tsx",
    "chars": 1754,
    "preview": "import React, { FC, useCallback, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport"
  },
  {
    "path": "src/components/TourGuide/style.css",
    "chars": 2334,
    "preview": "span[data-tour-elem=\"badge\"] {\n  top: 20px;\n  left: 20px;\n  width: 30px;\n  height: 30px;\n  padding: 0;\n  font-weight: bo"
  },
  {
    "path": "src/components/TourGuide/styled.ts",
    "chars": 481,
    "preview": "import styled from 'styled-components';\nimport { MAIN1_COLOR, WHITE_COLOR } from 'appConstants/colors';\nimport { TextSem"
  },
  {
    "path": "src/components/TourGuide/tourConfig.tsx",
    "chars": 2473,
    "preview": "import { Button, InvertedButton, ButtonsBlock } from 'typography';\nimport { setIsTourOpen } from 'modules/LoginPage/logi"
  },
  {
    "path": "src/components/index.ts",
    "chars": 862,
    "preview": "export { App } from './App';\nexport { Loader } from './Loader';\nexport { PrivateRoute } from './PrivateRoute';\nexport { "
  },
  {
    "path": "src/graphql/mutations/addUserToTeamMutation.ts",
    "chars": 651,
    "preview": "import { gql } from '@apollo/client';\n\nexport const ADD_USER_TO_TEAM_MUTATION = gql`\n  mutation addUserToTeam($data: Add"
  },
  {
    "path": "src/graphql/mutations/createCourseMutation.ts",
    "chars": 236,
    "preview": "import { gql } from '@apollo/client';\n\nexport const CREATE_COURSE_MUTATION = gql`\n  mutation createCourse($course: Creat"
  },
  {
    "path": "src/graphql/mutations/createTeamMutation.ts",
    "chars": 418,
    "preview": "import { gql } from '@apollo/client';\n\nexport const CREATE_TEAM_MUTATION = gql`\n  mutation createTeam($team: CreateTeamI"
  },
  {
    "path": "src/graphql/mutations/index.ts",
    "chars": 603,
    "preview": "export { UPD_USER_MUTATION } from './updUserMutation';\nexport { ADD_USER_TO_TEAM_MUTATION } from './addUserToTeamMutatio"
  },
  {
    "path": "src/graphql/mutations/removeUserFromCourseMutation.ts",
    "chars": 679,
    "preview": "import { gql } from '@apollo/client';\n\nexport const REMOVE_USER_FROM_COURSE_MUTATION = gql`\n  mutation removeUserFromCou"
  },
  {
    "path": "src/graphql/mutations/removeUserFromTeamMutation.ts",
    "chars": 744,
    "preview": "import { gql } from '@apollo/client';\n\nexport const REMOVE_USER_FROM_TEAM_MUTATION = gql`\n  mutation removeUserFromTeam("
  },
  {
    "path": "src/graphql/mutations/sortStudentsMutation.ts",
    "chars": 173,
    "preview": "import { gql } from '@apollo/client';\n\nexport const SORT_STUDENTS_MUTATION = gql`\n  mutation sortStudents($courseId: Str"
  },
  {
    "path": "src/graphql/mutations/updUserMutation.ts",
    "chars": 634,
    "preview": "import { gql } from '@apollo/client';\n\nexport const UPD_USER_MUTATION = gql`\n  mutation updateUser($user: UpdateUserInpu"
  },
  {
    "path": "src/graphql/mutations/updateCourseMutation.ts",
    "chars": 236,
    "preview": "import { gql } from '@apollo/client';\n\nexport const UPDATE_COURSE_MUTATION = gql`\n  mutation updateCourse($course: Updat"
  },
  {
    "path": "src/graphql/mutations/updateTeamMutation.ts",
    "chars": 418,
    "preview": "import { gql } from '@apollo/client';\n\nexport const UPDATE_TEAM_MUTATION = gql`\n  mutation updateTeam($team: UpdateTeamI"
  },
  {
    "path": "src/graphql/queries/coursesQuery.ts",
    "chars": 171,
    "preview": "import { gql } from '@apollo/client';\n\nexport const COURSES_QUERY = gql`\n  query getCourses {\n    courses {\n      id\n   "
  },
  {
    "path": "src/graphql/queries/index.ts",
    "chars": 227,
    "preview": "export { TEAMS_QUERY } from './teamsQuery';\nexport { USERS_QUERY } from './usersQuery';\n// export { USER_QUERY } from '."
  },
  {
    "path": "src/graphql/queries/teamsQuery.ts",
    "chars": 493,
    "preview": "import { gql } from '@apollo/client';\n\nexport const TEAMS_QUERY = gql`\n  query getTeams($courseId: String!, $pagination:"
  },
  {
    "path": "src/graphql/queries/usersQuery.ts",
    "chars": 575,
    "preview": "import { gql } from '@apollo/client';\n\nexport const USERS_QUERY = gql`\n  query getUsers($courseId: String!, $pagination:"
  },
  {
    "path": "src/graphql/queries/whoAmIQuery.ts",
    "chars": 583,
    "preview": "import { gql } from '@apollo/client';\n\nexport const WHOAMI_QUERY = gql`\n  query getWhoAMi {\n    whoAmI {\n      id\n      "
  },
  {
    "path": "src/hooks/graphql/index.ts",
    "chars": 1046,
    "preview": "export { useTeamsQuery } from './queries/useTeamsQuery';\nexport { useUsersQuery } from './queries/useUsersQuery';\nexport"
  },
  {
    "path": "src/hooks/graphql/mutations/useAddUserToTeamMutation.ts",
    "chars": 694,
    "preview": "import { useMutation } from '@apollo/client';\nimport { ADD_USER_TO_TEAM_MUTATION } from 'graphql/mutations';\nimport { WH"
  },
  {
    "path": "src/hooks/graphql/mutations/useCreateCourseMutation.ts",
    "chars": 937,
    "preview": "import { useMutation } from '@apollo/client';\nimport { Course, CreateCourseInput } from 'types';\nimport { COURSES_QUERY "
  },
  {
    "path": "src/hooks/graphql/mutations/useCreateTeamMutation.ts",
    "chars": 1893,
    "preview": "import { useMutation } from '@apollo/client';\nimport { CreateTeamInput, TeamList, User } from 'types';\nimport { TEAMS_QU"
  },
  {
    "path": "src/hooks/graphql/mutations/useExpelUserFromTeamMutation.ts",
    "chars": 2222,
    "preview": "import { useMutation } from '@apollo/client';\nimport { RemoveUserFromTeamInput, Team, TeamList, User } from 'types';\nimp"
  },
  {
    "path": "src/hooks/graphql/mutations/useRemoveUserFromCourseMutation.ts",
    "chars": 2694,
    "preview": "import { useMutation } from '@apollo/client';\nimport { CURRENT_COURSE, TEAMS_PER_PAGE } from 'appConstants';\nimport { RE"
  },
  {
    "path": "src/hooks/graphql/mutations/useRemoveUserFromTeamMutation.ts",
    "chars": 1916,
    "preview": "import { useMutation } from '@apollo/client';\nimport { RemoveUserFromTeamInput, Team, TeamList, User } from 'types';\nimp"
  },
  {
    "path": "src/hooks/graphql/mutations/useSortStudentsMutation.ts",
    "chars": 420,
    "preview": "import { useMutation } from '@apollo/client';\nimport { SORT_STUDENTS_MUTATION } from 'graphql/mutations';\n\ntype Props = "
  },
  {
    "path": "src/hooks/graphql/mutations/useUpdUserMutation.ts",
    "chars": 732,
    "preview": "import { useMutation } from '@apollo/client';\nimport { UPD_USER_MUTATION } from 'graphql/mutations';\nimport { WHOAMI_QUE"
  },
  {
    "path": "src/hooks/graphql/mutations/useUpdateCourseMutation.ts",
    "chars": 1018,
    "preview": "import { useMutation } from '@apollo/client';\nimport { UpdateCourseInput, Course } from 'types';\nimport { COURSES_QUERY "
  },
  {
    "path": "src/hooks/graphql/mutations/useUpdateTeamMutation.ts",
    "chars": 1072,
    "preview": "import { useMutation } from '@apollo/client';\nimport { UpdateTeamInput, User, Team } from 'types';\nimport { WHOAMI_QUERY"
  },
  {
    "path": "src/hooks/graphql/queries/useCoursesQuery.ts",
    "chars": 322,
    "preview": "import { useQuery } from '@apollo/client';\n\nimport { COURSES_QUERY } from 'graphql/queries';\n\nexport const useCoursesQue"
  },
  {
    "path": "src/hooks/graphql/queries/useTeamsQuery.ts",
    "chars": 654,
    "preview": "import { useQuery } from '@apollo/client';\nimport { TEAMS_PER_PAGE } from 'appConstants';\n\nimport { TEAMS_QUERY } from '"
  },
  {
    "path": "src/hooks/graphql/queries/useUsersQuery.ts",
    "chars": 747,
    "preview": "import { useQuery } from '@apollo/client';\nimport { USERS_PER_PAGE } from 'appConstants';\n\nimport { USERS_QUERY } from '"
  },
  {
    "path": "src/hooks/graphql/queries/useWhoAmIQuery.ts",
    "chars": 369,
    "preview": "import { useQuery } from '@apollo/client';\nimport { WHOAMI_QUERY } from 'graphql/queries';\n\ntype Props = {\n  skip: boole"
  },
  {
    "path": "src/index.tsx",
    "chars": 2536,
    "preview": "import React from 'react';\nimport ReactDOM from 'react-dom';\nimport { BrowserRouter as Router } from 'react-router-dom';"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock/index.tsx",
    "chars": 1159,
    "preview": "import React, { FC } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ModalInput, Label } from 'ty"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/components/InputsBlock/styled.ts",
    "chars": 733,
    "preview": "import styled from 'styled-components';\n\nexport const InputWrapper = styled.div<{ isModal?: boolean }>`\n  display: flex;"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/index.tsx",
    "chars": 4526,
    "preview": "import React, { FC, useCallback, useState } from 'react';\nimport { MAIN2_COLOR, WHITE_COLOR } from 'appConstants/colors'"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/AddCourseBlock/styled.ts",
    "chars": 527,
    "preview": "import styled from 'styled-components';\n\nexport const AddCourseBlockWrapper = styled.div`\n  display: flex;\n  align-items"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/CoursesList/components/Course/index.tsx",
    "chars": 1628,
    "preview": "import React, { FC } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useDispatch } from 'react-re"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/CoursesList/components/Course/styled.ts",
    "chars": 767,
    "preview": "import styled from 'styled-components';\nimport { BG_COLOR } from 'appConstants/colors';\nimport { GeneralAdaptiveFont } f"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/CoursesList/index.tsx",
    "chars": 2590,
    "preview": "import React, { FC } from 'react';\nimport { CoursesListWrapper } from './styled';\nimport { CourseItem } from './componen"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/CoursesList/styled.ts",
    "chars": 342,
    "preview": "import styled from 'styled-components';\n\nexport const CoursesListWrapper = styled.div`\n  display: flex;\n  flex-direction"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/components/ShowCourseSelect/index.tsx",
    "chars": 937,
    "preview": "import React, { FC, useState } from 'react';\nimport { SHOW_COURSES_OPTIONS } from 'appConstants';\nimport { CommonSelectL"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/index.tsx",
    "chars": 2777,
    "preview": "import React, { FC, useState, useMemo } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { AdminPage"
  },
  {
    "path": "src/modules/AdminPage/components/ContentWrapper/styled.ts",
    "chars": 852,
    "preview": "import { DARK_TEXT_COLOR, WHITE_COLOR } from 'appConstants/colors';\nimport styled from 'styled-components';\nimport { H2A"
  },
  {
    "path": "src/modules/AdminPage/components/index.ts",
    "chars": 53,
    "preview": "export { AdminPageWrapper } from './ContentWrapper';\n"
  },
  {
    "path": "src/modules/AdminPage/index.tsx",
    "chars": 662,
    "preview": "import React, { FC } from 'react';\nimport { TeamsTitleWrapper } from 'modules/TeamsList/styled';\nimport { useTranslation"
  },
  {
    "path": "src/modules/EditProfile/components/UserCourseListItem/index.tsx",
    "chars": 1447,
    "preview": "import React, { FC } from 'react';\nimport { useSelector } from 'react-redux';\nimport { MinusButton, UserCourseListItemSt"
  },
  {
    "path": "src/modules/EditProfile/components/UserCourseListItem/styled.ts",
    "chars": 629,
    "preview": "import styled from 'styled-components';\nimport { BG_COLOR, DARK_TEXT_COLOR } from 'appConstants/colors';\nimport { PlusBu"
  },
  {
    "path": "src/modules/EditProfile/formFields.ts",
    "chars": 3832,
    "preview": "import { INPUT_VALUES_EDIT_PROFILE } from 'appConstants';\nimport { Course } from 'types';\nimport { InputFieldProps } fro"
  },
  {
    "path": "src/modules/EditProfile/index.tsx",
    "chars": 8836,
    "preview": "import React, { FC, useEffect, useMemo, useState } from 'react';\nimport { Redirect, useHistory } from 'react-router-dom'"
  },
  {
    "path": "src/modules/EditProfile/styled.ts",
    "chars": 1834,
    "preview": "import styled from 'styled-components';\nimport { BG_COLOR, DARK_TEXT_COLOR, LIGHT_TEXT_COLOR, WHITE_COLOR } from 'appCon"
  },
  {
    "path": "src/modules/LoginPage/components/LoginInfoBlock/index.tsx",
    "chars": 771,
    "preview": "import React, { FC } from 'react';\nimport {\n  StyledLoginInfoBlock,\n  StyledLoginTitle,\n  StyledLoginRegistrationLink,\n "
  },
  {
    "path": "src/modules/LoginPage/components/LoginInfoBlock/styled.ts",
    "chars": 1364,
    "preview": "import styled from 'styled-components';\nimport { WHITE_COLOR, DARK_TEXT_COLOR, MAIN1_COLOR } from 'appConstants/colors';"
  },
  {
    "path": "src/modules/LoginPage/components/index.ts",
    "chars": 51,
    "preview": "export { LoginInfoBlock } from './LoginInfoBlock';\n"
  },
  {
    "path": "src/modules/LoginPage/index.tsx",
    "chars": 628,
    "preview": "import React, { FC } from 'react';\nimport { useSelector } from 'react-redux';\nimport { Redirect } from 'react-router-dom"
  },
  {
    "path": "src/modules/LoginPage/loginPageMiddleware.ts",
    "chars": 766,
    "preview": "import { CURRENT_LANG, CURRENT_COURSE, TOUR_OPENING } from 'appConstants';\nimport { Course } from 'types';\nimport { setC"
  },
  {
    "path": "src/modules/LoginPage/loginPageReducer.ts",
    "chars": 2364,
    "preview": "import {\n  DEFAULT_LANGUAGE,\n  SET_COMMON_ERROR,\n  SET_CURR_COURSE,\n  SET_CURR_LANG,\n  SET_TOKEN,\n  SET_BURGER_MENU_OPEN"
  },
  {
    "path": "src/modules/LoginPage/selectors.ts",
    "chars": 770,
    "preview": "import { State } from 'types';\n\nexport const selectToken = (state: State) => state.loginPageReducer.loginToken;\n\nexport "
  },
  {
    "path": "src/modules/LoginPage/styled.ts",
    "chars": 910,
    "preview": "import styled from 'styled-components';\nimport { MAIN1_COLOR, WHITE_COLOR } from 'appConstants/colors';\nimport { ReactCo"
  },
  {
    "path": "src/modules/NotFoundPage/index.tsx",
    "chars": 442,
    "preview": "import React, { FC } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ContentPageWrapper, PageTitl"
  },
  {
    "path": "src/modules/NotFoundPage/styled.ts",
    "chars": 189,
    "preview": "import styled from 'styled-components';\n\nexport const NotFoundPageWrapper = styled.div`\n  display: flex;\n  justify-conte"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/index.tsx",
    "chars": 1293,
    "preview": "import React, { FC, MouseEvent, useState } from 'react';\nimport { TablePopup } from 'components/TablePopup';\nimport { St"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/components/TableItem/styled.ts",
    "chars": 426,
    "preview": "import styled from 'styled-components';\n\ntype TStyledTableItem = {\n  tableItemCursor: boolean;\n};\n\nexport const StyledTa"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/index.tsx",
    "chars": 644,
    "preview": "import React, { FC } from 'react';\nimport { ListChildComponentProps } from 'react-window';\nimport { TableItem } from './"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/components/TableRow/styled.ts",
    "chars": 500,
    "preview": "import { BG_COLOR, DARK_TEXT_COLOR } from 'appConstants/colors';\nimport styled from 'styled-components';\n\nexport const S"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/index.tsx",
    "chars": 2034,
    "preview": "import React, { FC, useMemo, ReactText } from 'react';\nimport { useSelector } from 'react-redux';\nimport { FixedSizeList"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/styled.ts",
    "chars": 135,
    "preview": "import styled from 'styled-components';\n\nexport const StyledTableBody = styled.div`\n  display: flex;\n  width: 100%;\n  he"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableBody/styles.css",
    "chars": 2590,
    "preview": ".List {\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  height: 100%;\n  overflow-y: scroll !important;\n}\n\n.L"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableHead/index.tsx",
    "chars": 626,
    "preview": "import React, { FC } from 'react';\nimport { TABLE_HEADERS } from 'appConstants';\nimport { StyledTableHead, StyledTableHe"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/TableHead/styled.ts",
    "chars": 814,
    "preview": "import styled from 'styled-components';\nimport { LIGHT_TEXT_COLOR, DASHBOARD_HEADER_BG_COLOR } from 'appConstants/colors"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/components/index.ts",
    "chars": 82,
    "preview": "export { TableBody } from './TableBody';\nexport { TableHead } from './TableHead';\n"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/index.tsx",
    "chars": 405,
    "preview": "import React, { FC } from 'react';\nimport { TableBody, TableHead } from './components';\nimport { StyledTable } from './s"
  },
  {
    "path": "src/modules/StudentsTable/components/Dashboard/styled.ts",
    "chars": 438,
    "preview": "import styled from 'styled-components';\nimport { WHITE_COLOR } from 'appConstants/colors';\nimport { GeneralAdaptiveFont "
  },
  {
    "path": "src/modules/StudentsTable/index.tsx",
    "chars": 3995,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { USERS_PER_"
  },
  {
    "path": "src/modules/StudentsTable/selectors.ts",
    "chars": 207,
    "preview": "import { State } from 'types';\n\nexport const selectUserData = (state: State) => state.studentsTableReducer.userData;\n\nex"
  },
  {
    "path": "src/modules/StudentsTable/studentsTableReducer.ts",
    "chars": 1097,
    "preview": "import { SET_USER_DATA, SET_FILTER_DATA } from 'appConstants';\nimport { StateStudentsTable } from 'types';\nimport { defa"
  },
  {
    "path": "src/modules/StudentsTable/styled.ts",
    "chars": 1087,
    "preview": "import styled from 'styled-components';\nimport { DARK_TEXT_COLOR } from 'appConstants/colors';\nimport { ScrollBar } from"
  },
  {
    "path": "src/modules/TeamsList/components/TeamListModals/index.tsx",
    "chars": 5921,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { ModalExpel"
  },
  {
    "path": "src/modules/TeamsList/components/TeamListModals/useCommonMutations.ts",
    "chars": 2992,
    "preview": "import { useSelector } from 'react-redux';\nimport { selectSocialLink, selectTeamMemberExpelId, selectTeamPassword } from"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MemberListToggle/index.tsx",
    "chars": 850,
    "preview": "import React, { FC } from 'react';\nimport { MembersListToggleStyled, Chevron } from './styled';\nimport { ReactComponent "
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MemberListToggle/styled.ts",
    "chars": 860,
    "preview": "import styled from 'styled-components';\nimport { WHITE_COLOR } from 'appConstants/colors';\nimport { SVGArrowAdaptive } f"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/MyTeamInfoLine/index.tsx",
    "chars": 1340,
    "preview": "import React, { FC, MouseEvent, useState } from 'react';\nimport { InfoLineStyled, CopyClipboardButton } from './styled';"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/MyTeamInfoLine/styled.tsx",
    "chars": 965,
    "preview": "import styled from 'styled-components';\nimport { WHITE_COLOR } from 'appConstants/colors';\nimport { TextBold, GeneralAda"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/NotificationPopup/index.tsx",
    "chars": 248,
    "preview": "import React, { FC } from 'react';\nimport { NotificationPopupStyled } from './styled';\n\nconst NotificationPopup: FC = ({"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/components/NotificationPopup/styled.ts",
    "chars": 579,
    "preview": "import styled from 'styled-components';\nimport { LIGHT_TEXT_COLOR, WHITE_COLOR } from 'appConstants/colors';\n\nexport con"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/index.tsx",
    "chars": 1450,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch } from 'react-redux';\nimport { StyledMyTeamInfoBlock, "
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/components/MyTeamInfoBlock/styled.ts",
    "chars": 1063,
    "preview": "import styled, { css } from 'styled-components';\nimport { WHITE_COLOR, MAIN2_LIGHT_COLOR, MAIN2_COLOR } from 'appConstan"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/index.tsx",
    "chars": 2407,
    "preview": "import React, { FC, useState } from 'react';\nimport { useDispatch } from 'react-redux';\n\nimport { StyledMyTeam, HeaderDe"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/MyTeam/styled.ts",
    "chars": 3664,
    "preview": "import styled from 'styled-components';\nimport { ReactComponent as HeaderDecoration } from 'assets/svg/team-header-decor"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamItem/index.tsx",
    "chars": 1192,
    "preview": "import React, { FC, useState } from 'react';\nimport { TeamItemStyled, TeamItemTableWrapper } from './styled';\nimport { U"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamItem/styled.tsx",
    "chars": 919,
    "preview": "import styled from 'styled-components';\nimport { TextRegular, TextSemiBold, GeneralAdaptiveFont } from 'typography';\nimp"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/ExpelButton/index.tsx",
    "chars": 364,
    "preview": "import React, { FC } from 'react';\nimport { SmallCrossIcon, StyledExpelButton } from './styled';\n\ntype ExpelButtonProps "
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/ExpelButton/styled.ts",
    "chars": 789,
    "preview": "import styled from 'styled-components';\nimport { ReactComponent as Cross } from 'assets/svg/cross-small.svg';\nimport { M"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/TableCell/index.tsx",
    "chars": 355,
    "preview": "import React, { FC } from 'react';\n\ntype TTableCell = {\n  value: any;\n  isSocialLink?: boolean;\n};\n\nconst formatSocialLi"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/components/index.ts",
    "chars": 86,
    "preview": "export { TableCell } from './TableCell';\nexport { ExpelButton } from './ExpelButton';\n"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/components/TableRow/index.tsx",
    "chars": 1431,
    "preview": "import React, { FC } from 'react';\nimport { User } from 'types';\nimport { TableCell } from './components';\nimport { Expe"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/index.tsx",
    "chars": 1258,
    "preview": "import React, { FC } from 'react';\nimport { StyledTeamUserTable } from './styled';\nimport { User } from 'types';\nimport "
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamUserTable/styled.tsx",
    "chars": 2023,
    "preview": "import styled, { css } from 'styled-components';\nimport {\n  DASHBOARD_HEADER_BG_COLOR,\n  LIGHT_TEXT_COLOR,\n  DARK_TEXT_C"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamsHeader/index.tsx",
    "chars": 2044,
    "preview": "import React, { FC } from 'react';\nimport {\n  TeamsHeaderStyled,\n  TeamsHeaderRightStyled,\n  TeamsHeaderSubtitleStyled,\n"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/TeamsHeader/styled.ts",
    "chars": 1449,
    "preview": "import styled from 'styled-components';\nimport { WHITE_COLOR, MAIN2_COLOR } from 'appConstants/colors';\nimport { ReactCo"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/components/index.ts",
    "chars": 119,
    "preview": "export { TeamsHeader } from './TeamsHeader';\nexport { MyTeam } from './MyTeam';\nexport { TeamItem } from './TeamItem';\n"
  },
  {
    "path": "src/modules/TeamsList/components/Teams/index.tsx",
    "chars": 962,
    "preview": "import React, { FC } from 'react';\n\nimport { TeamsHeader, MyTeam, TeamItem } from './components';\nimport { Team, TeamLis"
  },
  {
    "path": "src/modules/TeamsList/components/index.ts",
    "chars": 84,
    "preview": "export { Teams } from './Teams';\nexport { TeamListModals } from './TeamListModals';\n"
  },
  {
    "path": "src/modules/TeamsList/index.tsx",
    "chars": 2394,
    "preview": "import React, { FC, useState } from 'react';\nimport { useSelector, useDispatch } from 'react-redux';\nimport { useTeamsQu"
  },
  {
    "path": "src/modules/TeamsList/selectors.ts",
    "chars": 1541,
    "preview": "import { State } from 'types';\n\nexport const selectIsActiveModalExpel = (state: State) => state.teamsListReducer.isActiv"
  },
  {
    "path": "src/modules/TeamsList/styled.ts",
    "chars": 307,
    "preview": "import styled from 'styled-components';\n\nexport const StyledTeams = styled.div`\n  max-width: 1320px;\n  width: 92%;\n`;\n\ne"
  },
  {
    "path": "src/modules/TeamsList/teamsListReducer.ts",
    "chars": 4522,
    "preview": "import {\n  SET_SOCIAL_LINK,\n  SET_TEAM_PASSWORD,\n  SET_TEAM_MEMBER_EXPEL_ID,\n  ACTIVE_MODAL_EXPEL,\n  ACTIVE_MODAL_LEAVE,"
  },
  {
    "path": "src/modules/TokenPage/index.tsx",
    "chars": 834,
    "preview": "import React, { FC, useEffect } from 'react';\nimport { AUTH_TOKEN } from 'appConstants';\nimport { useDispatch } from 're"
  },
  {
    "path": "src/modules/TutorialPage/components/NoteBlock/index.tsx",
    "chars": 736,
    "preview": "import React, { FC } from 'react';\nimport { NoteWrapper, NoteList } from './styled';\nimport { useTranslation } from 'rea"
  },
  {
    "path": "src/modules/TutorialPage/components/NoteBlock/styled.ts",
    "chars": 2244,
    "preview": "import {\n  DARK_TEXT_COLOR,\n  MAIN1_COLOR,\n  DASHBOARD_HEADER_BG_COLOR,\n  WHITE_COLOR,\n} from 'appConstants/colors';\nimp"
  },
  {
    "path": "src/modules/TutorialPage/components/StepBlock/index.tsx",
    "chars": 640,
    "preview": "import React, { FC } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { StepBlockWrapper, StepBlockT"
  },
  {
    "path": "src/modules/TutorialPage/components/StepBlock/styled.ts",
    "chars": 322,
    "preview": "import styled from 'styled-components';\nimport { TextRegular } from 'typography';\n\nexport const StepBlockWrapper = style"
  },
  {
    "path": "src/modules/TutorialPage/components/index.ts",
    "chars": 82,
    "preview": "export { StepBlock } from './StepBlock';\nexport { NoteBlock } from './NoteBlock';\n"
  },
  {
    "path": "src/modules/TutorialPage/index.tsx",
    "chars": 2006,
    "preview": "import React, { FC, useCallback } from 'react';\nimport { TutorialPageWrapper } from './styled';\nimport editProfileExampl"
  },
  {
    "path": "src/modules/TutorialPage/styled.ts",
    "chars": 1479,
    "preview": "import styled from 'styled-components';\nimport { GeneralAdaptiveFont } from 'typography';\n\nexport const TutorialPageWrap"
  },
  {
    "path": "src/modules/TutorialPage/tutorialPageInfo.tsx",
    "chars": 1295,
    "preview": "import myTeamExampleEN from 'assets/images/myTeamExampleEN.png';\nimport myTeamExampleRU from 'assets/images/myTeamExampl"
  },
  {
    "path": "src/modules/index.ts",
    "chars": 352,
    "preview": "export { LoginPage } from './LoginPage';\nexport { StudentsTable } from './StudentsTable';\nexport { TeamsList } from './T"
  },
  {
    "path": "src/react-app-env.d.ts",
    "chars": 402,
    "preview": "/// <reference types=\"react-scripts\" />\ndeclare module '*.woff2';\ndeclare module '*.svg' {\n  import React = require('rea"
  },
  {
    "path": "src/reportWebVitals.ts",
    "chars": 425,
    "preview": "import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n  if (onPerfEntr"
  },
  {
    "path": "src/setupTests.ts",
    "chars": 241,
    "preview": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).to"
  },
  {
    "path": "src/store/index.tsx",
    "chars": 868,
    "preview": "import React, { FC } from 'react';\nimport { Provider } from 'react-redux';\nimport { studentsTableReducer } from 'modules"
  },
  {
    "path": "src/translation/en/en.json",
    "chars": 8827,
    "preview": "{\n  \"First / Last Name\": \"First / Last Name\",\n  \"Score\": \"Score\",\n  \"Team Number\": \"Team Number\",\n  \"Location\": \"Locatio"
  },
  {
    "path": "src/translation/resources.ts",
    "chars": 576,
    "preview": "import { CURRENT_LANG, DEFAULT_LANGUAGE } from 'appConstants';\nimport i18n from 'i18next';\nimport { initReactI18next } f"
  },
  {
    "path": "src/translation/ru/ru.json",
    "chars": 9371,
    "preview": "{\n  \"First / Last Name\": \"Имя и фамилия\",\n  \"Score\": \"Рейтинг\",\n  \"Team Number\": \"№ команды\",\n  \"Location\": \"Локация\",\n "
  },
  {
    "path": "src/types.ts",
    "chars": 3148,
    "preview": "export type User = {\n  id: string;\n  firstName: string;\n  lastName: string;\n  github: string;\n  telegram: string | null;"
  },
  {
    "path": "src/typography/common.css",
    "chars": 424,
    "preview": "*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\n:root {\n  --BG_COLOR: #f2f8fd;\n  --OVERLAY_COLOR: rgba(54, 61, 72,"
  },
  {
    "path": "src/typography/fonts.css",
    "chars": 1470,
    "preview": "@font-face {\n  font-style: normal;\n  font-weight: 400;\n  font-family: \"Poppins\";\n  src: url(\"../assets/fonts/Poppins-Reg"
  },
  {
    "path": "src/typography/index.ts",
    "chars": 8308,
    "preview": "import styled, { css } from 'styled-components';\nimport { ReactComponent as RSLogoIcon } from 'assets/svg/rslogo.svg';\ni"
  },
  {
    "path": "src/typography/normalize.css",
    "chars": 6145,
    "preview": "/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n   ==========================="
  },
  {
    "path": "src/utils/isFieldValid.ts",
    "chars": 1314,
    "preview": "export const isFieldValid = (\n  value: string,\n  validateRules: any,\n  needValidate: boolean,\n  setInputValid: (valid: b"
  },
  {
    "path": "tsconfig.json",
    "chars": 559,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\n      \"dom\",\n      \"dom.iterable\",\n      \"esnext\"\n    ],\n    "
  }
]

// ... and 4 more files (download for full content)

About this extraction

This page contains the full source code of the rolling-scopes-school/RSS-Teams-FE GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 199 files (268.1 KB), approximately 79.8k tokens, and a symbol index with 193 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!