Merge pull request 'redesign' (#32) from redesign into master

Reviewed-on: http://git.plannaplan.pl/y0rune/frontend/pulls/32
Reviewed-by: Maciej <glowackimaciej97@gmail.com>
This commit is contained in:
Maciej 2020-11-20 20:39:22 +01:00
commit 5185315e9a
27 changed files with 698 additions and 437 deletions

View File

@ -1,28 +1,28 @@
module.exports = {
parser: '@typescript-eslint/parser',
extends: [
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended',
'plugin:react-hooks/recommended',
],
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_|^req|^next' }],
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'react/prop-types': 0,
},
settings: {
react: {
version: 'detect',
},
},
};
// module.exports = {
// parser: '@typescript-eslint/parser',
// extends: [
// 'plugin:react/recommended',
// 'plugin:@typescript-eslint/recommended',
// 'prettier/@typescript-eslint',
// 'plugin:prettier/recommended',
// 'plugin:react-hooks/recommended',
// ],
// parserOptions: {
// ecmaVersion: 2020,
// sourceType: 'module',
// ecmaFeatures: {
// jsx: true,
// },
// },
// rules: {
// '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_|^req|^next' }],
// '@typescript-eslint/no-explicit-any': 0,
// '@typescript-eslint/explicit-function-return-type': 0,
// 'react/prop-types': 0,
// },
// settings: {
// react: {
// version: 'detect',
// },
// },
// };

79
package-lock.json generated
View File

@ -2012,71 +2012,6 @@
"resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
"integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw=="
},
"@typescript-eslint/experimental-utils": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.9.1.tgz",
"integrity": "sha512-lkiZ8iBBaYoyEKhCkkw4SAeatXyBq9Ece5bZXdLe1LWBUwTszGbmbiqmQbwWA8cSYDnjWXp9eDbXpf9Sn0hLAg==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/types": "3.9.1",
"@typescript-eslint/typescript-estree": "3.9.1",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
}
},
"@typescript-eslint/parser": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.9.1.tgz",
"integrity": "sha512-y5QvPFUn4Vl4qM40lI+pNWhTcOWtpZAJ8pOEQ21fTTW4xTJkRplMjMRje7LYTXqVKKX9GJhcyweMz2+W1J5bMg==",
"dev": true,
"requires": {
"@types/eslint-visitor-keys": "^1.0.0",
"@typescript-eslint/experimental-utils": "3.9.1",
"@typescript-eslint/types": "3.9.1",
"@typescript-eslint/typescript-estree": "3.9.1",
"eslint-visitor-keys": "^1.1.0"
}
},
"@typescript-eslint/types": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.9.1.tgz",
"integrity": "sha512-15JcTlNQE1BsYy5NBhctnEhEoctjXOjOK+Q+rk8ugC+WXU9rAcS2BYhoh6X4rOaXJEpIYDl+p7ix+A5U0BqPTw==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.9.1.tgz",
"integrity": "sha512-IqM0gfGxOmIKPhiHW/iyAEXwSVqMmR2wJ9uXHNdFpqVvPaQ3dWg302vW127sBpAiqM9SfHhyS40NKLsoMpN2KA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "3.9.1",
"@typescript-eslint/visitor-keys": "3.9.1",
"debug": "^4.1.1",
"glob": "^7.1.6",
"is-glob": "^4.0.1",
"lodash": "^4.17.15",
"semver": "^7.3.2",
"tsutils": "^3.17.1"
},
"dependencies": {
"semver": {
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
"dev": true
}
}
},
"@typescript-eslint/visitor-keys": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.9.1.tgz",
"integrity": "sha512-zxdtUjeoSh+prCpogswMwVUJfEFmCOjdzK9rpNjNBfm6EyPt99x3RrJoBOGZO23FCt0WPKUCOL5mb/9D5LjdwQ==",
"dev": true,
"requires": {
"eslint-visitor-keys": "^1.1.0"
}
},
"@webassemblyjs/ast": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
@ -8794,6 +8729,15 @@
"sort-keys": "^1.0.0"
}
},
"notistack": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.1.tgz",
"integrity": "sha512-2T1WkokzRCM8N9EdueaXja160IMFIMHVhRu0fGkDje7qCzwBHlTMZY2NULQzB2GFOO6iGVzl5GCX2XrJIzI8bw==",
"requires": {
"clsx": "^1.1.0",
"hoist-non-react-statics": "^3.3.0"
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -10636,6 +10580,11 @@
"whatwg-fetch": "^3.0.0"
}
},
"react-click-away-listener": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/react-click-away-listener/-/react-click-away-listener-1.4.3.tgz",
"integrity": "sha512-c7d6mfZuHu/rIdnEHnovX/QsScQXlqtdAynSnZUyyH+6kPOAyB40k2c5br56c/qp4KBkHD0JQV4C7rVuAmroMw=="
},
"react-dev-utils": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz",

View File

@ -9,7 +9,9 @@
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"axios": "^0.19.2",
"notistack": "^1.0.1",
"react": "^16.13.1",
"react-click-away-listener": "^1.4.3",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
"styled-components": "^5.1.1"
@ -21,7 +23,6 @@
"@types/react": "^16.9.46",
"@types/react-dom": "^16.9.8",
"@types/styled-components": "^5.1.2",
"@typescript-eslint/parser": "^3.9.1",
"prettier": "^2.0.5",
"typescript": "^3.9.7"
},

View File

@ -1,22 +1,24 @@
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.svg" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link href="https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
<title>PlanNaPlan</title>
</head>
<body>
<noscript>Potrzebujesz włączyć JavaScript, żeby otworzyć tę aplikację</br>You need to enable JavaScript to run this app.</noscript>
<noscript>Potrzebujesz włączyć JavaScript, żeby otworzyć tę aplikację</br>You need to enable JavaScript to run this
app.</noscript>
<div id="root"></div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

1
src/assets/account.svg Normal file
View File

@ -0,0 +1 @@
<svg height="512pt" viewBox="0 0 512 512.00019" width="512pt" xmlns="http://www.w3.org/2000/svg"><path d="m256 511.996094c-141.484375 0-256-114.65625-256-255.996094 0-141.488281 114.496094-256 256-256 141.488281 0 255.996094 114.496094 255.996094 256 0 141.476562-114.667969 255.996094-255.996094 255.996094zm0 0" fill="#66a9df"/><path d="m256 0v511.996094c141.328125 0 255.996094-114.519532 255.996094-255.996094 0-141.5-114.507813-256-255.996094-256zm0 0" fill="#4f84cf"/><path d="m256 316c-74.488281 0-145.511719 32.5625-197.417969 102.96875 103.363281 124.941406 294.6875 123.875 396.65625-2.230469-25.179687-25.046875-81.894531-100.738281-199.238281-100.738281zm0 0" fill="#d6f3fe"/><path d="m455.238281 416.738281c-48.140625 59.527344-120.371093 95.257813-199.238281 95.257813v-195.996094c117.347656 0 174.058594 75.699219 199.238281 100.738281zm0 0" fill="#bdecfc"/><path d="m256 271c-49.628906 0-90-40.375-90-90v-30c0-49.625 40.371094-90 90-90 49.625 0 90 40.375 90 90v30c0 49.625-40.375 90-90 90zm0 0" fill="#d6f3fe"/><path d="m256 61v210c49.628906 0 90-40.371094 90-90v-30c0-49.628906-40.371094-90-90-90zm0 0" fill="#bdecfc"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
src/assets/bin.svg Normal file
View File

