diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..4d29575de
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/README.md b/README.md
index 03779cb84..43a38965d 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,15 @@
-# rslang
\ No newline at end of file
+# rslang
+
+Front-end Таска "Rslang" команда #108
+
+для локального развёртывания приложения необходимо выполнить следующие шаги:
+
+- клонировать репозиторий в локальную папку на компьютере, желательно не использовать в пути к папке приложения русских букв и большой вложенности папок.
+
+- установить необходимые зависимости приложения командой npm install
+
+- после успешной установки можно запустить приложение командой react-scripts start, приложение скомпилируется и откроется на dev-сервере
+
+- в файле /src/api/defData в константе url устанавливается путь к api серверу базы данных, по умолчанию установлен https://rslang.tk
+
+- инструкция по развёртыванию api сервера в read.me бэкэнд сервера.
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..b5c209139
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,345 @@
+{
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "@types/prop-types": {
+ "version": "15.7.3",
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
+ "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
+ },
+ "@types/react": {
+ "version": "17.0.3",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz",
+ "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==",
+ "requires": {
+ "@types/prop-types": "*",
+ "@types/scheduler": "*",
+ "csstype": "^3.0.2"
+ }
+ },
+ "@types/react-gauge-chart": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@types/react-gauge-chart/-/react-gauge-chart-0.3.0.tgz",
+ "integrity": "sha512-n5+3osoKXEXS8tdzEEB5cqRbfs/zo3tO0mMQFH5sDhZOQp1lnoh0pa+8Obl/E4ZBwOAUifGVOYRf5VOwFkdMaw==",
+ "requires": {
+ "@types/react": "*"
+ }
+ },
+ "@types/react-speech-recognition": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@types/react-speech-recognition/-/react-speech-recognition-3.6.0.tgz",
+ "integrity": "sha512-nFXlBxhz5Wnz/P7AQenmaG7r9MGBmvZhTW/MLPEPd1CYLgB+6jg0GygIYYM5LR+K1WyZ3+jXGhGszxoLQQkHXQ=="
+ },
+ "@types/scheduler": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz",
+ "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA=="
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ },
+ "csstype": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
+ "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
+ },
+ "d3": {
+ "version": "5.16.0",
+ "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz",
+ "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==",
+ "requires": {
+ "d3-array": "1",
+ "d3-axis": "1",
+ "d3-brush": "1",
+ "d3-chord": "1",
+ "d3-collection": "1",
+ "d3-color": "1",
+ "d3-contour": "1",
+ "d3-dispatch": "1",
+ "d3-drag": "1",
+ "d3-dsv": "1",
+ "d3-ease": "1",
+ "d3-fetch": "1",
+ "d3-force": "1",
+ "d3-format": "1",
+ "d3-geo": "1",
+ "d3-hierarchy": "1",
+ "d3-interpolate": "1",
+ "d3-path": "1",
+ "d3-polygon": "1",
+ "d3-quadtree": "1",
+ "d3-random": "1",
+ "d3-scale": "2",
+ "d3-scale-chromatic": "1",
+ "d3-selection": "1",
+ "d3-shape": "1",
+ "d3-time": "1",
+ "d3-time-format": "2",
+ "d3-timer": "1",
+ "d3-transition": "1",
+ "d3-voronoi": "1",
+ "d3-zoom": "1"
+ }
+ },
+ "d3-array": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+ "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+ },
+ "d3-axis": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz",
+ "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
+ },
+ "d3-brush": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz",
+ "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==",
+ "requires": {
+ "d3-dispatch": "1",
+ "d3-drag": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "1",
+ "d3-transition": "1"
+ }
+ },
+ "d3-chord": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
+ "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
+ "requires": {
+ "d3-array": "1",
+ "d3-path": "1"
+ }
+ },
+ "d3-collection": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
+ "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
+ },
+ "d3-color": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz",
+ "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q=="
+ },
+ "d3-contour": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
+ "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
+ "requires": {
+ "d3-array": "^1.1.1"
+ }
+ },
+ "d3-dispatch": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz",
+ "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA=="
+ },
+ "d3-drag": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz",
+ "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==",
+ "requires": {
+ "d3-dispatch": "1",
+ "d3-selection": "1"
+ }
+ },
+ "d3-dsv": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz",
+ "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==",
+ "requires": {
+ "commander": "2",
+ "iconv-lite": "0.4",
+ "rw": "1"
+ }
+ },
+ "d3-ease": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
+ "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
+ },
+ "d3-fetch": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz",
+ "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==",
+ "requires": {
+ "d3-dsv": "1"
+ }
+ },
+ "d3-force": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz",
+ "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==",
+ "requires": {
+ "d3-collection": "1",
+ "d3-dispatch": "1",
+ "d3-quadtree": "1",
+ "d3-timer": "1"
+ }
+ },
+ "d3-format": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz",
+ "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ=="
+ },
+ "d3-geo": {
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz",
+ "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==",
+ "requires": {
+ "d3-array": "1"
+ }
+ },
+ "d3-hierarchy": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz",
+ "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ=="
+ },
+ "d3-interpolate": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz",
+ "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==",
+ "requires": {
+ "d3-color": "1"
+ }
+ },
+ "d3-path": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz",
+ "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="
+ },
+ "d3-polygon": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz",
+ "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ=="
+ },
+ "d3-quadtree": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz",
+ "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA=="
+ },
+ "d3-random": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz",
+ "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ=="
+ },
+ "d3-scale": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
+ "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
+ "requires": {
+ "d3-array": "^1.2.0",
+ "d3-collection": "1",
+ "d3-format": "1",
+ "d3-interpolate": "1",
+ "d3-time": "1",
+ "d3-time-format": "2"
+ }
+ },
+ "d3-scale-chromatic": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz",
+ "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==",
+ "requires": {
+ "d3-color": "1",
+ "d3-interpolate": "1"
+ }
+ },
+ "d3-selection": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz",
+ "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg=="
+ },
+ "d3-shape": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz",
+ "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==",
+ "requires": {
+ "d3-path": "1"
+ }
+ },
+ "d3-time": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz",
+ "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA=="
+ },
+ "d3-time-format": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz",
+ "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==",
+ "requires": {
+ "d3-time": "1"
+ }
+ },
+ "d3-timer": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
+ "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
+ },
+ "d3-transition": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz",
+ "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==",
+ "requires": {
+ "d3-color": "1",
+ "d3-dispatch": "1",
+ "d3-ease": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "^1.1.0",
+ "d3-timer": "1"
+ }
+ },
+ "d3-voronoi": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
+ "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
+ },
+ "d3-zoom": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz",
+ "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==",
+ "requires": {
+ "d3-dispatch": "1",
+ "d3-drag": "1",
+ "d3-interpolate": "1",
+ "d3-selection": "1",
+ "d3-transition": "1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "react-gauge-chart": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/react-gauge-chart/-/react-gauge-chart-0.3.0.tgz",
+ "integrity": "sha512-W6oYFnlKNP5fuvERBwMuwjtQ+mNd+qpRjvjkTKrYeCmtBShCkxP17TOddtF5Sk5MbUJQle1MbER8TyJZaBLatA==",
+ "requires": {
+ "d3": "^5.12.0"
+ }
+ },
+ "react-speech-recognition": {
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/react-speech-recognition/-/react-speech-recognition-3.7.0.tgz",
+ "integrity": "sha512-apJhZ94GCnW8/6qIbnWHZrZqgDfYyuvVzU1WdEOuDHLeIgQ5CSe3l7IwXbkvxXqYQp4/7DmYbOmvXt2rRahXyQ==",
+ "dev": true
+ },
+ "rw": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+ "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ }
+ }
+}
diff --git a/rslang/.gitignore b/rslang/.gitignore
new file mode 100644
index 000000000..9d9101486
--- /dev/null
+++ b/rslang/.gitignore
@@ -0,0 +1,24 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+package-lock.json
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/rslang/README.md b/rslang/README.md
new file mode 100644
index 000000000..dbf499138
--- /dev/null
+++ b/rslang/README.md
@@ -0,0 +1,13 @@
+Front-end Таска "Rslang" команда #108
+
+для локального развёртывания приложения необходимо выполнить следующие шаги:
+
+- клонировать репозиторий в локальную папку на компьютере, желательно не использовать в пути к папке приложения русских букв и большой вложенности папок.
+
+- установить необходимые зависимости приложения командой npm install
+
+- после успешной установки можно запустить приложение командой react-scripts start, приложение скомпилируется и откроется на dev-сервере
+
+- в файле /src/api/defData в константе url устанавливается путь к api серверу базы данных, по умолчанию установлен https://rslang.tk
+
+- инструкция по развёртыванию api сервера в read.me бэкэнд сервера.
\ No newline at end of file
diff --git a/rslang/docs/api.md b/rslang/docs/api.md
new file mode 100644
index 000000000..f801a24e5
--- /dev/null
+++ b/rslang/docs/api.md
@@ -0,0 +1,67 @@
+
+ baseUrl - http://rslang.tk:3000/
+ baseUrl - https://rocky-basin-33827.herokuapp.com/
+ baseUrl - https://serene-falls-78086.herokuapp.com/
+
+ /doc - документация api
+
+## getData
+getWords - слова
+
+ GET для получения списка слов: https://rocky-basin-33827.herokuapp.com/words?page=2&group=0 - получить слова со 2-й страницы группы 0
+Строка запроса должна содержать в себе номер группы и номер страницы. Всего 6 групп(от 0 до 5) и в каждой группе по 30 страниц(от 0 до 29). В каждой странице по 20 слов. Группы разбиты по сложности от самой простой(0) до самой сложной(5).
+
+
+getUserData - получение даных пользователя
+
+ getUserData(url, token)
+
+ addUrl:
+ user - /users/{userId}
+ user words - /users/{userId}/words
+ user word - /users/{userId}/words/{wordId}
+ user settings - /users/{userId}/settings
+ user statistic - /users/{userId}/statistics
+
+ \users\{id}\statistics и \users\{id}\settings
+Объект optional у UserWord, Statistics, Settings имеет ограничение по размеру - не более 30 полей и общая длина объекта после JSON.stringify() не должна превышать 1500 символов. Структуру этих объектов вы разрабатываете сами исходя из требований и вашей реализации задачи.
+
+ word - /words/{wordId}
+ words - /words?page=2&group=0 - получить слова со 2-й страницы группы 0
+Строка запроса должна содержать в себе номер группы и номер страницы. Всего 6 групп(от 0 до 5) и в каждой группе по 30 страниц(от 0 до 29). В каждой странице по 20 слов. Группы разбиты по сложности от самой простой(0) до самой сложной(5).
+
+
+## setData
+setUserData - сохранение даных пользователя в базу
+
+ setUserData(url, token, body)
+
+ addUrl:
+ user settings - /users/{userId}/settings
+ user statistic - /users/{userId}/statistics
+
+statistics и settings обнавляются по ключам, можно отправить в body объект с одним ключём для обновления одного внутреннего объекта, при этом объект по этому ключу полностью перезапишется, не изменяя всего остального содержания settings или statistics.
+
+ statistics {
+ learnedWords: number,
+ optional: {},
+ vocabulary: {},
+ call: {},
+ speakit: {},
+ sprint: {},
+ ourgame: {},
+ puzzle: {},
+ savanna: {}
+ }
+
+ settings {
+ wordsPerDay: number,
+ optional: {},
+ vocabulary: {},
+ call: {},
+ speakit: {},
+ sprint: {},
+ ourgame: {},
+ puzzle: {},
+ savanna: {}
+ }
diff --git a/rslang/docs/task.md b/rslang/docs/task.md
new file mode 100644
index 000000000..556646f16
--- /dev/null
+++ b/rslang/docs/task.md
@@ -0,0 +1,219 @@
+https://github.com/rolling-scopes-school/tasks/blob/master/tasks/react/react-rslang.md
+
+RS Lang – приложение для изучения иностранных слов, включающее электронный учебник с базой слов для изучения, мини-игры для их повторения, страницу статистики для отслеживания индивидуального прогресса.
+
+электронная версия учебника "4000 Essential English Words" - из этого учебника необходимо воспроизвести Word List
+приложение Lingualeo - из этого приложения необходимо воспроизвести мини-игры "Саванна", "Аудиовызов", "Спринт".
+Для доступа к играм "Аудиовызов" и "Спринт" понадобится Lingualeo Premium. Бесплатный доступ к Lingualeo Premium на один день откроется после 5 дней тренировки. Также для знакомства с геймплеем можно использовать видео: Саванна и Аудиовызов, Спринт
+
+### Лучшие работы студентов предыдущего набора
+(сейчас требования к заданию изменились)
+
+https://rslang-team16-arcanar7.web.app/
+
+https://rslang-team41-jekman87.netlify.app/
+
+https://rslang-team5-alekchaik.netlify.app/
+
+https://rslang-team11-kagafon.netlify.app/
+
+https://rslang-team69-dimonwhite.netlify.app/
+
+https://rslang-team26-evgender.netlify.app/
+
+https://rslang-team64-viktorsipach.netlify.app/
+
+### Исходные данные
+Коллекция "4000 essential english words". Коллекция содержит 3600 часто употребляемых английских слов, изучение которых вам необходимо организовать. Слова в коллекции отсортированы от более простых и известных к более сложным. Первые 400 наиболее часто употребляемых слов в коллекцию не вошли. Считается, что это базовый запас взрослого человека, оставшийся от предыдущих попыток изучения языка. Вся коллекция разбита на шесть групп, в каждой группе 30 страниц, на каждой странице 20 слов для изучения.
+
+## Структура приложения
+
+- главная страница приложения
+
+- электронный учебник со словарём
+
+- мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра"
+
+- страница статистики
+
+### Описание функциональных блоков
+
+#### 1 Главная страница приложения
+выполняет функцию промо-страницы, её оформление определяет первое впечатление о приложении
+главная страница приложения содержит:
+- меню с навигацией по учебнику, ссылками на мини-игры и статистику. Меню или иконка меню отображается на всех страницах приложения
+- описание возможностей и преимуществ приложения
+- небольшое (5-7 минут) видео с демонстрацией работы приложения
+- раздел "О команде" с фото и ссылками на гитхабы всех участников команды, описанием вклада в разработку приложения каждого из них. При желании данный раздел можно вынести в отдельную страницу
+- footer со ссылками на гитхабы авторов приложения, год создания приложения, логотип курса со ссылкой на курс. footer отображается на всех страницах приложения за исключением мини-игр.
+
+ #### 2 Электронный учебник
+ - электронный учебник состоит из шести разделов, которым соответствуют шесть групп слов коллекции исходных данных. В каждом разделе 30 страниц. На каждой странице выводится:
+ - меню или иконка меню
+ - иконка настроек
+ - список из 20 слов
+ - ссылки на мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра" для повторения изученных слов
+ - навигация по страницам со стрелками для перехода к следующей и предыдущей страницам и номером текущей страницы
+ - также необходимо продумать навигацию по шести разделам учебника и предусмотреть небольшие различия в оформлении каждого раздела. Например, можно использовать для каждого раздела индикатор определённого цвета
+ - при перезагрузке страницы открывается последняя открытая страница приложения
+
+ ##### Настройки
+ - в настройках учебника у пользователя есть возможность указать:
+ - нужно ли отображать в списке слов перевод изучаемого слова и перевод предложений с ним
+ - нужно ли отображать возле каждого слова кнопки, при клике по которым данное слово добавляется в раздел словаря "Сложные слова" или "Удалённые слова"
+
+ ##### Список слов
+ - для каждого слова отображается:
+ - само слово, его транскрипция, его перевод
+ - предложение с объяснением значения изучаемого слова, его перевод
+ - предложение с примером использования изучаемого слова, его перевод
+ - картинка-ассоциация к изучаемому слову
+ - иконка аудио при клике по которой последовательно звучит произношение изучаемого слова, произношение предложения с объяснением его значения, произношение предложения с примером его использования
+ - кнопки, при клике по которым изучаемое слово добавляется в разделы словаря "Сложные слова" или "Удалённые слова"
+ - результат изучения/повторения слова в мини-играх
+ - если слово добавлено в раздел словаря "Сложные слова", оно остаётся на странице учебника, и его стиль изменяется или возле него выводится индикатор, указывающий, что оно относится к сложным словам
+ - если слово добавлено в раздел словаря "Удалённые слова", оно удаляется со страницы учебника. Если пользователь удалит со страницы все слова, страница удаляется
+
+ ##### Словарь
+ - словарь является частью учебника. В словаре есть разделы "Изучаемые слова", "Сложные слова", "Удалённые слова"
+ - в раздел "Изучаемые слова" попадают слова, которые были задействованы в мини-играх, если мини-игры открывались кликом по ссылке на странице учебника или на странице раздела словаря "Сложные слова". Также в раздел "Изучаемые слова" попадают слова, которые пользователь отметил как сложные. Возле сложных слов есть индикатор или они выделены стилем, так же, как и на странице учебника
+ - возле каждого слова в разделе "Изучаемые слова" указывается результат изучения - сколько раз слово было правильно угадано в мини-играх, сколько раз пользователь ошибался
+ - для каждого раздела и каждой страницы учебника указывается количество изучаемых слов и общий результат их изучения
+ - в разделы словаря "Сложные слова" и "Удалённые слова" слова попадают, если пользователь кликнул по соответствующим кнопкам возле слов на страницах учебника
+ - страницы разделов словаря "Сложные слова" и "Удалённые слова" выглядят точно так же, как страницы учебника: формируются страницы, на каждой из которых список из 20 слов, создаётся новая страница, на страницах есть ссылки на мини-игры для повторения слов. Слова из разных разделов учебника попадают на разные страницы, на странице есть индикатор, указывающий, к какому разделу учебника она относитеся. Если слов больше 20, создаётся новая страница. Единственное отличие в списке слов вместо кнопок, при клике по которым изучаемое слово добавляется в разделы словаря "Сложные слова" или "Удалённые слова", в словаре возле слова отображается кнопка "Восстановить", которая удаляет слово из словаря и восстанавливает его на странице электронного учебника
+
+ #### Мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра"
+ - мини-игры предназначены для изучения и повторения слов электронного учебника
+ - мини-игры "Саванна", "Аудиовызов" и "Спринт" повторяют одноимённые мини-игры приложения Lingualeo
+ - мини-игру с условным названием "Своя игра" вы придумываете сами
+ - слова, которые используются в мини-играх, отличаются в зависимости от того, откуда вы открываете игру: по ссылке в меню или по ссылке на странице учебника
+ - если мини-игра открывается по ссылке в меню, в ней есть возможность выбрать один из шести уровней сложности. Уровень сложности мини-игры определяет раздел учебника, слова из которого в ней будут использоваться,
+ - если мини-игра открывается по ссылке на странице учебника, она используется для повторения слов, размещённых на этой странице. В этом случае в игре нет возможности выбрать уровень сложности и используются те слова, которые размещены на данной странице учебника. Если 20 слов для мини-игры не хватает, в ней задействуются слова из предыдущих страниц учебника. Если предыдущих страниц нет или недостаточно, игру можно заканчивать досрочно, когда исчерпаются все доступные слова
+ - слова, которые использовались в мини-играх, открытых по ссылке на странице учебника или на странице раздела словаря "Сложные слова", попадают в раздел словаря "Изучаемые слова"
+
+ #### Страница статистики
+ - на странице статистики отображается краткосрочная статистика по результатам каждого дня и долгосрочная статистика за весь период изучения
+ - в краткосрочной статистике указывается количество изученных слов, процент правильных ответов и самая длинная серия правильных ответов по каждой мини-игре отдельно, а также общее количество изученных слов и процент правильных ответов за день
+ - в долгосрочной статистике представлены два графика. На одном из них отображается количество изученных слов за каждый день изучения, на другом - увеличение общего количества изученных слов за весь период изучения по дням.
+
+ #### Бекенд
+
+ Что уже есть:
+
+ создан репозиторий с бекендом на его основе создан ReactLearnWords API, позволяющий получить исходные данные
+
+ создана ReactLearnWords wiki с инструкциями по созданию базы данных MongoDB, деплою бекенда на heroku, примерами получения исходных данных
+
+ Что нужно сделать:
+ создать свою копию бекенда. Для этого: форкните репозиторий с бекендом для создания базы данных MongoDB и деплоя бекенда на heroku следуйте туториалам ReactLearnWords wiki
+
+ - вам необходимо добавить в бекенд возможность при регистрации нового пользователя указать его имя и загрузить фото
+
+### Технические требования
+- работа приложения проверяется в браузере Google Chrome последней версии
+- необходимо использовать React
+- можно использовать bootstrap, material design, css-фреймворки, html и css препроцессоры
+- можно использовать js-библиотеки
+- разрешается использовать jQuery только в качесте подключаемой зависимости для UI библиотек. Использование jQuery в основном коде приложения не допускается
+- рекомендуется использовать TypeScript
+- рекомендуется создать и использовать бекенд. Данная рекомендация связана с очень высоким спросом на фронтенд-разработчиков, знакомых хотя бы с основами node.js.
+запрещено копировать код других студентов, демо, примеров, которые приводятся в задании. Этот запрет касается html, css, js кода. Можно использовать небольшие фрагменты кода со Stack Overflow, других самостоятельно найденных источников в интернете, за исключением github-репозиториев студентов курса. Возле использованного чужого фрагмента кода в комментарии указывается ссылка на источник.
+
+### Как сабмитить задание
+Участникам команд необходимо записаться в таблицу, ссылка на которую будет размещена в анонсах
+
+Ссылку на pull request в rs app сабмитит только тимлид
+
+Убедитесь, что pull request доступен для проверки. Для этого откройте ссылку, которую сабмитите в rs app, в режиме инкогнито браузера
+
+Если задание не засабмитить до дедлайна, оно не попадёт на распределение при кросс-чеке и за него не будут выставлены баллы
+
+### Требования к оформлению приложения
+#### особое внимание обратите на качество оформления приложения.
+Как прототип можно использовать подходящие шаблоны, размещённые на behance, dribbble, pinterest
+
+Качественное приложение характеризуется проработанностью деталей, вниманием к типографике (не больше трёх шрифтов на странице, размер шрифта не меньше 14 рх, оптимальная контрастность шрифта и фона), тщательно подобранным контентом
+вёрстка адаптивная. Минимальная ширина страницы, при которой проверяется корректность отображения приложения - 500рх
+
+Интерактивность элементов, с которыми пользователи могут взаимодействовать, изменение внешнего вида самого элемента и состояния курсора при наведении, использование разных стилей для активного и неактивного состояния элемента, плавные анимации
+единство стилей всех страниц приложения - одинаковые шрифты, стили кнопок, отступы, одинаковые элементы на всех страницах приложения имеют одинаковый внешний вид и расположение. Цвет элементов и фоновые изображения могут отличаться. В этом случае цвета используются из одной палитры, а фоновые изображения из одной коллекции.
+
+#### Требования к мини-играм
+- все игры выполнены в одном стиле, при этом в оформлении каждой игры есть индивидуальные отличия (цветовая схема, фоновый рисунок, эффекты анимации и т. д.)
+мини-игру можно развернуть во весь экран
+- по окончанию каждой игры выводятся результаты мини-игры
+- одинаковые элементы игр, такие как результаты мини-игры, блок выбора уровня сложности, стартовый экран, если он есть, и т.д. идентичны по внешнему виду, расположению на странице, функционалу
+- управлять игрой можно как мышкой, так и клавишами на клавиатуре, как это реализовано в оригинальных играх
+- если мини-игра запускается из меню, в ней можно выбрать один из шести уровней сложности, которые отличаются тем, слова какой из шести частей коллекции исходных данных в ней задействованы
+- если мини-игра запускается со страницы учебника, в ней используются слова из той страницы учебника, на которой размещена ссылка на игру. Если размещённых на странице слов для игры недостаточно, задействуются слова с предыдущих страниц
+
+### Критерии оценивания
+
+Максимальный балл за задание 600
+
+500 баллов за приложение
+
+100 баллов за презентацию
+
+Для удобства проверки необходимо записать и разместить на YouTube небольшое (5-7 мин) видео для проверяющих с объяснением как реализован каждый пункт из перечисленных в критериях оценки. Особое внимание обратите на те пункты критериев оценки, которые проверяющий проверить не сможет, например, на то как вы реализовали базу данных, как задеплоили бекенд, как выглядит долгосрочная статистика и т.д. Ссылку на видео можно добавить в описание pull request или в footer приложения добавить иконку YouTube со ссылкой на видео.
+
+При оценивании приложения проверяются все требования, описанные в пунктах Описание функциональных блоков, Требования к оформлению приложения, Требования к мини-играм. Если какие-то из перечисленных требований не выполняются, снимаем часть баллов. В комментарии к оценке необходимо указать какие пункты не выполнены или выполнены частично.
+
+#### Вёрстка, дизайн, UI +40
+- вёрстка, дизайн, UI главной страницы приложения +10
+- вёрстка, дизайн, UI электронного учебника +10
+- вёрстка, дизайн, UI страницы статистики +10
+- оригинальный интересный качественный дизайн приложения +10
+
+#### Главная страница приложения +40
+- меню +10
+- описание возможностей и преимуществ приложения +10
+- видео с демонстрацией работы приложения +10
+- раздел "О команде" +10
+
+#### Электронный учебник +50
+- страницы и разделы учебника +10
+- настройки +10
+- список слов +20
+- навигация по страницам и разделам учебника +10
+
+#### Словарь +40
+- раздел "Изучаемые слова" +20
+- раздел "Сложные слова" +10
+- раздел "Удалённые слова" +10
+
+#### Мини-игры +200 (максимум +50 баллов за каждую игру)
+
+Мини-игра может оцениваться в 30, 40 или 50 баллов.
+
+При оценке предложенной командой игры, её сложность, интересность, полезность, качество реализации сравнивается с другими мини-играми и оценивается по сравнению с ними.
+
+- игра в основном соответствует прототипу, является его упрощённой версией +30
+
+- игра полностью повторяет прототип и детали его работы. Выполняются все перечисленные в задании требования к мини-играм +40
+
+- игра является улучшенной версией прототипа как с точки зрения внешнего вида и оформления, так и удобства работы. Присутствует дополнительный функционал, улучшающий качество приложения +50
+
+#### Страница статистики +40
+
+- краткосрочная статистика +20
+
+- долгосрочная статистика +20
+
+#### Бекенд +60
+
+- собственная копия бекенда размещена на heroku или другом бесплатном хостинге +20
+
+- приложение использует данные из собственного API +10
+
+- при регистрации нового пользователя можно указать его имя. При перезагрузке клиента данные о пользователе сохраняются +10
+
+- при регистрации нового пользователя можно загрузить фото +10
+
+- реализована авторизация и разавторизация пользователя. Основная часть приложения доступна без авторизации. Авторизация необходима только для хранения долгосрочной статистики и формирования словаря +10
+
+#### Дополнительный функционал +30**
+
+- реализован не указанный в задании дополнительный функционал. Оценивается оригинальная идея, вклад в улучшение качества приложения, полезность, сложность и качество выполнения +20
+
+- написано не меньше 10 юнит-тестов, использующих различные методы jest +10
diff --git a/rslang/package.json b/rslang/package.json
new file mode 100644
index 000000000..36293ac5d
--- /dev/null
+++ b/rslang/package.json
@@ -0,0 +1,82 @@
+{
+ "name": "rslang",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.11.9",
+ "@testing-library/react": "^11.2.5",
+ "@testing-library/user-event": "^12.8.1",
+ "@types/jest": "^26.0.20",
+ "@types/node": "^12.20.4",
+ "@types/react": "^17.0.2",
+ "@types/react-dom": "^17.0.1",
+ "@types/react-router-dom": "^5.1.7",
+ "bootstrap": "^4.6.0",
+ "bootstrap-icons": "^1.4.0",
+ "chart.js": "^2.9.4",
+ "lodash": "^4.17.21",
+ "node-sass": "^5.0.0",
+ "node-schedule": "^2.0.0",
+ "react": "^17.0.1",
+ "react-bootstrap": "^1.5.1",
+ "react-bootstrap-icons": "^1.4.0",
+ "react-chartjs-2": "^2.11.1",
+ "react-countdown-circle-timer": "^2.5.1",
+ "react-datetime": "^3.0.4",
+ "react-dom": "^17.0.1",
+ "react-gauge-chart": "^0.3.0",
+ "react-hook-form": "^6.15.5",
+ "react-icons": "^4.2.0",
+ "react-loadable": "^5.5.0",
+ "react-loadable-ssr-addon": "^1.0.1",
+ "react-moment": "^1.1.1",
+ "react-overlays": "^5.0.0",
+ "react-player": "^2.9.0",
+ "react-rating": "^2.0.5",
+ "react-router": "^5.2.0",
+ "react-router-dom": "^5.2.0",
+ "react-scripts": "4.0.3",
+ "react-speech-recognition": "^3.7.0",
+ "react-yandex-maps": "^4.6.0",
+ "twix": "^1.3.0",
+ "typescript": "^4.2.3",
+ "web-vitals": "^1.1.0"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "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/lodash": "^4.14.168",
+ "@types/node-schedule": "^1.3.1",
+ "@types/react-gauge-chart": "^0.3.0",
+ "@types/react-loadable": "^5.5.4",
+ "@types/react-speech-recognition": "^3.6.0",
+ "@types/styled-components": "^5.1.9",
+ "react-animations": "^1.0.0",
+ "react-gauge-chart": "^0.3.0",
+ "react-hook-form": "^6.15.5",
+ "react-rating": "^2.0.5",
+ "styled-components": "^5.2.3"
+ }
+}
diff --git a/rslang/public/favicon.ico b/rslang/public/favicon.ico
new file mode 100644
index 000000000..9f05b8bba
Binary files /dev/null and b/rslang/public/favicon.ico differ
diff --git a/rslang/public/index.html b/rslang/public/index.html
new file mode 100644
index 000000000..745ec48c9
--- /dev/null
+++ b/rslang/public/index.html
@@ -0,0 +1,49 @@
+
+
+
+
+ Ресурс позволяет учить английский онлайн при помощи метода
+ интервального повторения, отслеживания индивидуального прогресса и
+ мини-играми.
+
+
+ Мы рекомендуем сделать упор именно на изучении новых слов.
+
+
+ Метод интервального повторения.
+
+
+ Первый раз вы должны повторить это слово где-нибудь через пару
+ минут, потом — через час, далее — на следующий день, затем — через
+ 2 дня, 5 дней, 10 дней, 3 недели, 6 недель, 3 месяца, 6 месяцев и
+ т.д. И вуаля: вы на всю жизнь запомните, что за словом «cat»
+ скрывается некто пушистый и мурлыкающий.{" "}
+
+
+
+
+
+
+
+
+
Особенности приложения
+
+
+
+
+
+
+
+ Слова и готовый фразы
+
+
+ Расширяй свой словарный запас и учи популярные фразы. Они
+ выручат в любой ситуации, помогут поддержать разговор, сделают
+ речь живой и непринужденной.
+
+
+
+
+
+
+
+ Рассказы и статьи
+
+ Если вы регулярно читаете художественные произведения
+ англоязычных писателей, вы осваиваете «правильный» английский
+ язык, который отличается от разговорного.
+
+
+
+
+
+
+
+ Тесты
+
+ Тесты благоприятно влияют на быстрое изучение нового материала и
+ закрепление уже пройденного, они могут заменить Вам учителя при
+ изучении английского самостоятельно.
+
+
+
+
+
+
+ Мини-игры
+
+ Игры помогут вам не просто приятно провести время, но и
+ расширить словарный запас, подтянуть знание грамматики и
+ правописание.
+
+
+
+
+
+
+
+ Статистика прогресса
+
+
+ Вне зависимости от того, играете ли вы или тренируете слова -
+ статистика по изученным словам обновляется и всегда доступна в
+ настройках.
+
+
+
+
+
+
+
+
+ На этой странице вы можете следить за своим прогрессом и выбирать
+ желаемый набор слов для изучения, например,{" "}
+ “Новые слова” , “Повторить слова”
+ или “Сложные слова” . Удачи!
+
+
+
Сегодня изучено
+
+ Сегодня изучено: {props.learnedWordToday.length} из{" "}
+ {props.words.length * (props.page + 1)} слов
+
+
+
+ );
+};
+
+export default StudiedVocabularySection;
diff --git a/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.scss b/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.scss
new file mode 100644
index 000000000..0bd032208
--- /dev/null
+++ b/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.scss
@@ -0,0 +1,13 @@
+.selected-words-head {
+ font-size: 1.2rem;
+ font-weight: 500;
+}
+.list-word {
+ display: flex;
+ align-items: center;
+ padding-left: 3.5rem;
+ font-size: 1.2rem;
+}
+.list-word-checkbox {
+ margin-left: -2.25rem;
+}
diff --git a/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.tsx b/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.tsx
new file mode 100644
index 000000000..4675f9e23
--- /dev/null
+++ b/rslang/src/components/Vocabulary/VocabularySections/VocabularySections.tsx
@@ -0,0 +1,79 @@
+import "bootstrap/dist/css/bootstrap.min.css";
+import "./VocabularySections.scss";
+import React, { useState, useEffect } from "react";
+import _ from "lodash";
+import StudiedVocabularySection from "./StudiedVocabularySection";
+import HardVocabularySection from "./HardVocabularySection";
+import DeletedVocabularySection from "./DeletedVocabularySection";
+interface InterfaceVocabularySections {
+ selectedSection: string;
+ hardWords: any;
+ learnedWords: any;
+ deletedWords: any;
+ sortingDeletedWords: any;
+ getHardWords(arr: any): void;
+ getLearnedWords(arr: any): void;
+ getDeletedWords(arr: any): void;
+}
+
+const VocabularySections: React.FC = (props) => {
+ const [hardWords, setHardWords] = useState([]);
+ const [learnedWords, setLearnedWords] = useState([]);
+ const [deletedWords, setDeletedWords] = useState([]);
+
+ useEffect(() => {
+ props.getHardWords(hardWords);
+ }, [hardWords]);
+
+ useEffect(() => {
+ props.getLearnedWords(learnedWords);
+ }, [learnedWords]);
+
+ useEffect(() => {
+ props.getDeletedWords(deletedWords);
+ }, [deletedWords]);
+
+ const getHardWords = (arr: any) => {
+ setHardWords(_.uniqWith(hardWords.concat(arr), _.isEqual));
+ };
+
+ const getLearnedWords = (arr: any) => {
+ setLearnedWords(_.uniqWith(learnedWords.concat(arr), _.isEqual));
+ };
+
+ const getDeletedWords = (arr: any) => {
+ setDeletedWords(_.uniqWith(deletedWords.concat(arr), _.isEqual));
+ };
+
+ const showSelectedSection = () => {
+ if (props.selectedSection === "hard-sections") {
+ return (
+
+ );
+ } else if (props.selectedSection === "deleted-sections") {
+ return (
+
+ );
+ } else {
+ return (
+
+ );
+ }
+ };
+ return showSelectedSection();
+};
+export default VocabularySections;
diff --git a/rslang/src/hooks/useLocalStorage.tsx b/rslang/src/hooks/useLocalStorage.tsx
new file mode 100644
index 000000000..c1f199de6
--- /dev/null
+++ b/rslang/src/hooks/useLocalStorage.tsx
@@ -0,0 +1,28 @@
+import { useState } from "react";
+
+const useLocalStorage = (key: any, initialValue: any) => {
+ const [storedValue, setStoredValue] = useState(() => {
+ // window.localStorage.clear();
+ try {
+ const item = window.localStorage.getItem(key);
+ return item ? JSON.parse(item) : initialValue;
+ } catch (error) {
+ console.log(error);
+ return initialValue;
+ }
+ });
+ const setValue = (value: any) => {
+ try {
+ const valueToStore =
+ value instanceof Function ? value(storedValue) : value;
+ setStoredValue(valueToStore);
+ window.localStorage.setItem(key, JSON.stringify(valueToStore));
+ } catch (error) {
+ console.log(error);
+ }
+ };
+
+ return [storedValue, setValue];
+};
+
+export default useLocalStorage;
diff --git a/rslang/src/index.css b/rslang/src/index.css
new file mode 100644
index 000000000..4a1df4db7
--- /dev/null
+++ b/rslang/src/index.css
@@ -0,0 +1,13 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
+ "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
+ monospace;
+}
diff --git a/rslang/src/index.tsx b/rslang/src/index.tsx
new file mode 100644
index 000000000..eec0ac9c7
--- /dev/null
+++ b/rslang/src/index.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import "./index.css";
+import App from "./App";
+import reportWebVitals from "./reportWebVitals";
+
+ReactDOM.render(
+
+
+ ,
+ 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();
diff --git a/rslang/src/react-app-env.d.ts b/rslang/src/react-app-env.d.ts
new file mode 100644
index 000000000..6431bc5fc
--- /dev/null
+++ b/rslang/src/react-app-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/rslang/src/reportWebVitals.ts b/rslang/src/reportWebVitals.ts
new file mode 100644
index 000000000..49a2a16e0
--- /dev/null
+++ b/rslang/src/reportWebVitals.ts
@@ -0,0 +1,15 @@
+import { ReportHandler } from 'web-vitals';
+
+const reportWebVitals = (onPerfEntry?: ReportHandler) => {
+ if (onPerfEntry && onPerfEntry instanceof Function) {
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
+ getCLS(onPerfEntry);
+ getFID(onPerfEntry);
+ getFCP(onPerfEntry);
+ getLCP(onPerfEntry);
+ getTTFB(onPerfEntry);
+ });
+ }
+};
+
+export default reportWebVitals;
diff --git a/rslang/src/setupTests.ts b/rslang/src/setupTests.ts
new file mode 100644
index 000000000..8f2609b7b
--- /dev/null
+++ b/rslang/src/setupTests.ts
@@ -0,0 +1,5 @@
+// jest-dom adds custom jest matchers for asserting on DOM nodes.
+// allows you to do things like:
+// expect(element).toHaveTextContent(/react/i)
+// learn more: https://github.com/testing-library/jest-dom
+import '@testing-library/jest-dom';
diff --git a/rslang/src/utils/AudioWord.tsx b/rslang/src/utils/AudioWord.tsx
new file mode 100644
index 000000000..a553df1bc
--- /dev/null
+++ b/rslang/src/utils/AudioWord.tsx
@@ -0,0 +1,11 @@
+import { url } from "./../api/defData";
+
+export const playAudioWord = (audioPath: string) => {
+ const audioWord = new Audio(url + audioPath);
+ audioWord.play();
+};
+
+export const playAudio = (audio: any) => {
+ const audioWord = new Audio(audio);
+ audioWord.play();
+};
diff --git a/rslang/tsconfig.json b/rslang/tsconfig.json
new file mode 100644
index 000000000..a273b0cfc
--- /dev/null
+++ b/rslang/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src"
+ ]
+}
diff --git a/task.md b/task.md
new file mode 100644
index 000000000..556646f16
--- /dev/null
+++ b/task.md
@@ -0,0 +1,219 @@
+https://github.com/rolling-scopes-school/tasks/blob/master/tasks/react/react-rslang.md
+
+RS Lang – приложение для изучения иностранных слов, включающее электронный учебник с базой слов для изучения, мини-игры для их повторения, страницу статистики для отслеживания индивидуального прогресса.
+
+электронная версия учебника "4000 Essential English Words" - из этого учебника необходимо воспроизвести Word List
+приложение Lingualeo - из этого приложения необходимо воспроизвести мини-игры "Саванна", "Аудиовызов", "Спринт".
+Для доступа к играм "Аудиовызов" и "Спринт" понадобится Lingualeo Premium. Бесплатный доступ к Lingualeo Premium на один день откроется после 5 дней тренировки. Также для знакомства с геймплеем можно использовать видео: Саванна и Аудиовызов, Спринт
+
+### Лучшие работы студентов предыдущего набора
+(сейчас требования к заданию изменились)
+
+https://rslang-team16-arcanar7.web.app/
+
+https://rslang-team41-jekman87.netlify.app/
+
+https://rslang-team5-alekchaik.netlify.app/
+
+https://rslang-team11-kagafon.netlify.app/
+
+https://rslang-team69-dimonwhite.netlify.app/
+
+https://rslang-team26-evgender.netlify.app/
+
+https://rslang-team64-viktorsipach.netlify.app/
+
+### Исходные данные
+Коллекция "4000 essential english words". Коллекция содержит 3600 часто употребляемых английских слов, изучение которых вам необходимо организовать. Слова в коллекции отсортированы от более простых и известных к более сложным. Первые 400 наиболее часто употребляемых слов в коллекцию не вошли. Считается, что это базовый запас взрослого человека, оставшийся от предыдущих попыток изучения языка. Вся коллекция разбита на шесть групп, в каждой группе 30 страниц, на каждой странице 20 слов для изучения.
+
+## Структура приложения
+
+- главная страница приложения
+
+- электронный учебник со словарём
+
+- мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра"
+
+- страница статистики
+
+### Описание функциональных блоков
+
+#### 1 Главная страница приложения
+выполняет функцию промо-страницы, её оформление определяет первое впечатление о приложении
+главная страница приложения содержит:
+- меню с навигацией по учебнику, ссылками на мини-игры и статистику. Меню или иконка меню отображается на всех страницах приложения
+- описание возможностей и преимуществ приложения
+- небольшое (5-7 минут) видео с демонстрацией работы приложения
+- раздел "О команде" с фото и ссылками на гитхабы всех участников команды, описанием вклада в разработку приложения каждого из них. При желании данный раздел можно вынести в отдельную страницу
+- footer со ссылками на гитхабы авторов приложения, год создания приложения, логотип курса со ссылкой на курс. footer отображается на всех страницах приложения за исключением мини-игр.
+
+ #### 2 Электронный учебник
+ - электронный учебник состоит из шести разделов, которым соответствуют шесть групп слов коллекции исходных данных. В каждом разделе 30 страниц. На каждой странице выводится:
+ - меню или иконка меню
+ - иконка настроек
+ - список из 20 слов
+ - ссылки на мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра" для повторения изученных слов
+ - навигация по страницам со стрелками для перехода к следующей и предыдущей страницам и номером текущей страницы
+ - также необходимо продумать навигацию по шести разделам учебника и предусмотреть небольшие различия в оформлении каждого раздела. Например, можно использовать для каждого раздела индикатор определённого цвета
+ - при перезагрузке страницы открывается последняя открытая страница приложения
+
+ ##### Настройки
+ - в настройках учебника у пользователя есть возможность указать:
+ - нужно ли отображать в списке слов перевод изучаемого слова и перевод предложений с ним
+ - нужно ли отображать возле каждого слова кнопки, при клике по которым данное слово добавляется в раздел словаря "Сложные слова" или "Удалённые слова"
+
+ ##### Список слов
+ - для каждого слова отображается:
+ - само слово, его транскрипция, его перевод
+ - предложение с объяснением значения изучаемого слова, его перевод
+ - предложение с примером использования изучаемого слова, его перевод
+ - картинка-ассоциация к изучаемому слову
+ - иконка аудио при клике по которой последовательно звучит произношение изучаемого слова, произношение предложения с объяснением его значения, произношение предложения с примером его использования
+ - кнопки, при клике по которым изучаемое слово добавляется в разделы словаря "Сложные слова" или "Удалённые слова"
+ - результат изучения/повторения слова в мини-играх
+ - если слово добавлено в раздел словаря "Сложные слова", оно остаётся на странице учебника, и его стиль изменяется или возле него выводится индикатор, указывающий, что оно относится к сложным словам
+ - если слово добавлено в раздел словаря "Удалённые слова", оно удаляется со страницы учебника. Если пользователь удалит со страницы все слова, страница удаляется
+
+ ##### Словарь
+ - словарь является частью учебника. В словаре есть разделы "Изучаемые слова", "Сложные слова", "Удалённые слова"
+ - в раздел "Изучаемые слова" попадают слова, которые были задействованы в мини-играх, если мини-игры открывались кликом по ссылке на странице учебника или на странице раздела словаря "Сложные слова". Также в раздел "Изучаемые слова" попадают слова, которые пользователь отметил как сложные. Возле сложных слов есть индикатор или они выделены стилем, так же, как и на странице учебника
+ - возле каждого слова в разделе "Изучаемые слова" указывается результат изучения - сколько раз слово было правильно угадано в мини-играх, сколько раз пользователь ошибался
+ - для каждого раздела и каждой страницы учебника указывается количество изучаемых слов и общий результат их изучения
+ - в разделы словаря "Сложные слова" и "Удалённые слова" слова попадают, если пользователь кликнул по соответствующим кнопкам возле слов на страницах учебника
+ - страницы разделов словаря "Сложные слова" и "Удалённые слова" выглядят точно так же, как страницы учебника: формируются страницы, на каждой из которых список из 20 слов, создаётся новая страница, на страницах есть ссылки на мини-игры для повторения слов. Слова из разных разделов учебника попадают на разные страницы, на странице есть индикатор, указывающий, к какому разделу учебника она относитеся. Если слов больше 20, создаётся новая страница. Единственное отличие в списке слов вместо кнопок, при клике по которым изучаемое слово добавляется в разделы словаря "Сложные слова" или "Удалённые слова", в словаре возле слова отображается кнопка "Восстановить", которая удаляет слово из словаря и восстанавливает его на странице электронного учебника
+
+ #### Мини-игры "Саванна", "Аудиовызов", "Спринт", "Своя игра"
+ - мини-игры предназначены для изучения и повторения слов электронного учебника
+ - мини-игры "Саванна", "Аудиовызов" и "Спринт" повторяют одноимённые мини-игры приложения Lingualeo
+ - мини-игру с условным названием "Своя игра" вы придумываете сами
+ - слова, которые используются в мини-играх, отличаются в зависимости от того, откуда вы открываете игру: по ссылке в меню или по ссылке на странице учебника
+ - если мини-игра открывается по ссылке в меню, в ней есть возможность выбрать один из шести уровней сложности. Уровень сложности мини-игры определяет раздел учебника, слова из которого в ней будут использоваться,
+ - если мини-игра открывается по ссылке на странице учебника, она используется для повторения слов, размещённых на этой странице. В этом случае в игре нет возможности выбрать уровень сложности и используются те слова, которые размещены на данной странице учебника. Если 20 слов для мини-игры не хватает, в ней задействуются слова из предыдущих страниц учебника. Если предыдущих страниц нет или недостаточно, игру можно заканчивать досрочно, когда исчерпаются все доступные слова
+ - слова, которые использовались в мини-играх, открытых по ссылке на странице учебника или на странице раздела словаря "Сложные слова", попадают в раздел словаря "Изучаемые слова"
+
+ #### Страница статистики
+ - на странице статистики отображается краткосрочная статистика по результатам каждого дня и долгосрочная статистика за весь период изучения
+ - в краткосрочной статистике указывается количество изученных слов, процент правильных ответов и самая длинная серия правильных ответов по каждой мини-игре отдельно, а также общее количество изученных слов и процент правильных ответов за день
+ - в долгосрочной статистике представлены два графика. На одном из них отображается количество изученных слов за каждый день изучения, на другом - увеличение общего количества изученных слов за весь период изучения по дням.
+
+ #### Бекенд
+
+ Что уже есть:
+
+ создан репозиторий с бекендом на его основе создан ReactLearnWords API, позволяющий получить исходные данные
+
+ создана ReactLearnWords wiki с инструкциями по созданию базы данных MongoDB, деплою бекенда на heroku, примерами получения исходных данных
+
+ Что нужно сделать:
+ создать свою копию бекенда. Для этого: форкните репозиторий с бекендом для создания базы данных MongoDB и деплоя бекенда на heroku следуйте туториалам ReactLearnWords wiki
+
+ - вам необходимо добавить в бекенд возможность при регистрации нового пользователя указать его имя и загрузить фото
+
+### Технические требования
+- работа приложения проверяется в браузере Google Chrome последней версии
+- необходимо использовать React
+- можно использовать bootstrap, material design, css-фреймворки, html и css препроцессоры
+- можно использовать js-библиотеки
+- разрешается использовать jQuery только в качесте подключаемой зависимости для UI библиотек. Использование jQuery в основном коде приложения не допускается
+- рекомендуется использовать TypeScript
+- рекомендуется создать и использовать бекенд. Данная рекомендация связана с очень высоким спросом на фронтенд-разработчиков, знакомых хотя бы с основами node.js.
+запрещено копировать код других студентов, демо, примеров, которые приводятся в задании. Этот запрет касается html, css, js кода. Можно использовать небольшие фрагменты кода со Stack Overflow, других самостоятельно найденных источников в интернете, за исключением github-репозиториев студентов курса. Возле использованного чужого фрагмента кода в комментарии указывается ссылка на источник.
+
+### Как сабмитить задание
+Участникам команд необходимо записаться в таблицу, ссылка на которую будет размещена в анонсах
+
+Ссылку на pull request в rs app сабмитит только тимлид
+
+Убедитесь, что pull request доступен для проверки. Для этого откройте ссылку, которую сабмитите в rs app, в режиме инкогнито браузера
+
+Если задание не засабмитить до дедлайна, оно не попадёт на распределение при кросс-чеке и за него не будут выставлены баллы
+
+### Требования к оформлению приложения
+#### особое внимание обратите на качество оформления приложения.
+Как прототип можно использовать подходящие шаблоны, размещённые на behance, dribbble, pinterest
+
+Качественное приложение характеризуется проработанностью деталей, вниманием к типографике (не больше трёх шрифтов на странице, размер шрифта не меньше 14 рх, оптимальная контрастность шрифта и фона), тщательно подобранным контентом
+вёрстка адаптивная. Минимальная ширина страницы, при которой проверяется корректность отображения приложения - 500рх
+
+Интерактивность элементов, с которыми пользователи могут взаимодействовать, изменение внешнего вида самого элемента и состояния курсора при наведении, использование разных стилей для активного и неактивного состояния элемента, плавные анимации
+единство стилей всех страниц приложения - одинаковые шрифты, стили кнопок, отступы, одинаковые элементы на всех страницах приложения имеют одинаковый внешний вид и расположение. Цвет элементов и фоновые изображения могут отличаться. В этом случае цвета используются из одной палитры, а фоновые изображения из одной коллекции.
+
+#### Требования к мини-играм
+- все игры выполнены в одном стиле, при этом в оформлении каждой игры есть индивидуальные отличия (цветовая схема, фоновый рисунок, эффекты анимации и т. д.)
+мини-игру можно развернуть во весь экран
+- по окончанию каждой игры выводятся результаты мини-игры
+- одинаковые элементы игр, такие как результаты мини-игры, блок выбора уровня сложности, стартовый экран, если он есть, и т.д. идентичны по внешнему виду, расположению на странице, функционалу
+- управлять игрой можно как мышкой, так и клавишами на клавиатуре, как это реализовано в оригинальных играх
+- если мини-игра запускается из меню, в ней можно выбрать один из шести уровней сложности, которые отличаются тем, слова какой из шести частей коллекции исходных данных в ней задействованы
+- если мини-игра запускается со страницы учебника, в ней используются слова из той страницы учебника, на которой размещена ссылка на игру. Если размещённых на странице слов для игры недостаточно, задействуются слова с предыдущих страниц
+
+### Критерии оценивания
+
+Максимальный балл за задание 600
+
+500 баллов за приложение
+
+100 баллов за презентацию
+
+Для удобства проверки необходимо записать и разместить на YouTube небольшое (5-7 мин) видео для проверяющих с объяснением как реализован каждый пункт из перечисленных в критериях оценки. Особое внимание обратите на те пункты критериев оценки, которые проверяющий проверить не сможет, например, на то как вы реализовали базу данных, как задеплоили бекенд, как выглядит долгосрочная статистика и т.д. Ссылку на видео можно добавить в описание pull request или в footer приложения добавить иконку YouTube со ссылкой на видео.
+
+При оценивании приложения проверяются все требования, описанные в пунктах Описание функциональных блоков, Требования к оформлению приложения, Требования к мини-играм. Если какие-то из перечисленных требований не выполняются, снимаем часть баллов. В комментарии к оценке необходимо указать какие пункты не выполнены или выполнены частично.
+
+#### Вёрстка, дизайн, UI +40
+- вёрстка, дизайн, UI главной страницы приложения +10
+- вёрстка, дизайн, UI электронного учебника +10
+- вёрстка, дизайн, UI страницы статистики +10
+- оригинальный интересный качественный дизайн приложения +10
+
+#### Главная страница приложения +40
+- меню +10
+- описание возможностей и преимуществ приложения +10
+- видео с демонстрацией работы приложения +10
+- раздел "О команде" +10
+
+#### Электронный учебник +50
+- страницы и разделы учебника +10
+- настройки +10
+- список слов +20
+- навигация по страницам и разделам учебника +10
+
+#### Словарь +40
+- раздел "Изучаемые слова" +20
+- раздел "Сложные слова" +10
+- раздел "Удалённые слова" +10
+
+#### Мини-игры +200 (максимум +50 баллов за каждую игру)
+
+Мини-игра может оцениваться в 30, 40 или 50 баллов.
+
+При оценке предложенной командой игры, её сложность, интересность, полезность, качество реализации сравнивается с другими мини-играми и оценивается по сравнению с ними.
+
+- игра в основном соответствует прототипу, является его упрощённой версией +30
+
+- игра полностью повторяет прототип и детали его работы. Выполняются все перечисленные в задании требования к мини-играм +40
+
+- игра является улучшенной версией прототипа как с точки зрения внешнего вида и оформления, так и удобства работы. Присутствует дополнительный функционал, улучшающий качество приложения +50
+
+#### Страница статистики +40
+
+- краткосрочная статистика +20
+
+- долгосрочная статистика +20
+
+#### Бекенд +60
+
+- собственная копия бекенда размещена на heroku или другом бесплатном хостинге +20
+
+- приложение использует данные из собственного API +10
+
+- при регистрации нового пользователя можно указать его имя. При перезагрузке клиента данные о пользователе сохраняются +10
+
+- при регистрации нового пользователя можно загрузить фото +10
+
+- реализована авторизация и разавторизация пользователя. Основная часть приложения доступна без авторизации. Авторизация необходима только для хранения долгосрочной статистики и формирования словаря +10
+
+#### Дополнительный функционал +30**
+
+- реализован не указанный в задании дополнительный функционал. Оценивается оригинальная идея, вклад в улучшение качества приложения, полезность, сложность и качество выполнения +20
+
+- написано не меньше 10 юнит-тестов, использующих различные методы jest +10