@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m256 441.142c8.284 0 15-6.716 15-15v-201.409c0-8.284-6.716-15-15-15s-15 6.716-15 15v201.409c0 8.284 6.716 15 15 15z"/><path d="m173.412 427.552c.78 8.263 8.115 14.303 16.344 13.523 8.248-.779 14.302-8.096 13.523-16.344l-19.018-201.409c-.779-8.247-8.083-14.303-16.344-13.523-8.248.779-14.302 8.096-13.523 16.344z"/><path d="m322.244 441.076c8.238.779 15.564-5.269 16.344-13.523l19.018-201.409c.779-8.248-5.276-15.565-13.523-16.344-8.26-.784-15.565 5.276-16.344 13.523l-19.018 201.409c-.779 8.247 5.276 15.565 13.523 16.344z"/><path d="m57.646 168.875h8.967l43.448 330.083c.982 7.463 7.344 13.042 14.872 13.042h262.135c7.528 0 13.889-5.579 14.872-13.042l43.448-330.083h8.967c8.284 0 15-6.716 15-15v-65.629c0-8.284-6.716-15-15-15h-128.357v-5.911c0-37.128-30.207-67.335-67.335-67.335h-5.325c-37.128 0-67.335 30.207-67.335 67.335v5.911h-128.357c-8.284 0-15 6.716-15 15v65.629c0 8.284 6.715 15 15 15zm316.267 313.125h-235.826l-41.215-313.125h318.257zm-157.911-414.665c0-20.586 16.749-37.335 37.335-37.335h5.325c20.586 0 37.335 16.749 37.335 37.335v5.911h-79.995zm-143.356 35.911h366.709v35.629c-3.207 0-362.709 0-366.709 0z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 B

41
src/assets/expand.svg Normal file
View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="306px" height="306px" viewBox="0 0 306 306" style="enable-background:new 0 0 306 306;" xml:space="preserve">
<g>
<g id="expand-more">
<polygon points="270.3,58.65 153,175.95 35.7,58.65 0,94.35 153,247.35 306,94.35 "/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 748 B

42
src/assets/poland.svg Normal file
View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 473.677 473.677" style="enable-background:new 0 0 473.677 473.677;" xml:space="preserve">
<path style="fill:#E4E4E4;" d="M324.752,236.842h148.925C473.677,106.032,367.641,0,236.835,0
C302.232,0,324.76,118.425,324.752,236.842z"/>
<path style="fill:#F3F4F5;" d="M0,236.842h334.931C334.939,118.425,302.232,0,236.835,0C106.036,0,0,106.032,0,236.842z"/>
<path style="fill:#D84141;" d="M319.771,236.842c0,118.417-17.535,236.835-82.936,236.835
c130.807,0,236.842-106.036,236.842-236.835H319.771z"/>
<path style="fill:#DC4D4E;" d="M334.931,236.842H0c0,130.799,106.036,236.835,236.835,236.835
C302.232,473.677,334.931,355.26,334.931,236.842z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 473.68 473.68" style="enable-background:new 0 0 473.68 473.68;" xml:space="preserve">
<g>
<path style="fill:#29337A;" d="M41.712,102.641c-15.273,22.168-26.88,47.059-33.918,73.812h107.734L41.712,102.641z"/>
<path style="fill:#29337A;" d="M170.511,9.48c-27.288,7.947-52.56,20.628-74.814,37.168l74.814,74.814V9.48z"/>
<path style="fill:#29337A;" d="M101.261,430.982c20.874,14.607,44.195,25.915,69.25,33.211v-102.45L101.261,430.982z"/>
<path style="fill:#29337A;" d="M10.512,306.771c7.831,25.366,19.831,48.899,35.167,69.833l69.833-69.833H10.512z"/>
</g>
<g>
<path style="fill:#FFFFFF;" d="M45.619,97.144c-1.324,1.81-2.629,3.646-3.908,5.501l73.816,73.812H7.793
c-1.746,6.645-3.171,13.418-4.345,20.284h141.776L45.619,97.144z"/>
<path style="fill:#FFFFFF;" d="M95.767,427.074c1.802,1.343,3.654,2.621,5.493,3.908l69.25-69.242v102.45
c6.653,1.945,13.41,3.624,20.284,4.974V332.05L95.767,427.074z"/>
<path style="fill:#FFFFFF;" d="M5.25,286.487c1.47,6.873,3.205,13.642,5.258,20.284h105.001l-69.833,69.833
c7.595,10.377,16.017,20.115,25.168,29.12L190.08,286.487H5.25L5.25,286.487z"/>
<path style="fill:#FFFFFF;" d="M170.511,9.48v111.982l-74.815-74.81c-10.314,7.67-19.955,16.185-28.888,25.403l123.983,123.983
V4.506C183.921,5.864,177.164,7.547,170.511,9.48z"/>
</g>
<g>
<polygon style="fill:#D32030;" points="170.511,306.056 169.8,306.771 170.511,306.771 "/>
<polygon style="fill:#D32030;" points="190.084,286.487 190.794,286.487 190.794,285.773 "/>
<polygon style="fill:#D32030;" points="281.229,196.737 280.545,196.737 280.545,197.425 "/>
<polygon style="fill:#D32030;" points="171.21,176.457 170.511,175.754 170.511,176.457 "/>
<polygon style="fill:#D32030;" points="190.794,196.037 190.794,196.737 191.494,196.737 "/>
</g>
<g>
<path style="fill:#252F6C;" d="M300.825,411.764v53.091c25.381-7.105,49.045-18.305,70.211-32.897l-57.526-57.526
C308.913,390.583,307.231,398.933,300.825,411.764z"/>
<path style="fill:#252F6C;" d="M313.812,108.471l62.799-62.799C354.05,29.15,328.456,16.559,300.824,8.818v54.538
C308.21,78.146,308.831,89.384,313.812,108.471z"/>
<path style="fill:#252F6C;" d="M427.029,377.984c15.815-21.275,28.141-45.29,36.147-71.213h-107.36L427.029,377.984z"/>
<path style="fill:#252F6C;" d="M465.887,176.457c-7.188-27.318-19.143-52.676-34.898-75.192l-75.2,75.192H465.887z"/>
</g>
<g>
<path style="fill:#E7E7E7;" d="M327.638,290.5l16.275,16.275l77.903,77.903c1.769-2.214,3.526-4.42,5.217-6.69l-71.213-71.213
h107.36c2.046-6.638,3.784-13.41,5.25-20.284H329.16C328.932,289.367,327.911,287.643,327.638,290.5z"/>
<path style="fill:#E7E7E7;" d="M311.352,120.348l70.607-70.615c-1.769-1.372-3.541-2.737-5.348-4.061l-62.799,62.799
C314.463,110.954,310.746,117.805,311.352,120.348z"/>
<path style="fill:#E7E7E7;" d="M300.825,58.992V8.814c-6.645-1.862-13.41-3.44-20.284-4.727v24.476
C288.088,36.745,294.853,47.022,300.825,58.992z"/>
<path style="fill:#E7E7E7;" d="M326.041,196.737h144.195c-1.171-6.866-2.599-13.635-4.345-20.284H355.793l75.2-75.192
C423.6,90.7,415.384,80.768,406.409,71.565l-84.702,84.694C323.988,171.622,325.009,180.544,326.041,196.737z"/>
<path style="fill:#E7E7E7;" d="M310.088,371.002l60.952,60.959c10.138-6.982,19.685-14.753,28.593-23.189l-80.173-80.177
C316.901,343.423,313.865,357.745,310.088,371.002z"/>
<path style="fill:#E7E7E7;" d="M280.545,442.301v27.28c6.873-1.279,13.635-2.865,20.284-4.727v-53.091
C294.853,423.738,288.088,434.13,280.545,442.301z"/>
</g>
<path style="fill:#D71F28;" d="M321.707,156.259l84.694-84.694c-7.625-7.831-15.8-15.119-24.446-21.832l-66.55,66.561
C318.363,128.657,319.706,142.808,321.707,156.259z"/>
<g>
<path style="fill:#D32030;" d="M225.019,0.292C228.965,0.101,232.899,0,236.836,0C232.876,0,228.935,0.101,225.019,0.292z"/>
<path style="fill:#D32030;" d="M236.836,473.68c-3.938,0-7.872-0.108-11.81-0.299C228.942,473.579,232.876,473.68,236.836,473.68z"
/>
<path style="fill:#D32030;" d="M236.836,473.68c14.943,0,29.535-1.447,43.708-4.099v-27.28
C268.103,455.786,253.549,473.68,236.836,473.68z"/>
</g>
<g>
<path style="fill:#D71F28;" d="M470.232,196.737H327.911c1.885,29.704,1.657,60.249-0.681,89.75h141.2
c3.418-16.017,5.25-32.613,5.25-49.643C473.68,223.164,472.461,209.784,470.232,196.737z"/>
<path style="fill:#D71F28;" d="M327.638,290.5c-1.316,13.994-5.901,24.898-8.182,38.099l80.173,80.173
c7.932-7.517,15.347-15.557,22.183-24.094l-77.9-77.907L327.638,290.5z"/>
</g>
<path style="fill:#D32030;" d="M280.545,30.324V4.091C266.376,1.447,251.784,0,236.836,0C253.549,0,268.103,16.843,280.545,30.324z"
/>
<g>
<path style="fill:#29337A;" d="M300.825,422.007c6.406-12.834,11.899-27.609,16.499-43.757l-16.499-16.499V422.007z"/>
<path style="fill:#29337A;" d="M319.377,102.906c-4.989-19.087-11.166-36.439-18.552-51.229v69.773L319.377,102.906z"/>
</g>
<g>
<path style="fill:#FFFFFF;" d="M332.234,295.092c0.269-2.857,0.512-5.725,0.744-8.605h-9.349L332.234,295.092z"/>
<path style="fill:#FFFFFF;" d="M300.825,121.451V51.674c-5.976-11.97-12.737-22.254-20.284-30.429v129.906l40.735-40.735
c-0.613-2.543-1.257-5.034-1.9-7.517L300.825,121.451z"/>
<path style="fill:#FFFFFF;" d="M281.229,196.737h52.429c-1.028-16.192-2.666-32.123-4.944-47.482L281.229,196.737z"/>
<path style="fill:#FFFFFF;" d="M280.545,452.432c7.547-8.182,14.308-18.459,20.284-30.429v-60.256l16.499,16.499
c3.784-13.264,6.959-27.434,9.525-42.261l-46.307-46.304L280.545,452.432L280.545,452.432z"/>
</g>
<path style="fill:#E51D35;" d="M280.545,452.432V289.681l46.304,46.307c2.277-13.205,4.069-26.899,5.381-40.896l-8.605-8.605h9.349
c2.337-29.502,2.565-60.047,0.681-89.75h-52.429l47.482-47.482c-2.001-13.455-4.476-26.469-7.434-38.836l-40.728,40.735V21.248
C268.103,7.763,253.549,0,236.836,0c-3.938,0-7.872,0.101-11.817,0.292c-11.649,0.583-23.073,2.016-34.225,4.215v191.531
L66.808,72.055c-7.618,7.861-14.704,16.237-21.189,25.089l79.313,79.313l20.291,20.284H3.448C1.227,209.784,0,223.164,0,236.844
c0,17.034,1.84,33.626,5.25,49.643h184.834L70.847,405.724c7.808,7.67,16.121,14.813,24.921,21.349l95.023-95.023v137.116
c11.151,2.199,22.583,3.631,34.232,4.215c3.938,0.191,7.872,0.299,11.81,0.299C253.549,473.68,268.103,465.917,280.545,452.432z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

View File

@ -8,6 +8,8 @@ import styled from 'styled-components';
const Wrapper = styled.div`
display: flex;
height: calc(100vh - 80px);
background-color: #ECEEF4;
padding: 20px;
`;
export const App = () => {

View File

@ -1,43 +1,52 @@
import React, { useState, useContext, MouseEvent } from 'react';
import Collapse from '@material-ui/core/Collapse';
import ExpandIcon from '../assets/expand.png';
import { Course, Group, GroupType } from '../types/index';
import { ReactComponent as Expand } from '../assets/expand.svg';
import { Course, Group } from '../types/index';
import { coursesContext } from '../contexts/CoursesProvider';
import styled from 'styled-components';
import { makeStyles } from '@material-ui/core/styles';
import { ReactComponent as CloseIcon } from '../assets/close.svg';
import { ReactComponent as Bin } from '../assets/bin.svg';
interface ClassExandIconProps {
isSelected: boolean;
}
const CourseStyled = styled.div`
const CourseCardWrapper = styled.div`
position: relative;
display: flex;
min-height: 40px;
background-color: rgb(100, 181, 246) !important;
background-color: rgb(100, 181, 246);
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 10px;
padding-top: 10px;
padding-bottom: 10px;
border-radius: 10px;
cursor: pointer;
align-items: stretch;
position: relative;
box-shadow: 9px 9px 8px -2px rgba(0, 0, 0, 0.59);
`;
const CourseNameStyled = styled.div`
padding-top:20px;
padding-bottom:10px;
padding-left:35px;
padding-right:35px;
const TitleWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
`
const BinIcon = styled(Bin)`
width: 20px;
height: 20px;
max-width: 20px;
min-width: 20px;
cursor: pointer;
&:hover {
fill: white;
}
`;
interface ClassGroupProps {
groupType: GroupType;
}
const CourseName = styled.div`
padding-left: 3px;
padding-right: 3px;
font-size: 16px;
user-select: none;
`;
const ClassGroupStyled = styled.div`
position: relative;
@ -45,22 +54,28 @@ position:relative;
padding-bottom: 1px;
:hover {
cursor: pointer;
background-color:#9ED3FF;
background-color: #9ed3ff;
}
`;
const ClassExandIconStyled = styled.img<ClassExandIconProps>`
margin-top: 5px;
interface ExpandIconProps {
isSelected: boolean;
}
const ExpandIcon = styled(Expand) <ExpandIconProps>`
width: 20px;
height: 20px;
max-width: 20px;
min-width: 20px;
transition: 0.2s;
transform: ${(props) => (props.isSelected ? 'scaleY(-1);' : 'scaleY(1);')};
transform: ${({ isSelected }) => (isSelected ? 'scaleY(-1);' : 'scaleY(1);')};
`;
const TypeClass = styled.div`
font-size: 12px;
position: absolute;
border-radius: 15px;
background-color:#00506B;
background-color: #00506b;
border: 2px solid;
min-width: 45px;
top: 5px;
@ -87,16 +102,7 @@ const useStyles = makeStyles({
},
});
const DeleteFromBasketIcon = styled(CloseIcon)`
width: 20px;
cursor: pointer;
position: absolute;
left: 230px;
top: -5px;
&:hover {
fill: white;
}
`;
interface CourseCardProps {
course: Course;
@ -111,24 +117,24 @@ export const CourseCard = ({ course }: CourseCardProps) => {
const onGroupClick = (group: Group, id: number) => addGroup(group, id);
return (
<CourseStyled>
<DeleteFromBasketIcon onClick={() => deleteFromBasket(course.id)}></DeleteFromBasketIcon>
<CourseNameStyled onClick={() => setSelected(!isSelected)}>{course.name}</CourseNameStyled>
<CourseCardWrapper>
<TitleWrapper>
<BinIcon onClick={() => deleteFromBasket(course.id)}></BinIcon>
<CourseName onClick={() => setSelected(!isSelected)}>{course.name}</CourseName>
<ExpandIcon onClick={() => setSelected(!isSelected)} isSelected={isSelected} />
</TitleWrapper>
<Collapse className={classes.expanded} in={isSelected} timeout="auto" unmountOnExit>
{groups
.sort((a, b) => b.type.localeCompare(a.type))
.map((group, index) => (
<ClassGroupStyled key={index} onClick={() => onGroupClick(group, course.id)}>
<TypeClass>{group.type==="CLASS"? "Ćw." : "Wyk."}</TypeClass>
<TypeClass>{group.type === 'CLASS' ? 'Ćw.' : 'Wyk.'}</TypeClass>
<p>
{group.time} {group.room} <br></br> {group.lecturer}
</p>
</ClassGroupStyled>
))}
</Collapse>
<div onClick={() => setSelected(!isSelected)}>
<ClassExandIconStyled isSelected={isSelected} alt="expand" src={ExpandIcon} />
</div>
</CourseStyled>
</CourseCardWrapper>
);
};

View File

@ -1,20 +1,19 @@
import React, { useState, useContext, useEffect, MouseEvent, ChangeEvent } from 'react';
import axios from 'axios';
import { Input } from '@material-ui/core';
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import React, { useState, useContext, useEffect, MouseEvent, forwardRef } from 'react';
import { coursesContext } from '../contexts/CoursesProvider';
import { Course, Basket } from '../types';
import { Course } from '../types';
import styled from 'styled-components';
import { makeStyles } from '@material-ui/core/styles';
const DropdownStyled = styled.div`
const DropdownContainer = styled.div`
position: relative;
z-index: 99999999;
max-height: 420px;
border-radius: 3px;
overflow-y: auto;
box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
z-index: 100;
position: relative;
border-radius:0px 0px 0px 15px;
::-webkit-scrollbar-track {
border-radius: 10px;
background-color: #f5f5f5;
@ -25,70 +24,69 @@ const DropdownStyled = styled.div`
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: #d4b851;
background-color: black;
border: 1px solid;
}
`;
const CourseStyled = styled.div`
position: relative;
z-index: 10;
const CourseContainer = styled.div`
padding: 5px;
padding-left: 20px;
background-color: #e6c759;
background-color: #f2f4f7;
font-size: 18px;
font-family: Lato;
font-weight: 500;
scroll-snap-align: end;
border-bottom:1px solid;
:hover {
background-color: #d4b851;
background-color: #eceef4;
cursor: pointer;
}
`;
const useStyles = makeStyles({
topbarInput: {
marginTop: '8px',
width: '100%',
},
});
interface DropdownProps {
clearInput: boolean;
handleClearInput: () => void;
open: boolean;
input: string;
handleCloseDropdown: () => void;
}
export const Dropdown = ({ clearInput, handleClearInput }: DropdownProps) => {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [input, setInput] = useState<string>('');
export const Dropdown = forwardRef(({ open, input, handleCloseDropdown }: DropdownProps, ref: any) => {
//courses - choosenCourses
const [filteredCourses, setFilteredCourses] = useState<Array<Course>>([]);
const { courses, basket, addToBasket } = useContext(coursesContext)!;
useEffect(() => {
console.log('wut');
}, [open, input, handleCloseDropdown]);
useEffect(() => {
console.log('input is: ', input);
}, [input]);
useEffect(() => {
console.log('is open: ', open);
}, [open]);
useEffect(() => {
const filterCourses = (input: string) => {
const choosenCoursesNames = basket.map(({ name }) => name.trim());
const filteredCourses = courses.filter(
({ name }) => name.toLowerCase().includes(input.toLowerCase()) && !choosenCoursesNames.includes(name),
({ name }) =>
name
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.includes(
input
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, ''),
) && !choosenCoursesNames.includes(name),
);
setFilteredCourses(filteredCourses);
};
console.log("filtering courses");
filterCourses(input);
}, [input, open, basket]);
useEffect(() => {
clearInput && (setInput(''), handleClearInput());
}, [clearInput]);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => setInput(event.target.value);
const handleClick = () => setOpen(true);
const handleClickAway = () => setOpen(false);
}, [open, input, basket]);
const onCourseClick = async (event: MouseEvent) => {
const target = event.currentTarget;
@ -97,31 +95,21 @@ export const Dropdown = ({ clearInput, handleClearInput }: DropdownProps) => {
console.log('added course is');
console.log(course);
addToBasket(course);
setOpen(false);
handleCloseDropdown();
}
};
return (
<ClickAwayListener onClickAway={handleClickAway}>
<div>
<Input
placeholder="Wyszukaj..."
inputProps={{ 'aria-label': 'description' }}
className={classes.topbarInput}
onChange={handleChange}
onClick={handleClick}
value={input}
/>
<DropdownContainer>
{open && (
<DropdownStyled>
<>
{filteredCourses.map(({ name, id }, index) => (
<CourseStyled key={index} id={id.toString()} onClick={onCourseClick}>
<CourseContainer key={index} id={id.toString()} onClick={onCourseClick}>
<p>{name} </p>
</CourseStyled>
</CourseContainer>
))}
</DropdownStyled>
</>
)}
</div>
</ClickAwayListener>
</DropdownContainer>
);
};
});

View File

@ -12,9 +12,8 @@ export const Profile = ({ anchorEl, handleClose }: ProfileProps) => {
return (
<Menu anchorEl={anchorEl} keepMounted open={Boolean(anchorEl)} onClose={handleClose}>
<MenuItem>Profile</MenuItem>
<MenuItem>My account</MenuItem>
<MenuItem onClick={logout}>Logout</MenuItem>
<MenuItem>Profil</MenuItem>
<MenuItem onClick={logout}>Wyloguj</MenuItem>
</Menu>
);
};

View File

@ -1,17 +1,14 @@
import React, { useContext } from 'react';
import Snackbar from '@material-ui/core/Snackbar';
import { CourseCard } from './CourseCard';
import { coursesContext } from '../contexts/CoursesProvider';
import MuiAlert, { AlertProps } from '@material-ui/lab/Alert';
import styled from 'styled-components';
import { debounce } from "lodash";
import { debounce } from 'lodash';
const RightbarStyled = styled.div`
padding-top: 10px;
padding-left: 15px;
padding-right: 15px;
text-align: center;
font-family: Lato;
height: 100%;
width: 300px;
overflow-y: scroll;
@ -25,24 +22,22 @@ const RightbarStyled = styled.div`
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: #d4b851;
background-color: black;
border: 1px solid;
}
background-color: white;
border-radius: 5px;
box-shadow: 3px 3px 3px -2px rgba(0, 0, 0, 0.59);
`;
const RightbarTextStyled = styled.div`
display: flex;
flex-direction: column;
`;
const SaveButton = styled.div`
display: flex;
justify-content: center;
align-items: center;
background-color: #417cab !important;
user-select: none;
background-color: #417cab;
border-radius: 10px;
cursor: pointer;
height: 40px;
background-color: red;
margin-bottom: 10px;
&:hover {
color: white;
@ -50,15 +45,9 @@ const SaveButton = styled.div`
box-shadow: 6px 6px 6px -2px rgba(0, 0, 0, 0.59);
`;
function Alert(props: AlertProps) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
export const Rightbar = () => {
const { courses, basket, saveBasket } = useContext(coursesContext)!;
const [open, setOpen] = React.useState(false);
const getBasketGroups = () => {
const names = basket.map(({ name }) => name);
return courses.filter(({ name }) => names.includes(name));
@ -66,38 +55,15 @@ export const Rightbar = () => {
const filteredCourses = getBasketGroups();
const save = debounce(() => {
saveBasket();
setOpen(true);
console.log("zmiana")
},500);
const handleClose = (event?: React.SyntheticEvent, reason?: string) => {
if (reason === 'clickaway') {
return;
}
setOpen(false);
};
const handleSave = debounce(() => saveBasket(), 500);
//need to insert student name from db and course maybe based on current time or from db too
return (
<RightbarStyled>
<RightbarTextStyled>
<p>
Hubert Wrzesiński<br></br>
Semestr zimowy 2020/2021
</p>
<SaveButton onClick={save}>ZAPISZ</SaveButton>
</RightbarTextStyled>
<SaveButton onClick={handleSave}>ZAPISZ</SaveButton>
{filteredCourses.map((course, index) => (
<CourseCard course={course} key={index} />
))}
<Snackbar open={open} autoHideDuration={5000} onClose={handleClose}>
<Alert onClose={handleClose} severity="success">
Zapisano plan!
</Alert>
</Snackbar>
</RightbarStyled>
);
};

View File

@ -1,4 +1,4 @@
import React, { useEffect, MouseEvent, useRef } from 'react';
import React, { useEffect, MouseEvent, useRef, useCallback, useLayoutEffect } from 'react';
import { useState } from 'react';
import { SchedulerEvents } from './SchedulerEvents';
import { days, hours } from '../constants/index';
@ -6,74 +6,93 @@ import styled from 'styled-components/macro';
const SchedulerWrapper = styled.div`
border-collapse: collapse;
flex-grow: 1;
flex: 1;
background-color: white;
padding: 10px 40px 25px 10px;
border-radius: 5px;
margin-right: 20px;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 3px 3px 3px -2px rgba(0, 0, 0, 0.59);
`;
const TableBody = styled.div`
position: relative;
width: 100%;
display: flex;
flex-direction: column;
height: calc(100% * 25 / 26);
`;
const TableRow = styled.div`
display: flex;
height: 100%;
`;
const TableHead = styled.div`
display: flex;
width: 100%;
height: calc(100% / 26);
`;
interface TableCellProps {
height: number;
cellHeight?: number;
isHourColumn?: boolean;
}
const TableCell = styled.div<TableCellProps>`
height: ${({ height }) => height}px;
border: 1px solid #ddd;
border-width: ${({ isHourColumn }) => !isHourColumn && '2px'};
border-style: ${({ isHourColumn }) => !isHourColumn && 'none solid dotted none'};
border-color: rgb(242, 243, 245);
display: flex;
align-items: center;
justify-content: center;
flex: 1;
font-size: 1.25vw;
`;
const T = styled.table`
width: 100%;
height: 100%;
justify-content: ${({ isHourColumn }) => (isHourColumn ? 'flex-end' : 'center')};
flex: ${({ isHourColumn }) => (isHourColumn ? '1' : '5')};
margin-right: ${({ isHourColumn }) => (isHourColumn ? '10px' : '0px')};
margin-top: ${({ isHourColumn, cellHeight }) => (isHourColumn ? `-${cellHeight}px` : '0px')};
font-size: 0.75vw;
user-select: none;
border-collapse: collapse;
:nth-child(2) {
border-left: 2px solid rgb(242, 243, 245);
}
font-weight: bold;
`;
export const Scheduler = () => {
const cellRef = useRef<HTMLDivElement>(null);
const [cellWidth, setCellWidth] = useState(0);
const [cellTop, setCellTop] = useState(0);
const [cellHeight, setCellHeight] = useState(0);
const wrapperRef = useRef<HTMLDivElement>(null);
const [wrapperHeight, setWrapperHeight] = useState(0);
console.log('cell height: ', cellHeight);
useEffect(() => {
const handleResize = () => {
if (cellRef.current && wrapperRef.current) {
if (cellRef.current) {
setCellWidth(cellRef.current.getBoundingClientRect().width);
setCellTop(cellRef.current.getBoundingClientRect().top);
setWrapperHeight(wrapperRef.current.getBoundingClientRect().height);
setCellHeight(cellRef.current.getBoundingClientRect().height);
cellRef.current.style.backgroundColor = 'blue';
}
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<>
<SchedulerWrapper ref={wrapperRef}>
<SchedulerWrapper>
<TableHead>
{days.map((day, indexCell) =>
indexCell === 0 ? (
<TableCell /* style={{ flexGrow: 1 }} */ height={wrapperHeight / 13} key={indexCell} ref={cellRef}>
<TableCell isHourColumn={true} key={indexCell}>
{day}
</TableCell>
) : (
<TableCell /* style={{ flexGrow: 3 }} */ height={wrapperHeight / 13} key={indexCell} ref={cellRef}>
<TableCell style={{ borderStyle: 'none none solid none' }} key={indexCell}>
{day}
</TableCell>
),
@ -84,19 +103,31 @@ export const Scheduler = () => {
<TableRow key={indexRow}>
{[hour, '', '', '', '', ''].map((value, indexCell) =>
indexCell === 0 ? (
<TableCell /* style={{ flexGrow: 1 }} */ height={wrapperHeight / 13} key={`${indexRow}${indexCell}`}>
<TableCell isHourColumn={true} cellHeight={cellHeight} key={`${indexRow}${indexCell}`}>
{value}
</TableCell>
) : indexRow === 0 && indexCell === 1 ? (
<TableCell ref={cellRef} key={`${indexRow}${indexCell}`}>
{value}
</TableCell>
) : indexRow === 23 ? (
<TableCell style={{ borderBottom: '2px solid rgb(242, 243, 245)' }} key={`${indexRow}${indexCell}`}>
{value}
</TableCell>
) : indexCell === 5 ? (
<TableCell key={`${indexRow}${indexCell}`}>{value}</TableCell>
) : indexRow % 2 !== 0 ? (
<TableCell style={{ borderBottom: '2px solid rgb(242, 243, 245)' }} key={`${indexRow}${indexCell}`}>
{value}
</TableCell>
) : (
<TableCell /* style={{ flexGrow: 3 }} */ height={wrapperHeight / 13} key={`${indexRow}${indexCell}`}>
{value}
</TableCell>
<TableCell key={`${indexRow}${indexCell}`}>{value}</TableCell>
),
)}
</TableRow>
))}
<SchedulerEvents cellTop={cellTop} cellWidth={cellWidth} cellHeight={cellHeight} />
</TableBody>
<SchedulerEvents cellTop={cellTop} cellWidth={cellWidth} cellHeight={wrapperHeight / 13} />
</SchedulerWrapper>
</>
);

View File

@ -11,13 +11,10 @@ interface SchedulerEventsProps {
export const SchedulerEvents = ({ cellTop, cellWidth, cellHeight }: SchedulerEventsProps) => {
const { basket } = useContext(coursesContext)!;
console.log(`values: cellTop: ${cellTop}, cellWidth: ${cellWidth}, cellHeight: ${cellHeight}`);
const [choosenGroupsMappedToEvents, setChoosenGroupsMappedToEvents] = useState<any>([]);
interface GroupTimeToEventRowMapping {
[time: string]: number;
}
const groupTimeToEventRowMapping: GroupTimeToEventRowMapping = {
const groupTimeToEventRowMapping: { [time: string]: number } = {
'8.15': 0,
'10.00': 1,
'11.45': 2,
@ -56,17 +53,17 @@ export const SchedulerEvents = ({ cellTop, cellWidth, cellHeight }: SchedulerEve
indexRow={index}
cellTop={
index === 0
? cellTop + (cellHeight + cellHeight * 2 * index + cellHeight / 4)
? cellHeight / 2
: index === 1
? cellTop + (cellHeight + cellHeight * 2 * index)
? cellHeight * 4
: index === 2
? cellTop + (cellHeight + cellHeight * 2 * index - cellHeight / 4)
? cellHeight * 7.5
: index === 3
? cellTop + (cellHeight + cellHeight * 2 * index - cellHeight / 4)
? cellHeight * 11.5
: index === 4
? cellTop + (cellHeight + cellHeight * 2 * index - cellHeight / 2)
? cellHeight * 15
: index === 5
? cellTop + (cellHeight + cellHeight * 2 * index - (cellHeight * 3) / 4)
? cellHeight * 18.5
: 0
}
cellWidth={cellWidth}

View File

@ -1,4 +1,4 @@
import React, { MouseEvent, useEffect, useState } from 'react';
import React, { MouseEvent, useState } from 'react';
import { Group, GroupType } from '../types';
import styled from 'styled-components/macro';
import Popover from '@material-ui/core/Popover';
@ -18,43 +18,40 @@ const useStyles = makeStyles((theme: Theme) =>
}),
);
interface SchedulerEventProps {
interface ClassesWrapperProps {
eventIndex: number;
cellTop: number;
cellWidth: number;
cellHeight: number;
}
const SchedulerEvent = styled.div<SchedulerEventProps>`
const ClassesWrapper = styled.div<ClassesWrapperProps>`
position: absolute;
display: flex;
top: ${({ cellTop }) => cellTop}px;
left: ${({ cellWidth, eventIndex }) => cellWidth + 5 + cellWidth * eventIndex}px;
width: ${({ cellWidth }) => (cellWidth * 2.5) / 3}px;
height: ${({ cellHeight }) => (cellHeight * 2 * 3) / 4}px;
left: ${({ cellWidth, eventIndex }) => (cellWidth * 1) / 5 + 15 + cellWidth * eventIndex}px;
width: ${({ cellWidth }) => cellWidth - 10}px;
height: ${({ cellHeight }) => cellHeight * 3}px;
z-index: 2;
padding-left: 10px;
`;
interface ClassesProps {
cellWidth: number;
cellHeight: number;
groupType: GroupType;
}
const Classes = styled.div<ClassesProps>`
display: flex;
flex: 1;
justify-content: center;
align-items: center;
z-index: 2;
border-radius: 10px;
font-size:0.90vw;
/* background-color: rgb(100, 181, 246); */
width: ${({ cellWidth }) => (cellWidth * 2.5) / 3}px;
height: ${({ cellHeight }) => (cellHeight * 2 * 3) / 4}px;
height: ${({ cellHeight }) => cellHeight * 3}px;
margin-right: 5px;
text-align: center;
background-color:${({groupType})=>groupType === "CLASS" ? "#FFDC61" : "#A68820"};
text-align: left;
background-color: ${({ groupType }) => (groupType === 'CLASS' ? '#FFDC61' : '#9ed3ff')};
box-shadow: 9px 9px 8px -2px rgba(0, 0, 0, 0.59);
`;
@ -85,9 +82,9 @@ export const SchedulerRow = ({ groups, indexRow, cellTop, cellWidth, cellHeight
const open = Boolean(anchorEl);
return (
<>
<div>
{[...Array(5)].map((_, eventIndex) => (
<SchedulerEvent
<ClassesWrapper
eventIndex={eventIndex}
cellTop={cellTop}
cellWidth={cellWidth}
@ -100,8 +97,10 @@ export const SchedulerRow = ({ groups, indexRow, cellTop, cellWidth, cellHeight
group.day === eventIndex && (
<>
<Classes
onClick={() => {
console.log('group: ', group);
}}
groupType={group.type}
cellWidth={cellWidth}
cellHeight={cellHeight}
id={`eventRow${indexRow}eventCol${eventIndex}${index}`}
key={index}
@ -110,11 +109,10 @@ export const SchedulerRow = ({ groups, indexRow, cellTop, cellWidth, cellHeight
onMouseEnter={(e) => handlePopoverOpen(e)}
onMouseLeave={handlePopoverClose}
>
<p>
{groups[index].name}
<br></br>
{groups[index].room}
</p>
<div>
<p style={{ fontWeight: 700 }}>{groups[index].name}</p>
<p>{groups[index].room}</p>
</div>
</Classes>
<Popover
id={`mouse-over-popover`}
@ -144,8 +142,8 @@ export const SchedulerRow = ({ groups, indexRow, cellTop, cellWidth, cellHeight
</>
),
)}
</SchedulerEvent>
</ClassesWrapper>
))}
</>
</div>
);
};

View File

@ -1,80 +1,111 @@
import React, { useState, MouseEvent } from 'react';
import React, { useState, MouseEvent, ChangeEvent, useEffect } from 'react';
import Transfer from '../assets/transfer.png';
import Search from '../assets/search.svg';
import UK from '../assets/UK.png';
import PL from '../assets/PL.png';
import User from '../assets/user.png';
import CloseIcon from '../assets/close.svg';
import { ReactComponent as Close } from '../assets/close.svg';
import ProfileIcon from '../assets/account.svg';
import { Profile } from './Profile';
import { Dropdown } from './Dropdown';
import styled from 'styled-components';
const TopbarTextStyled = styled.div`
@media only screen and (max-width: 670px) {
display: none;
}
`;
import PolishIcon from '../assets/poland.svg';
import EnglishIcon from '../assets/united-kingdom.svg';
import styled from 'styled-components/macro';
import ClickAwayListener from 'react-click-away-listener';
const Topbar = styled.div`
background-color: #ffdc61;
background-color: #E3E5ED;
height: 80px;
padding: 5px;
font-family: comic sans MS;
font-size: 24px;
font-weight: bold;
display: flex;
justify-content: space-between;
`;
const TopbarLogoWrapperStyled = styled.div`
const LogoWrapper = styled.div`
display: flex;
align-items: center;
flex-grow: 0.5;
justify-content: flex-start;
align-items: center;
flex: 2;
margin-left: 10px;
`;
const TopbarLogoStyled = styled.img`
width: 80px;
height: 80px;
const Logo = styled.img`
width: 70px;
height: 70px;
@media only screen and (max-width: 670px) {
width: 60px;
height: 60px;
}
`;
const TopbarInputStyled = styled.div`
width: 70%;
const Text = styled.div`
margin-left: 10px;
font-size: 1.4rem;
user-select: none;
@media only screen and (max-width: 670px) {
display: none;
}
`;
const FlexboxColumn = styled.div`
display: flex;
flex-grow: 3;
flex-direction: column;
flex: 12;
`;
const TopbarInputFieldStyled = styled.div`
width: 96%;
margin-top: 10px;
const InputWrapper = styled.div`
display: flex;
margin-top: 15px;
background-color: #f2f4f7;
border-radius: 6px;
align-items: center;
`;
const TopbarInputIconStyled = styled.img`
width: 35px;
const Input = styled.input`
background-color: #f1f2f5;
font-size: 20px;
height: 40px;
width: 100%;
border: none;
margin-left: 5px;
border-top-left-radius: 6px;
border-bottom-left-radius: 6px;
&:focus {
outline: none;
}
`;
const CloseIcon = styled(Close)`
width: 30px;
height: 30px;
margin-right: 5px;
@media only screen and (max-width: 670px) {
width: 25px;
}
cursor: pointer;
:hover {
fill: grey;
}
`;
const TopbarIcon = styled.img`
width: 50px;
const IconWrapper = styled.div`
display: flex;
justify-content: flex-end;
align-items: center;
width: 335px;
`;
const Icon = styled.img`
width: 40px;
margin: 5px;
cursor: pointer;
@media only screen and (max-width: 670px) {
width: 35px;
}
`;
const TopbarIconBox = styled.div`
display: flex;
align-items: center;
justify-content: space-around;
flex-grow: 1.5;
`;
interface TopbarProps {
handleTransfer: (e: MouseEvent) => void;
@ -84,6 +115,8 @@ export default function ({ handleTransfer }: TopbarProps) {
const [clearInput, setClearInput] = useState(false);
const [isPolish, setIsPolish] = useState(false);
const [anchorEl, setAnchorEl] = useState<HTMLImageElement | null>(null);
const [open, setOpen] = useState(false);
const [input, setInput] = useState('');
const onLangChange = () => setIsPolish(!isPolish);
@ -93,25 +126,41 @@ export default function ({ handleTransfer }: TopbarProps) {
const handleClearInput = () => setClearInput(!clearInput);
const handleChange = (event: ChangeEvent<HTMLInputElement>) => setInput(event.target.value);
const handleClick = () => setOpen(true);
const handleCloseDropdown = () => setOpen(false);
const handleClickAway = () => setOpen(false);
useEffect(() => {
clearInput && (setInput(''), handleClearInput());
}, [clearInput]);
return (
<Topbar>
<TopbarLogoWrapperStyled>
<TopbarLogoStyled alt="logo" src="https://plannaplan.pl/img/logo.svg" />
<TopbarTextStyled> plan na plan </TopbarTextStyled>
</TopbarLogoWrapperStyled>
<TopbarInputStyled>
<TopbarInputIconStyled alt="search" src={Search} />
<TopbarInputFieldStyled>
<Dropdown clearInput={clearInput} handleClearInput={handleClearInput} />
</TopbarInputFieldStyled>
<TopbarInputIconStyled alt="close" src={CloseIcon} onClick={handleClearInput} />
</TopbarInputStyled>
<TopbarIconBox>
<TopbarIcon alt="transfer" src={Transfer} onClick={handleTransfer} />
<TopbarIcon alt="change_language" src={isPolish ? UK : PL} onClick={onLangChange} />
<TopbarIcon alt="profile" src={User} onClick={handleProfile} />
<LogoWrapper>
<Logo alt="logo" src="https://plannaplan.pl/img/logo.svg" />
<Text> plan na plan </Text>
</LogoWrapper>
<FlexboxColumn>
<ClickAwayListener onClickAway={handleClickAway}>
<InputWrapper>
<Input placeholder="Wyszukaj przedmiot..." onChange={handleChange} onClick={handleClick} value={input} />
<CloseIcon onClick={handleClearInput} />
</InputWrapper>
<Dropdown open={open} input={input} handleCloseDropdown={handleCloseDropdown} />
</ClickAwayListener>
</FlexboxColumn>
<IconWrapper>
{/* <Text>Maciej Głowacki</Text> */}
{/* <Icon alt="transfer" src={Transfer} onClick={handleTransfer} /> */}
<Icon alt="change_language" src={isPolish ? EnglishIcon : PolishIcon} onClick={onLangChange} />
<Icon alt="profile" src={ProfileIcon} onClick={handleProfile} />
<Profile anchorEl={anchorEl} handleClose={handleClose} />
</TopbarIconBox>
</IconWrapper>
</Topbar>
);
}

View File

@ -53,7 +53,6 @@ const TransferReceiveStyled = styled.div`
`;
const TransferTextStyled = styled.div`
font-family: Lato;
font-size: 30px;
margin-bottom: 10px;
`;

View File

@ -8,15 +8,30 @@ export const days = [
];
export const hours = [
"8:00",
"",
"9:00",
"",
"10:00",
"",
"11:00",
"",
"12:00",
"",
"13:00",
"",
"14:00",
"",
"15:00",
"",
"16:00",
"",
"17:00",
"",
"18:00",
"",
"19:00",
"",
];
export const MONDAY_TO_FRIDAY = 5;

View File

@ -1,7 +1,8 @@
import React, { useState, createContext, useEffect, ReactNode, useContext } from 'react';
import { Course, Group, Basket, GroupType } from '../types';
import axios from 'axios';
import { CASContext, CASProvider } from './CASProvider';
import { CASContext } from './CASProvider';
import { useSnackbar } from 'notistack';
interface CourseContext {
courses: Array<Course>;
@ -22,44 +23,73 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
const [courses, setCourses] = useState<Array<Course>>([]);
const [basket, setBasket] = useState<Array<Basket>>([]);
const { enqueueSnackbar } = useSnackbar();
const { closeSnackbar } = useSnackbar();
const CAS = useContext(CASContext)!;
const token = CAS?.user?.token;
const selectBasketIds = (basket: Array<Basket>) => {
const classesIds = basket.map((course) => course.classes.id);
const lecturesIds = basket.map((course) => course?.lecture?.id);
return lecturesIds[0] === undefined ? classesIds : [...classesIds, ...lecturesIds];
};
const addToBasket = (course: Course) => {
const courseToBasket = {
const courseToBasket: Basket = {
name: course.name,
id: course.id,
classes: course.classes[0],
lecture: course.lectures !== undefined ? course.lectures[0] : undefined,
} as Basket;
};
setBasket([...basket, courseToBasket]);
};
const deleteFromBasket = (id: number) => setBasket(basket.filter((course) => course.id !== id));
const saveBasket = async () => {
try {
let data = [7, 43, 54];
let json = JSON.stringify(data);
let post_data = { json_data: json };
const ech = await axios.post<Array<number>>(
`${process.env.REACT_APP_API_URL}/api/v1/commisions/add?`,
[7, 43, 54],
{
const basketIds = selectBasketIds(basket);
const config = {
method: 'post' as const,
url: `${process.env.REACT_APP_API_URL}/api/v1/commisions/add?`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
data: JSON.stringify(basketIds),
};
const action = (key: any) => (
<>
<button
onClick={() => {
closeSnackbar(key);
}}
>
X
</button>
</>
);
console.log('api response;', ech);
try {
await axios.request(config);
enqueueSnackbar('Plan został zapisany', {
variant: 'success',
action,
});
} catch (e) {
console.log(e);
enqueueSnackbar('Zapisywanie planu nie powiodło się', {
variant: 'error',
action,
});
}
console.log('saving to basket');
};
const addGroup = (choosenGroup: Group, id: number) => {
const basketCourse = basket.filter((course) => course.id === id)[0];
const type = choosenGroup.type;
const { type } = choosenGroup;
if (type === GroupType.CLASS) {
setBasket(
basket.map((basket) => (basket.id === basketCourse.id ? { ...basket, classes: choosenGroup } : basket)),
@ -71,23 +101,43 @@ export const CoursesProvider = ({ children }: CoursesProviderProps) => {
}
};
useEffect(() => {
const fetchData = async () => {
const { data } = await axios.get<Array<{ id: string; name: string; groups: Array<Group> }>>(
const getNewestTimetable = async () => {
const config = {
method: 'get' as const,
url: `${process.env.REACT_APP_API_URL}/api/v1/assignments/getCurrentAssignments`,
headers: {
Authorization: `Bearer ${token}`,
},
};
try {
let { data: basket } = await axios.request(config);
if (basket === '') {
basket = [];
}
setBasket(basket);
} catch (e) {
console.log(e);
}
};
const fetchClasses = async () => {
try {
const { data: courses } = await axios.get<Array<Course>>(
`${process.env.REACT_APP_API_URL}/api/v1/courses/getCoursesWithGroups`,
);
const courses = data.map(({ id, name, groups }) => ({
id: parseInt(id),
name,
lectures: groups.filter(({ type }) => type === GroupType.LECTURE),
classes: groups.filter(({ type }) => type === GroupType.CLASS),
})) as Array<Course>;
courses.sort((a: Course, b: Course) => (a.name > b.name ? 1 : -1));
courses.sort((a, b) => (a.name > b.name ? 1 : -1));
setCourses(courses);
} catch (e) {
console.log(e);
}
};
fetchData();
}, []);
useEffect(() => {
fetchClasses();
if (token) {
getNewestTimetable();
}
}, [token]);
return (
<coursesContext.Provider value={{ courses, basket, addToBasket, addGroup, deleteFromBasket, saveBasket }}>

View File

@ -4,15 +4,24 @@ import { App } from './components/App';
import { CASProvider } from './contexts/CASProvider';
import { CoursesProvider } from './contexts/CoursesProvider';
import { GlobalStyles } from './styles/GlobalStyles';
import { SnackbarProvider } from 'notistack';
ReactDOM.render(
<>
<SnackbarProvider
maxSnack={3}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
>
<CASProvider>
<CoursesProvider>
<GlobalStyles />
<App />
</CoursesProvider>
</CASProvider>
</SnackbarProvider>
</>,
document.getElementById('root'),
);

View File

@ -11,7 +11,7 @@ export const GlobalStyles = createGlobalStyle`
margin: 0;
padding: 0;
line-height: 24px;
font-family: 'Roboto', sans-serif;
}
body::-webkit-scrollbar {