├── .gitignore ├── Code of conduct.md ├── Contributing guidelines.md ├── LICENSE ├── README.md ├── backend ├── .idea │ ├── .gitignore │ ├── Log_app.iml │ ├── inspectionProfiles │ │ └── profiles_settings.xml │ ├── misc.xml │ ├── modules.xml │ └── vcs.xml ├── accounts │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ ├── admin.cpython-38.pyc │ │ ├── api.cpython-38.pyc │ │ ├── models.cpython-38.pyc │ │ ├── serializers.cpython-38.pyc │ │ ├── urls.cpython-38.pyc │ │ └── utils.cpython-38.pyc │ ├── admin.py │ ├── api.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_emailuser_username.py │ │ ├── 0003_auto_20201031_2229.py │ │ ├── __init__.py │ │ └── __pycache__ │ │ │ ├── 0001_initial.cpython-38.pyc │ │ │ ├── 0002_emailuser_username.cpython-38.pyc │ │ │ ├── 0003_auto_20201031_2229.cpython-38.pyc │ │ │ └── __init__.cpython-38.pyc │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ ├── utils.py │ └── views.py ├── frontend │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── log_app_django │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-37.pyc │ │ ├── __init__.cpython-38.pyc │ │ ├── settings.cpython-37.pyc │ │ ├── settings.cpython-38.pyc │ │ ├── urls.cpython-37.pyc │ │ ├── urls.cpython-38.pyc │ │ ├── wsgi.cpython-37.pyc │ │ └── wsgi.cpython-38.pyc │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py ├── requirements.txt ├── trucks │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ ├── admin.cpython-38.pyc │ │ ├── api.cpython-38.pyc │ │ ├── apps.cpython-38.pyc │ │ ├── models.cpython-38.pyc │ │ ├── serializers.cpython-38.pyc │ │ └── urls.cpython-38.pyc │ ├── admin.py │ ├── api.py │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0002_auto_20201025_1152.py │ │ ├── 0003_auto_20201025_2132.py │ │ ├── 0004_auto_20201025_2222.py │ │ ├── 0005_auto_20201029_2137.py │ │ ├── __init__.py │ │ └── __pycache__ │ │ │ ├── 0001_initial.cpython-38.pyc │ │ │ ├── 0002_auto_20201025_1152.cpython-38.pyc │ │ │ ├── 0003_auto_20201025_2132.cpython-38.pyc │ │ │ ├── 0004_auto_20201025_2222.cpython-38.pyc │ │ │ ├── 0005_auto_20201029_2137.cpython-38.pyc │ │ │ └── __init__.cpython-38.pyc │ ├── models.py │ ├── serializers.py │ ├── tests.py │ ├── urls.py │ └── views.py └── user.txt ├── docs └── client_docs │ ├── logowanie.pdf │ ├── rejestracja.pdf │ ├── start.pdf │ └── wymiary_przestrzeni_i_ladunkow.xlsx └── frontend ├── .env.development ├── .env.production ├── .eslintrc ├── .prettierrc ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon-apple.png ├── favicon.png └── index.html └── src ├── App.test.js ├── assets └── images │ ├── 404.png │ └── LogAppLogo.png ├── components ├── Header │ ├── Header.jsx │ └── Header.module.scss ├── LoginInfo │ ├── LoginInfo.jsx │ └── LoginInfo.module.scss ├── Message │ ├── Message.jsx │ └── Message.module.scss ├── Modal │ └── Modal.jsx ├── ReturnButton │ ├── ReturnButton.jsx │ └── ReturnButton.module.scss └── Spinner │ ├── Spinner.jsx │ └── Spinner.module.scss ├── helpers └── helpers.jsx ├── index.js ├── serviceWorker.js ├── setupTests.js ├── store └── StoreProvider.jsx └── views ├── Contact ├── Contact.jsx └── Contact.module.scss ├── Error ├── Error.jsx └── Error.module.scss ├── Footer ├── Footer.jsx └── Footer.module.scss ├── FreeStart ├── FreeStart.jsx ├── FreeStart.module.scss └── subcomponents │ ├── InfoDetails.jsx │ ├── LoadDetails.module.scss │ ├── LoadInfo.js │ ├── LoadPopup.jsx │ ├── LoadPopup.module.scss │ ├── LoadsDetails.jsx │ ├── VechicleDetails.jsx │ ├── VechicleDetails.module.scss │ ├── VechicleInfo.js │ ├── VechiclePopup.jsx │ └── VechiclePopup.module.scss ├── Help ├── Help.jsx └── Help.modules.scss ├── Home ├── Home.jsx └── Home.module.scss ├── Login ├── Login.jsx └── Login.module.scss ├── LostPassword ├── LostPassword.jsx └── LostPassword.module.scss ├── Main ├── Main.jsx └── Main.module.scss ├── Registration ├── Registration.jsx └── Registration.module.scss ├── Root ├── Root.js ├── common.scss ├── index.scss ├── mixins.scss ├── reset.scss └── variables.scss └── Start ├── Start.jsx └── Start.module.scss /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,virtualenv,venv,pycharm+iml,pycharm+all,pycharm,dotenv,react 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,virtualenv,venv,pycharm+iml,pycharm+all,pycharm,dotenv,react 5 | 6 | ### dotenv ### 7 | .env 8 | 9 | ### PyCharm ### 10 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 11 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 12 | 13 | # User-specific stuff 14 | .idea/**/workspace.xml 15 | .idea/**/tasks.xml 16 | .idea/**/usage.statistics.xml 17 | .idea/**/dictionaries 18 | .idea/**/shelf 19 | 20 | # Generated files 21 | .idea/**/contentModel.xml 22 | 23 | # Sensitive or high-churn files 24 | .idea/**/dataSources/ 25 | .idea/**/dataSources.ids 26 | .idea/**/dataSources.local.xml 27 | .idea/**/sqlDataSources.xml 28 | .idea/**/dynamic.xml 29 | .idea/**/uiDesigner.xml 30 | .idea/**/dbnavigator.xml 31 | 32 | # Gradle 33 | .idea/**/gradle.xml 34 | .idea/**/libraries 35 | 36 | # Gradle and Maven with auto-import 37 | # When using Gradle or Maven with auto-import, you should exclude module files, 38 | # since they will be recreated, and may cause churn. Uncomment if using 39 | # auto-import. 40 | # .idea/artifacts 41 | # .idea/compiler.xml 42 | # .idea/jarRepositories.xml 43 | # .idea/modules.xml 44 | # .idea/*.iml 45 | # .idea/modules 46 | # *.iml 47 | # *.ipr 48 | 49 | # CMake 50 | cmake-build-*/ 51 | 52 | # Mongo Explorer plugin 53 | .idea/**/mongoSettings.xml 54 | 55 | # File-based project format 56 | *.iws 57 | 58 | # IntelliJ 59 | out/ 60 | 61 | # mpeltonen/sbt-idea plugin 62 | .idea_modules/ 63 | 64 | # JIRA plugin 65 | atlassian-ide-plugin.xml 66 | 67 | # Cursive Clojure plugin 68 | .idea/replstate.xml 69 | 70 | # Crashlytics plugin (for Android Studio and IntelliJ) 71 | com_crashlytics_export_strings.xml 72 | crashlytics.properties 73 | crashlytics-build.properties 74 | fabric.properties 75 | 76 | # Editor-based Rest Client 77 | .idea/httpRequests 78 | 79 | # Android studio 3.1+ serialized cache file 80 | .idea/caches/build_file_checksums.ser 81 | 82 | ### PyCharm Patch ### 83 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 84 | 85 | # *.iml 86 | # modules.xml 87 | # .idea/misc.xml 88 | # *.ipr 89 | 90 | # Sonarlint plugin 91 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 92 | .idea/**/sonarlint/ 93 | 94 | # SonarQube Plugin 95 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 96 | .idea/**/sonarIssues.xml 97 | 98 | # Markdown Navigator plugin 99 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 100 | .idea/**/markdown-navigator.xml 101 | .idea/**/markdown-navigator-enh.xml 102 | .idea/**/markdown-navigator/ 103 | 104 | # Cache file creation bug 105 | # See https://youtrack.jetbrains.com/issue/JBR-2257 106 | .idea/$CACHE_FILE$ 107 | 108 | # CodeStream plugin 109 | # https://plugins.jetbrains.com/plugin/12206-codestream 110 | .idea/codestream.xml 111 | 112 | ### PyCharm+all ### 113 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 114 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 115 | 116 | # User-specific stuff 117 | 118 | # Generated files 119 | 120 | # Sensitive or high-churn files 121 | 122 | # Gradle 123 | 124 | # Gradle and Maven with auto-import 125 | # When using Gradle or Maven with auto-import, you should exclude module files, 126 | # since they will be recreated, and may cause churn. Uncomment if using 127 | # auto-import. 128 | # .idea/artifacts 129 | # .idea/compiler.xml 130 | # .idea/jarRepositories.xml 131 | # .idea/modules.xml 132 | # .idea/*.iml 133 | # .idea/modules 134 | # *.iml 135 | # *.ipr 136 | 137 | # CMake 138 | 139 | # Mongo Explorer plugin 140 | 141 | # File-based project format 142 | 143 | # IntelliJ 144 | 145 | # mpeltonen/sbt-idea plugin 146 | 147 | # JIRA plugin 148 | 149 | # Cursive Clojure plugin 150 | 151 | # Crashlytics plugin (for Android Studio and IntelliJ) 152 | 153 | # Editor-based Rest Client 154 | 155 | # Android studio 3.1+ serialized cache file 156 | 157 | ### PyCharm+all Patch ### 158 | # Ignores the whole .idea folder and all .iml files 159 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 160 | 161 | .idea/ 162 | 163 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 164 | 165 | *.iml 166 | modules.xml 167 | .idea/misc.xml 168 | *.ipr 169 | 170 | # Sonarlint plugin 171 | .idea/sonarlint 172 | 173 | ### PyCharm+iml ### 174 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 175 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 176 | 177 | # User-specific stuff 178 | 179 | # Generated files 180 | 181 | # Sensitive or high-churn files 182 | 183 | # Gradle 184 | 185 | # Gradle and Maven with auto-import 186 | # When using Gradle or Maven with auto-import, you should exclude module files, 187 | # since they will be recreated, and may cause churn. Uncomment if using 188 | # auto-import. 189 | # .idea/artifacts 190 | # .idea/compiler.xml 191 | # .idea/jarRepositories.xml 192 | # .idea/modules.xml 193 | # .idea/*.iml 194 | # .idea/modules 195 | # *.iml 196 | # *.ipr 197 | 198 | # CMake 199 | 200 | # Mongo Explorer plugin 201 | 202 | # File-based project format 203 | 204 | # IntelliJ 205 | 206 | # mpeltonen/sbt-idea plugin 207 | 208 | # JIRA plugin 209 | 210 | # Cursive Clojure plugin 211 | 212 | # Crashlytics plugin (for Android Studio and IntelliJ) 213 | 214 | # Editor-based Rest Client 215 | 216 | # Android studio 3.1+ serialized cache file 217 | 218 | ### PyCharm+iml Patch ### 219 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 220 | 221 | 222 | ### react ### 223 | .DS_* 224 | *.log 225 | logs 226 | **/*.backup.* 227 | **/*.back.* 228 | 229 | node_modules 230 | bower_components 231 | build 232 | 233 | *.sublime* 234 | 235 | psd 236 | thumb 237 | sketch 238 | 239 | ### venv ### 240 | # Virtualenv 241 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 242 | .Python 243 | [Bb]in 244 | [Ii]nclude 245 | [Ll]ib 246 | [Ll]ib64 247 | [Ll]ocal 248 | [Ss]cripts 249 | pyvenv.cfg 250 | .venv 251 | pip-selfcheck.json 252 | 253 | ### VirtualEnv ### 254 | # Virtualenv 255 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 256 | 257 | ### VisualStudioCode ### 258 | .vscode/* 259 | !.vscode/settings.json 260 | !.vscode/tasks.json 261 | !.vscode/launch.json 262 | !.vscode/extensions.json 263 | *.code-workspace 264 | 265 | ### VisualStudioCode Patch ### 266 | # Ignore all local history of files 267 | .history 268 | .ionide 269 | 270 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,virtualenv,venv,pycharm+iml,pycharm+all,pycharm,dotenv,react 271 | 272 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 273 | 274 | venv 275 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 276 | 277 | # dependencies 278 | node_modules 279 | /.pnp 280 | .pnp.js 281 | 282 | # testing 283 | /coverage 284 | 285 | # production 286 | /build 287 | 288 | # misc 289 | .DS_Store 290 | .env.local 291 | .env.development.local 292 | .env.test.local 293 | .env.production.local 294 | 295 | npm-debug.log* 296 | yarn-debug.log* 297 | yarn-error.log* 298 | 299 | debug.log 300 | -------------------------------------------------------------------------------- /Code of conduct.md: -------------------------------------------------------------------------------- 1 | # KODEKS PROJEKTU 2 | 3 | 1. Jesteśmy wszyscy jedną społecznością więc odnosimy się do siebie z szacunkiem 4 | 2. Każdy popełnia błędy, na nich mamy się uczyć 5 | 3. Jeśli możesz komuś pomóc albo ktoś potrzebuje pomocy? POMÓŻ NA TYLE, NA ILE MOŻESZ 6 | 4. Nie wolno przeklinać, obrażać lub wyśmiewać innych 7 | 5. Wszystkie commity opisujemy (co zrobiliśmy, jakie są zmiany) 8 | 6. Jeśli widzimy, że ktoś gdzieś popełnił błąd to zwracamy na to grzecznie uwagę i pomagamy go poprawić 9 | 7. Nie ma głupich pytań, można pytać o wszystko 10 | 8. Nie wstydzimy się poprosić o pomoc 11 | 9. Wszystkie zachowania niepoprawne, niepożądane lub obraźliwe od razu zgłaszamy do rozpatrzenia słuszności skargi 12 | 10. Naruszenie zasad skutkuje usunięciem z projektu 13 | -------------------------------------------------------------------------------- /Contributing guidelines.md: -------------------------------------------------------------------------------- 1 | ## Co będzie ładowane w samochody? 2 | 3 | Wyłącznie ładunki częściowe, tzw. drobnica – nie uwzględniamy ładunków cało pojazdowych. 4 | 5 | ## Wstępny plan aplikacji: 6 | 7 | Projekt ma dwie fazy i trzy główne elementy: 8 | 9 | - Faza i pierwszy element to aplikacja do zarządzania przestrzenią ładunkową pojazdów. 10 | - Faza dwa to elementy, aplikacja do zgłaszania wolnych ładunków i przestrzeni ładunkowych oraz drugi element łączenie jednego z drugim i automatyzacja planowania. 11 | 12 | - Aplikacja do zarządzania przestrzenią ładunkową, jest to najprostszy element, w związku z tym najszybciej do zrobienia i wdrożenia. Założenia to możliwość szybkiego wyboru typowej przestrzeni ładunkowej oraz typowych nośników oraz możliwość rozplanowania ładunku w przestrzeni ręcznie lub automatycznie. Dodatkowa opcja (może nawet płatna) to możliwość ręcznego wprowadzenia wymiarów zarówno przestrzeni jak i wymiarów elementów. Myślę o wersji opisowej na bazie formularzy oraz wersji graficznej na bazie danych z formularzy. Po podaniu wymaganych danych lub wyborze standardów, automat przelicza ile zostanie jeszcze wolnej przestrzeni na wybranej przestrzeni i ma możliwość automatycznego zaplanowania ułożenia. 13 | - Aplikacja do zgłaszania wolnych ładunków i wolnych przestrzeni ładunkowych. Online, zgłoszenia na bazie wyłącznie formularzy z wykorzystaniem bazy danych i możliwości przesyłania formularzy do własnego API. Po przetworzeniu API zwraca informacje na stronę w postaci kolejnych wpisów, można je filtrować po zadanych parametrach. To grubszy temat z wykorzystaniem wiedzy Full stack – głównie w back-end i pewnie dedykowanego serwera. 14 | - Planowanie – to aplikacja na bazie dwóch poprzednich, wykorzystanie wolnej powierzchni ładunkowej „mojego” pojazdu na podstawie danych (zapytań) przesłanych przez klientów w aplikacji do zgłaszania. 15 | 16 | Do tego automat, który kontaktuje się z klientem, potwierdza daty odbiorów, dostaw i ceny. 17 | 18 | ## Faza Pierwsza - (Aplikacja do zarządzania przestrzenią ładunkową pojazdów) funkcje biznesowe: 19 | 20 | 1. Panel logowania 21 | 22 | - Możliwość zalogowania do aplikacji - wtedy dane wyboru użytkownika powinny być zapamiętywane przez program. Użytkownik zalogowany powinien mieć możliwość konfiguracji i zapisu typowych dla siebie parametrów pojazdów. 23 | - Możliwość korzystania z aplikacji bez logowania - użytkownik nie ma możliwości skonfigurowania i zapisania parametrów. 24 | 25 | 2. Panel wyboru środka transportu 26 | 27 | - wybór przestrzeni ładunkowej/środka transportu - tylko możliwość wyboru za pomocą wskazanych przez program opcji z listy (OPCJE*DOSTARCZY*@TM), 28 | - dane liczbowe: długość, szerokość, wysokość, ładowność (DANE*DOSTARCZY*@TM), 29 | - DO_OMÓWIENIA wizualizacja 30 | 31 | 3. Panel wyboru ładunku i miejsca 32 | 33 | - w tym panelu również widoczny środek transportu (jeżeli będzie wizualizacja) i jego kubatura, 34 | - pole wyboru środków ładunkowych - z listy na podstawie typowych danych nośników transportowych (DOSTARCZY\_@TM), ale także wysokość, waga i ilość określana "z ręki". Dodatkowo możliwość wpisania przez użytkownika wszystkich parametrów "z ręki" 35 | - pole wpisywania adresu i daty odbiory i dostawy przesyłki (DO_OMÓWIENIA API GOOGLE MAPS) 36 | 37 | 4. Mechanika aplikacji 38 | 39 | - użytkownik po zalogowaniu (lub nie) widzi panel wyboru pojazdu/przestrzeni ładunkowej, 40 | - po dokonaniu wybory widzi panel wyboru ładunku, miejsca i daty, podczas wyboru może cofnąć się i zmienić pojazd - dla nie zalogowanych zaczyna od początku, dla zalogowanych program pyta czy zapisać dotychczasowy postęp załadunku 41 | - każdorazowo po dokonaniu wybory ładunku, miejsca i daty klika "załaduj", jeżeli nie to ten wybór nie będzie brany pod uwagę przez program 42 | - po kliknięciu "załaduj" program dokonuje obliczeń i aktualizuje przestrzeń ładunkową i routing (trasę) (DO_OMÓWIENIA - czy od razu opcja aktualizacji trasy, będzie pisana) 43 | 44 | 5. Obliczenia programu (bez aktualizacji trasy) 45 | 46 | - na podstawie wprowadzonych lub wybranych danych przez użytkownika przeliczają się wartości przestrzeni ładunkowej pojazdu: szerokość _ długość _ wysokość 47 | - dane te ograniczają możliwość załadunku towaru do wielkości przestrzeni ładunkowej 48 | - przykład wymiarów naczepy ciężarowej: 250cm szerokości 1360cm długości 275cm wysokości 49 | - standardowa i podstawowa jednostka opakowania w logistyce to euro-paleta o wymiarach 120cm _ 80cm _ Xcm(wysokość palety) 50 | - na środek transportowy o podanych wyżej wymiarach można załadować maksymalnie 33 euro-palety o przykładowej wysokości X=200cm, wynika to z obliczenia że dwie palety obok siebie zajmują 120 \* 2 czyli 240cm (co jest mniejsze od szerokości naczepy wynoszącej 250cm), na długość 80cm. zatem 30 palet to prostokąt o długości 1200cm i szerokości 240cm. Pozostaje wolne miejsce o wymiarach długość: 1360cm - 1200cm = 160cm 8 szerokość 250cm - tu sa ładowane 3 ostatnie palety: 80cm + 80cm + 80cm - co daje 240cm < 250cm na długość 120cm. 51 | - na podstawie powyższego obliczenia należy zaprogramować działanie aplikacji w taki sposób, aby w momencie wybrania ładunku i kliknięcia przycisku "załaduj" obliczała ona: 1. ile pozostało wolnego miejsca po ostatnim załadunku względem wybranej przestrzeni ładunkowej 2. Czy wymiary podanego ładunku zmieszczą się na pozostałą przestrzeń 3. Ile pozostanie wolnej przestrzeni po załadunku. 52 | - Nie poruszono tu kwestii piętrowania palet, związanego z ich wysokością - będzie to doprecyzowane. 53 | - każdorazowe dodanie kolejnego elementu (palet) i kliknięcie "załaduj" powoduje kolejne obliczenia. 54 | - brak miejsca: w momencie kiedy użytkownik doda kolejne elementy(palety), a program ustali ze nie ma już miejsca, musi poinformować użytkownika ile miejsca pozostało i co z wybranych elementów jeszcze można załadować 55 | 56 | - Przykład: 57 | szerokość przestrzeni ładunkowej pojazdu = 2,5m 58 | długość = 10m 59 | wysokość = 2,6m 60 | 61 | Ładujemy: 1. 5 palet 1,2m szer. 0,8m dł. 2,2m wys. - po przeliczeniu pozostaje nam 7,6m przestrzeni o szerokości 2,5m - gdybyśmy załadowali 6 palet wynik byłby taki sam. To jedno puste miejsce zostaje w pamięci programu i jest wypełnieniem przy kolejnym ładowaniu. 2. do załadowanych 5 palet dorzucamy 3 kolejne 1,2m szer 1m dł 2m wys. - po przeliczeniu pozostaje 6,4m długości (pierwsze puste miejsce zostało zmatchowane i uzupełnione). 62 | 63 | - Piętrowanie palet. To opcja wyboru - zawsze "z ręki", po wprowadzeniu ilości i wymiarów, klient może wybrać opcje piętrowanie - opcja ta dotyczy tylko danych wprowadzony w jednym cyklu, czyli przed kliknięciem załaduj. Program sprawdza czy podana wysokość palety/elementu może być podwojona względem wysokości pojazdu, jeżeli tak dzieli załadowany towar przez 2 z uwzględnieniem modulo. Tzn jeżeli mam parzystą ilość palet/elementów dziel przez 2, jeżeli nieparzysta, dzieli przez dwa i reszta 1. 64 | 65 | - Przykład: 66 | szerokość przestrzeni ładunkowej pojazdu = 2,5m 67 | długość = 10m 68 | wysokość = 2,6m 69 | 70 | Ładujemy: 1. 5 palet 1,2m szer. 0,8m dł. 1m wys - klikamy piętrować - program sprawdza czy 2 razy wysokość palet jest mniejsza niż wysokość przestrzeni ładunkowej - po przeliczeniu pozostaje 8,4m wolnej długości (w tym jedno miejsce w pamięci aplikacji do ew. uzupełnienia) 2. dorzucamy 3 kolejne palety 1,2 0,8 2m wys - klikamy piętrować - program informuje że nie da się tej wysokości spiętrować - po przeliczeniu pozostaje 7,6m długości (puste miejsce z pamięci zostało uzupełnione). 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 logappopen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LOGAPP 2 | 3 | Stworzenie tego projektu ma na celu głównie naukę i pomoc początkującym programistom, którzy rozpoczynają swoją przygodę z programowaniem. 4 | Celem jest stworzenie w pełni funkcjonalnej aplikacji do zarządzania ładunkami samochodowymi. 5 | Zaproszeni do udziału w projekcie są wszyscy chętni. Zależy nam najbardziej na juniorach, którzy będą mogli się pochwalić swoją pracą przy rozmowach rekrutacyjnych. 6 | 7 | ### TECHNOLOGIE 8 | 9 | To jest początek więc, żadne technologie nie są wybrane. Przez pierwszy tydzień będzie robiona "burza mózgów". Po tej dyskusji wybierzemy coś i będziemy używać wybranych technologii. 10 | 11 | ### KOMUNIKACJA 12 | 13 | W chwili obecnej utworzony jest specjalny kanał na slacku dla tego projektu. Projekt jest w fazie omawiania pracy, wyglądu i podziału ról. 14 | 15 | Link do slacka poniżej: 16 | - [Slack projektu](https://join.slack.com/t/log-app/shared_invite/zt-hgc78zat-Yev3TwDOhxqyAeDp5oO2xg "Slack projektu") 17 | 18 | Osoby chętne mogą też się zwracać bezpośrednio do "opiekunów" projektu poprzez e-mail. 19 | - [Marek Książek](mailto:marek.ksiazek1990@gmail.com) 20 | - [Tomasz Matras](mailto:tomasz.matras@developerweb.pl) 21 | 22 | ## ZAPRASZAM DO WSPÓŁPRACY 23 | 24 | P.S. Plik README będzie rósł z czasem ;) 25 | -------------------------------------------------------------------------------- /backend/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | /venv -------------------------------------------------------------------------------- /backend/.idea/Log_app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /backend/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /backend/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | -------------------------------------------------------------------------------- /backend/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /backend/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /backend/accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__init__.py -------------------------------------------------------------------------------- /backend/accounts/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/admin.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/admin.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/api.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/api.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/models.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/models.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/serializers.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/serializers.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/urls.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/urls.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/__pycache__/utils.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/__pycache__/utils.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.contrib.auth.admin import UserAdmin 3 | 4 | from .models import EmailUser 5 | 6 | # Register your models here. 7 | admin.site.register(EmailUser) 8 | 9 | class CustomUserAdmin(UserAdmin): 10 | model = EmailUser 11 | list_display = ('username' 'email', 'is_staff', 'is_active',) 12 | list_filter = ('username', 'email', 'is_staff', 'is_active',) 13 | fieldsets = ( 14 | (None, {'fields': ('email', 'password')}), 15 | ('Permissions', {'fields': ('is_staff', 'is_active')}), 16 | ) 17 | add_fieldsets = ( 18 | (None, { 19 | 'classes': ('wide',), 20 | 'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active')} 21 | ), 22 | ) 23 | search_fields = ('email',) 24 | ordering = ('email',) 25 | -------------------------------------------------------------------------------- /backend/accounts/api.py: -------------------------------------------------------------------------------- 1 | import os 2 | from rest_framework import generics, permissions, status 3 | from rest_framework.response import Response 4 | from knox.models import AuthToken 5 | from django.contrib.auth.tokens import PasswordResetTokenGenerator 6 | from django.utils.encoding import smart_str, force_str, smart_bytes, DjangoUnicodeDecodeError 7 | from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode 8 | from django.contrib.sites.shortcuts import get_current_site 9 | from django.urls import reverse 10 | from django.http import HttpResponsePermanentRedirect 11 | # from django.shortcuts import redirect 12 | 13 | 14 | from .models import EmailUser 15 | from .serializers import UserSerializer, RegisterSerializer, LoginSerializer, ResetPasswordEmailRequestSerializer, SetNewPasswordSerializer 16 | from .utils import Util 17 | 18 | 19 | class CustomRedirect(HttpResponsePermanentRedirect): 20 | 21 | allowed_schemes = [os.environ.get('APP_SCHEME'), 'http', 'https'] 22 | 23 | 24 | # Register API 25 | class RegisterAPI(generics.GenericAPIView): 26 | serializer_class = RegisterSerializer 27 | 28 | def post(self, request, *args, **kwargs): 29 | serializer = self.get_serializer(data=request.data) 30 | serializer.is_valid(raise_exception=True) 31 | 32 | user = serializer.save() 33 | user_data = serializer.data 34 | 35 | user_email = EmailUser.objects.get(email=user_data['email']) 36 | user_name = EmailUser.objects.get(username=user_data['username']) 37 | 38 | 39 | email_body = 'Hi ' + user_name.username + ', thanks for registering' 40 | # email_body = 'Hi, thanks for registering' 41 | 42 | data = { 43 | 'email_body': email_body, 44 | 'to_email': user_email.email, 45 | 'email_subject': 'Hello there...' 46 | } 47 | 48 | Util.send_email(data) 49 | 50 | return Response({ 51 | "user": UserSerializer(user, context=self.get_serializer_context()).data, 52 | "token": AuthToken.objects.create(user)[1] 53 | }) 54 | 55 | 56 | 57 | 58 | # Login API 59 | class LoginAPI(generics.GenericAPIView): 60 | serializer_class = LoginSerializer 61 | 62 | def post(self, request, *args, **kwargs): 63 | serializer = self.get_serializer(data=request.data) 64 | serializer.is_valid(raise_exception=True) 65 | user = serializer.validated_data 66 | return Response({ 67 | "user": UserSerializer(user, context=self.get_serializer_context()).data, 68 | "token": AuthToken.objects.create(user)[1] 69 | }) 70 | 71 | 72 | # Get User API 73 | class UserAPI(generics.RetrieveAPIView): 74 | permission_classes = [ 75 | permissions.IsAuthenticated, 76 | ] 77 | serializer_class = UserSerializer 78 | 79 | def get_object(self): 80 | return self.request.user 81 | 82 | 83 | # Password reset request 84 | class RequestPasswordResetEmail(generics.GenericAPIView): 85 | serializer_class = ResetPasswordEmailRequestSerializer 86 | 87 | def post(self, request): 88 | serializer = self.serializer_class(data=request.data) 89 | email = request.data['email'] 90 | 91 | if EmailUser.objects.filter(email=email).exists(): 92 | user = EmailUser.objects.get(email=email) 93 | uidb64 = urlsafe_base64_encode(smart_bytes((user.id))) 94 | token = PasswordResetTokenGenerator().make_token(user) 95 | current_site = get_current_site(request=request).domain 96 | relativeLink = reverse('password-reset-confirm', kwargs={'uidb64': uidb64, 'token': token}) 97 | redirect_url = request.data.get('redirect_url', '') 98 | absurl = 'http://' + current_site + relativeLink 99 | email_body = 'Hello, \n Use link below to reset your password \n' + absurl + "?redirect+url=" + redirect_url 100 | data = { 101 | 'email_body': email_body, 102 | 'to_email': user.email, 103 | 'email_subject': 'Reset yor password' 104 | } 105 | 106 | Util.send_email(data) 107 | return Response({'success': 'We have send you link to reset your password'}, status=status.HTTP_200_OK) 108 | else: 109 | return Response({'error': 'There is no such email in database'}, status=status.HTTP_401_UNAUTHORIZED) 110 | 111 | 112 | class PasswordTokenCheckAPI(generics.GenericAPIView): 113 | serializer_class = SetNewPasswordSerializer 114 | 115 | def get(self, request, uidb64, token): 116 | redirect_url = request.GET.get('redirect_url') 117 | 118 | try: 119 | id = smart_str(urlsafe_base64_decode(uidb64)) 120 | user = EmailUser.objects.get(id=id) 121 | 122 | if not PasswordResetTokenGenerator().check_token(user, token): 123 | if len(redirect_url) > 3: 124 | return CustomRedirect(redirect_url + '?token_valid=False') 125 | else: 126 | return CustomRedirect(os.environ.get('FRONTEND_URL', '') + '?token_valid=False') 127 | 128 | if redirect_url and len(redirect_url) > 3: 129 | return CustomRedirect(redirect_url+'?token_valid=True&message=Credentials Valid&uidb64='+uidb64+'&token='+token) 130 | else: 131 | return CustomRedirect(os.environ.get('FRONTEND_URL', '')+'?token_valid=True') 132 | 133 | except DjangoUnicodeDecodeError as identifier: 134 | try: 135 | if not PasswordResetTokenGenerator().check_token(user): 136 | return CustomRedirect(redirect_url+'?token_valid=False') 137 | except UnboundLocalError as e: 138 | return Response({'error': 'Token is not valid, please request a new one'}, status=status.HTTP_400_BAD_REQUEST) 139 | 140 | 141 | class SetNewPasswordAPIView(generics.GenericAPIView): 142 | serializer_class = SetNewPasswordSerializer 143 | 144 | def patch(self, request): 145 | serializer = self.serializer_class(data=request.data) 146 | serializer.is_valid(raise_exception=True) 147 | return Response({'success': True, 'message': 'Password reset success'}, status=status.HTTP_200_OK) 148 | 149 | -------------------------------------------------------------------------------- /backend/accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | name = 'accounts' 6 | -------------------------------------------------------------------------------- /backend/accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-29 20:37 2 | 3 | from django.db import migrations, models 4 | import django.utils.timezone 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | initial = True 10 | 11 | dependencies = [ 12 | ('auth', '0012_alter_user_first_name_max_length'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='EmailUser', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('password', models.CharField(max_length=128, verbose_name='password')), 21 | ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), 22 | ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), 23 | ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), 24 | ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), 25 | ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), 26 | ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), 27 | ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), 28 | ('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')), 29 | ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), 30 | ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 31 | ], 32 | options={ 33 | 'verbose_name': 'user', 34 | 'verbose_name_plural': 'users', 35 | 'abstract': False, 36 | }, 37 | ), 38 | ] 39 | -------------------------------------------------------------------------------- /backend/accounts/migrations/0002_emailuser_username.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-30 22:12 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('accounts', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='emailuser', 15 | name='username', 16 | field=models.CharField(db_index=True, default=None, max_length=255, unique=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/accounts/migrations/0003_auto_20201031_2229.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-31 21:29 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('accounts', '0002_emailuser_username'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AlterField( 14 | model_name='emailuser', 15 | name='username', 16 | field=models.CharField(db_index=True, default=None, max_length=255, unique=True, verbose_name='login'), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /backend/accounts/migrations/__pycache__/0001_initial.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/migrations/__pycache__/0001_initial.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/migrations/__pycache__/0002_emailuser_username.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/migrations/__pycache__/0002_emailuser_username.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/migrations/__pycache__/0003_auto_20201031_2229.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/migrations/__pycache__/0003_auto_20201031_2229.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/migrations/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/accounts/migrations/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /backend/accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.models import BaseUserManager, AbstractUser 2 | from django.db import models 3 | from django.contrib.auth import get_user_model 4 | 5 | 6 | class CustomUserManager(BaseUserManager): 7 | """ 8 | Custom user model manager where email is the unique identifiers 9 | for authentication instead of usernames. 10 | """ 11 | def create_user(self, username, email, password, **kwargs): 12 | """ 13 | Create and save a User with the given email and password. 14 | """ 15 | if username is None: 16 | raise TypeError('Users should have a username') 17 | if not email: 18 | raise ValueError('The email must be sent') 19 | user = self.model(username=username, email=self.normalize_email(email)) 20 | user.set_password(password) 21 | user.save() 22 | return user 23 | 24 | 25 | def create_superuser(self, username, email, password, **kwargs): 26 | """ 27 | Create and save a SuperUser with the given email and password. 28 | """ 29 | if username is None: 30 | raise TypeError('Users should have a username') 31 | if password is None: 32 | raise TypeError('Password should not be none') 33 | 34 | user = self.create_user(username, email, password) 35 | user.is_superuser = True 36 | user.is_staff = True 37 | user.save() 38 | return user 39 | 40 | 41 | class EmailUser(AbstractUser): 42 | username = models.CharField('login', max_length=255, unique=True, db_index=True, default=None) 43 | email = models.EmailField('email address', unique=True) 44 | 45 | USERNAME_FIELD = 'email' 46 | REQUIRED_FIELDS = ['username'] 47 | 48 | objects = CustomUserManager() 49 | 50 | def __str__(self): 51 | return self.email 52 | 53 | 54 | EmailUser = get_user_model() -------------------------------------------------------------------------------- /backend/accounts/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from django.contrib.auth import authenticate 3 | from rest_framework.exceptions import AuthenticationFailed 4 | from django.contrib.auth.tokens import PasswordResetTokenGenerator 5 | from django.utils.encoding import smart_str, force_str, smart_bytes, DjangoUnicodeDecodeError 6 | from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode 7 | 8 | from .models import EmailUser 9 | 10 | 11 | # User Serializer 12 | class UserSerializer(serializers.ModelSerializer): 13 | class Meta: 14 | model = EmailUser 15 | fields = ('id', 'email', 'username') 16 | 17 | 18 | # Register Serializer 19 | class RegisterSerializer(serializers.ModelSerializer): 20 | class Meta: 21 | model = EmailUser 22 | fields = ('id', 'username', 'email', 'password') 23 | extra_kwargs = {'password': {'write_only': True}} 24 | 25 | def create(self, validated_data): 26 | user = EmailUser.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password']) 27 | 28 | return user 29 | 30 | 31 | # Login Serializer 32 | class LoginSerializer(serializers.Serializer): 33 | email = serializers.EmailField() 34 | password = serializers.CharField() 35 | 36 | def validate(self, data): 37 | user = authenticate(**data) 38 | if user and user.is_active: 39 | return user 40 | raise serializers.ValidationError("Incorrect Credentials") 41 | 42 | 43 | class ResetPasswordEmailRequestSerializer(serializers.Serializer): 44 | email = serializers.EmailField(min_length=2) 45 | 46 | redirect_url = serializers.CharField(max_length=500, required=False) 47 | 48 | class Meta: 49 | fields = ['email'] 50 | 51 | 52 | class SetNewPasswordSerializer(serializers.Serializer): 53 | password = serializers.CharField(min_length=6, max_length=68, write_only=True) 54 | token = serializers.CharField(min_length=1, write_only=True) 55 | uidb64 = serializers.CharField(min_length=1, write_only=True) 56 | 57 | class Meta: 58 | fields = ['password', 'token', 'uidb64'] 59 | 60 | def validate(self, attrs): 61 | try: 62 | password = attrs.get('password') 63 | token = attrs.get('token') 64 | uidb64 = attrs.get('uidb64') 65 | 66 | id = force_str(urlsafe_base64_decode(uidb64)) 67 | user = EmailUser.objects.get(id=id) 68 | 69 | if not PasswordResetTokenGenerator().check_token(user, token): 70 | raise AuthenticationFailed('The reset link is invalid', 401) 71 | 72 | user.set_password(password) 73 | user.save() 74 | 75 | return user 76 | except Exception as e: 77 | raise AuthenticationFailed('The reset link is invalid', 401) 78 | return super().validate(attrs) -------------------------------------------------------------------------------- /backend/accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from .api import RegisterAPI, LoginAPI, UserAPI, RequestPasswordResetEmail, PasswordTokenCheckAPI, SetNewPasswordAPIView 3 | from knox import views as knox_views 4 | 5 | urlpatterns = [ 6 | path('api/auth/', include('knox.urls')), 7 | path('api/auth/register', RegisterAPI.as_view()), 8 | path('api/auth/login', LoginAPI.as_view()), 9 | path('api/auth/user', UserAPI.as_view()), 10 | path('api/auth/logout', knox_views.LogoutView.as_view(), name='knox_logout'), 11 | path('api/request-reset-email', RequestPasswordResetEmail.as_view()), 12 | path('api/password-reset//', PasswordTokenCheckAPI.as_view(), name='password-reset-confirm'), 13 | path('api/password-reset-complete', SetNewPasswordAPIView.as_view(), name='password-reset-complete'), 14 | ] 15 | -------------------------------------------------------------------------------- /backend/accounts/utils.py: -------------------------------------------------------------------------------- 1 | from django.core.mail import EmailMessage 2 | import threading 3 | 4 | 5 | class EmailThread(threading.Thread): 6 | 7 | def __init__(self, email): 8 | self.email = email 9 | threading.Thread.__init__(self) 10 | 11 | def run(self): 12 | self.email.send() 13 | 14 | 15 | class Util: 16 | @staticmethod 17 | def send_email(data): 18 | email = EmailMessage(subject=data['email_subject'], body=data['email_body'], to=[data['to_email']]) 19 | EmailThread(email).start() -------------------------------------------------------------------------------- /backend/accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /backend/frontend/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/frontend/__init__.py -------------------------------------------------------------------------------- /backend/frontend/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /backend/frontend/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class FrontendConfig(AppConfig): 5 | name = 'frontend' 6 | -------------------------------------------------------------------------------- /backend/frontend/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/frontend/migrations/__init__.py -------------------------------------------------------------------------------- /backend/frontend/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /backend/frontend/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/frontend/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /backend/log_app_django/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__init__.py -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/settings.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/settings.cpython-37.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/settings.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/settings.cpython-38.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/urls.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/urls.cpython-37.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/urls.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/urls.cpython-38.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/wsgi.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/wsgi.cpython-37.pyc -------------------------------------------------------------------------------- /backend/log_app_django/__pycache__/wsgi.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/log_app_django/__pycache__/wsgi.cpython-38.pyc -------------------------------------------------------------------------------- /backend/log_app_django/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for log_app_django project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'log_app_django.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /backend/log_app_django/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for log_app_django project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.1.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.1/ref/settings/ 11 | """ 12 | 13 | from pathlib import Path 14 | from dotenv import load_dotenv 15 | from os import getenv 16 | 17 | load_dotenv() 18 | 19 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 20 | BASE_DIR = Path(__file__).resolve().parent.parent 21 | 22 | 23 | # Quick-start development settings - unsuitable for production 24 | # See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/ 25 | 26 | # SECURITY WARNING: keep the secret key used in production secret! 27 | SECRET_KEY = 'gsi%7o57z=^0*@1itd3x8o=8!=ho_&&_hrj(72z+!c-&v&mk4t' 28 | 29 | # SECURITY WARNING: don't run with debug turned on in production! 30 | DEBUG = True 31 | 32 | ALLOWED_HOSTS = [] 33 | 34 | AUTH_USER_MODEL = 'accounts.EmailUser' 35 | 36 | # Application definition 37 | 38 | INSTALLED_APPS = [ 39 | # 'trucks.apps.TrucksConfig', 40 | 'django.contrib.admin', 41 | 'django.contrib.auth', 42 | 'django.contrib.contenttypes', 43 | 'django.contrib.sessions', 44 | 'django.contrib.messages', 45 | 'django.contrib.staticfiles', 46 | 47 | 'rest_framework', 48 | 'corsheaders', 49 | 'accounts', 50 | 'trucks', 51 | 'knox', 52 | 53 | ] 54 | 55 | REST_FRAMEWORK = { 56 | 'DEFAULT_AUTHENTICATION_CLASSES': [ 57 | # 'rest_framework.authentication.BasicAuthentication', 58 | # 'rest_framework.authentication.SessionAuthentication', 59 | 'knox.auth.TokenAuthentication', 60 | ] 61 | } 62 | 63 | MIDDLEWARE = [ 64 | 'django.middleware.security.SecurityMiddleware', 65 | 'django.contrib.sessions.middleware.SessionMiddleware', 66 | 'corsheaders.middleware.CorsMiddleware', 67 | 'django.middleware.common.CommonMiddleware', 68 | 'django.middleware.common.CommonMiddleware', 69 | 'django.middleware.csrf.CsrfViewMiddleware', 70 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 71 | 'django.contrib.messages.middleware.MessageMiddleware', 72 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 73 | ] 74 | 75 | ROOT_URLCONF = 'log_app_django.urls' 76 | 77 | TEMPLATES = [ 78 | { 79 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 80 | 'DIRS': [], 81 | 'APP_DIRS': True, 82 | 'OPTIONS': { 83 | 'context_processors': [ 84 | 'django.template.context_processors.debug', 85 | 'django.template.context_processors.request', 86 | 'django.contrib.auth.context_processors.auth', 87 | 'django.contrib.messages.context_processors.messages', 88 | ], 89 | }, 90 | }, 91 | ] 92 | 93 | WSGI_APPLICATION = 'log_app_django.wsgi.application' 94 | 95 | 96 | # Database 97 | # https://docs.djangoproject.com/en/3.1/ref/settings/#databases 98 | 99 | # DATABASES = { 100 | # 'default': { 101 | # 'ENGINE': 'django.db.backends.sqlite3', 102 | # 'NAME': BASE_DIR / 'db.sqlite3', 103 | # } 104 | # } 105 | DATABASES = { 106 | 'default': { 107 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 108 | 'NAME': 'postgres_test_logapp', 109 | 'USER': 'postgres', 110 | 'PASSWORD': 'admin1', 111 | 'HOST': 'localhost', 112 | 'PORT': '5432', 113 | } 114 | } 115 | 116 | 117 | # Password validation 118 | # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators 119 | 120 | AUTH_PASSWORD_VALIDATORS = [ 121 | { 122 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 123 | }, 124 | { 125 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 126 | }, 127 | { 128 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 129 | }, 130 | { 131 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 132 | }, 133 | ] 134 | 135 | 136 | # Internationalization 137 | # https://docs.djangoproject.com/en/3.1/topics/i18n/ 138 | 139 | LANGUAGE_CODE = 'en-us' 140 | 141 | TIME_ZONE = 'UTC' 142 | 143 | USE_I18N = True 144 | 145 | USE_L10N = True 146 | 147 | USE_TZ = True 148 | 149 | 150 | # Static files (CSS, JavaScript, Images) 151 | # https://docs.djangoproject.com/en/3.1/howto/static-files/ 152 | 153 | STATIC_URL = '/static/' 154 | 155 | DEFAULT_FROM_EMAIL = getenv('EMAIL_HOST_USER') 156 | SERVER_EMAIL = getenv('EMAIL_HOST_USER') 157 | EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 158 | # EMAIL_USE_TLS = True 159 | EMAIL_USE_SSL = True 160 | EMAIL_HOST = 'smtp.gmail.com' 161 | EMAIL_PORT = 465 162 | EMAIL_HOST_USER = getenv('EMAIL_HOST_USER') 163 | EMAIL_HOST_PASSWORD = getenv('EMAIL_HOST_PASSWORD') 164 | 165 | CORS_ALLOW_ALL_ORIGINS = True 166 | -------------------------------------------------------------------------------- /backend/log_app_django/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | 4 | urlpatterns = [ 5 | path('admin/', admin.site.urls), 6 | path('', include('accounts.urls')), 7 | path('', include('trucks.urls')) 8 | ] 9 | -------------------------------------------------------------------------------- /backend/log_app_django/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for log_app_django project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'log_app_django.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'log_app_django.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /backend/requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.2.10 2 | cffi==1.14.3 3 | cryptography==3.1.1 4 | Django==3.1.2 5 | django-cors-headers==3.5.0 6 | django-rest-knox==4.1.0 7 | djangorestframework==3.12.1 8 | psycopg2==2.8.6 9 | pycparser==2.20 10 | python-dotenv==0.15.0 11 | pytz==2020.1 12 | six==1.15.0 13 | sqlparse==0.4.1 14 | -------------------------------------------------------------------------------- /backend/trucks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__init__.py -------------------------------------------------------------------------------- /backend/trucks/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/admin.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/admin.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/api.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/api.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/apps.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/apps.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/models.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/models.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/serializers.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/serializers.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/__pycache__/urls.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/__pycache__/urls.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Truck 3 | 4 | # Register your models here. 5 | admin.site.register(Truck) 6 | -------------------------------------------------------------------------------- /backend/trucks/api.py: -------------------------------------------------------------------------------- 1 | from trucks.models import Truck 2 | from rest_framework import viewsets, permissions 3 | from .serializers import TruckSerializer 4 | 5 | 6 | # Lead Viewset 7 | class TruckViewSet(viewsets.ModelViewSet): 8 | queryset = Truck.objects.all() 9 | permission_classes = [ 10 | permissions.AllowAny 11 | ] 12 | serializer_class = TruckSerializer -------------------------------------------------------------------------------- /backend/trucks/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TrucksConfig(AppConfig): 5 | name = 'trucks' 6 | -------------------------------------------------------------------------------- /backend/trucks/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-25 10:33 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Trucks', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('car', models.CharField(max_length=100)), 19 | ('semitariler', models.CharField(max_length=100)), 20 | ('capacity', models.CharField(max_length=100)), 21 | ('registration_number', models.CharField(max_length=100, unique=True)), 22 | ('message', models.CharField(blank=True, max_length=500)), 23 | ('created_at', models.DateTimeField(auto_now_add=True)), 24 | ], 25 | ), 26 | ] 27 | -------------------------------------------------------------------------------- /backend/trucks/migrations/0002_auto_20201025_1152.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-25 10:52 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('trucks', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameField( 14 | model_name='trucks', 15 | old_name='semitariler', 16 | new_name='semitrailer', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/trucks/migrations/0003_auto_20201025_2132.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-25 20:32 2 | 3 | from django.db import migrations 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('trucks', '0002_auto_20201025_1152'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RenameModel( 14 | old_name='Trucks', 15 | new_name='Truck', 16 | ), 17 | ] 18 | -------------------------------------------------------------------------------- /backend/trucks/migrations/0004_auto_20201025_2222.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-25 21:22 2 | 3 | from django.db import migrations, models 4 | import django.db.models.deletion 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('trucks', '0003_auto_20201025_2132'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RenameField( 15 | model_name='truck', 16 | old_name='car', 17 | new_name='car_manufacturer', 18 | ), 19 | migrations.CreateModel( 20 | name='Car', 21 | fields=[ 22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 23 | ('name', models.CharField(max_length=50)), 24 | ('truck', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='trucks.truck')), 25 | ], 26 | ), 27 | ] 28 | -------------------------------------------------------------------------------- /backend/trucks/migrations/0005_auto_20201029_2137.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.1.2 on 2020-10-29 20:37 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('trucks', '0004_auto_20201025_2222'), 10 | ] 11 | 12 | operations = [ 13 | migrations.RemoveField( 14 | model_name='car', 15 | name='truck', 16 | ), 17 | migrations.AddField( 18 | model_name='car', 19 | name='truck', 20 | field=models.ManyToManyField(to='trucks.Truck'), 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /backend/trucks/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__init__.py -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/0001_initial.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/0001_initial.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/0002_auto_20201025_1152.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/0002_auto_20201025_1152.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/0003_auto_20201025_2132.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/0003_auto_20201025_2132.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/0004_auto_20201025_2222.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/0004_auto_20201025_2222.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/0005_auto_20201029_2137.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/0005_auto_20201029_2137.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/migrations/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/backend/trucks/migrations/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /backend/trucks/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Truck(models.Model): 5 | car_manufacturer = models.CharField(max_length=100) 6 | semitrailer = models.CharField(max_length=100) 7 | capacity = models.CharField(max_length=100) 8 | registration_number = models.CharField(max_length=100, unique=True) 9 | message = models.CharField(max_length=500, blank=True) 10 | created_at = models.DateTimeField(auto_now_add=True) 11 | 12 | def __str__(self): 13 | return self.car_manufacturer 14 | 15 | 16 | class Car(models.Model): 17 | truck = models.ManyToManyField(Truck) 18 | name = models.CharField(max_length=50) 19 | 20 | def __str__(self): 21 | return self.name -------------------------------------------------------------------------------- /backend/trucks/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from trucks.models import Truck 3 | 4 | 5 | # Trucks Serializer 6 | class TruckSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = Truck 9 | fields = '__all__' -------------------------------------------------------------------------------- /backend/trucks/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/trucks/urls.py: -------------------------------------------------------------------------------- 1 | from rest_framework import routers 2 | from .api import TruckViewSet 3 | 4 | 5 | router = routers.DefaultRouter() 6 | router.register('api/truck', TruckViewSet, 'truck') 7 | 8 | urlpatterns = router.urls 9 | -------------------------------------------------------------------------------- /backend/trucks/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /backend/user.txt: -------------------------------------------------------------------------------- 1 | testest_user 2 | testmail@logapp.com 3 | test1234 -------------------------------------------------------------------------------- /docs/client_docs/logowanie.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/docs/client_docs/logowanie.pdf -------------------------------------------------------------------------------- /docs/client_docs/rejestracja.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/docs/client_docs/rejestracja.pdf -------------------------------------------------------------------------------- /docs/client_docs/start.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/docs/client_docs/start.pdf -------------------------------------------------------------------------------- /docs/client_docs/wymiary_przestrzeni_i_ladunkow.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/docs/client_docs/wymiary_przestrzeni_i_ladunkow.xlsx -------------------------------------------------------------------------------- /frontend/.env.development: -------------------------------------------------------------------------------- 1 | REACT_APP_API_BASE_URL=http://localhost:8000 2 | REACT_APP_API_LOGIN_URL=${REACT_APP_API_BASE_URL}/api/auth/login 3 | REACT_APP_API_REGISTER_URL=${REACT_APP_API_BASE_URL}/api/auth/register 4 | REACT_APP_API_USER_URL=${REACT_APP_API_BASE_URL}/api/auth/user 5 | REACT_APP_API_LOGOUT_URL=${REACT_APP_API_BASE_URL}/api/auth/logout 6 | REACT_APP_API_TRUCK_URL=${REACT_APP_API_BASE_URL}/api/truck 7 | -------------------------------------------------------------------------------- /frontend/.env.production: -------------------------------------------------------------------------------- 1 | REACT_APP_API_BASE_URL=http://logapi.pl/ 2 | REACT_APP_API_LOGIN_URL=${REACT_APP_API_BASE_URL}/api/auth/login 3 | REACT_APP_API_REGISTER_URL=${REACT_APP_API_BASE_URL}/api/auth/register 4 | REACT_APP_API_USER_URL=${REACT_APP_API_BASE_URL}/api/auth/user 5 | REACT_APP_API_LOGOUT_URL=${REACT_APP_API_BASE_URL}/api/auth/logout 6 | REACT_APP_API_TRUCK_URL=${REACT_APP_API_BASE_URL}/api/truck -------------------------------------------------------------------------------- /frontend/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier", "prettier/react"], 3 | "env": { 4 | "jest": true 5 | }, 6 | "globals": { 7 | "window": true, 8 | "document": true, 9 | "localStorage": true, 10 | "fetch": true 11 | }, 12 | "rules": { 13 | "no-console": 0, 14 | "jsx-a11y/no-noninteractive-element-interactions": [ 15 | 0, 16 | { 17 | "handlers": [ 18 | "onClick", 19 | "onMouseDown", 20 | "onMouseUp", 21 | "onKeyPress", 22 | "onKeyDown", 23 | "onKeyUp" 24 | ] 25 | } 26 | ], 27 | "jsx-a11y/no-static-element-interactions": [ 28 | 0, 29 | { 30 | "handlers": [ 31 | "onClick", 32 | "onMouseDown", 33 | "onMouseUp", 34 | "onKeyPress", 35 | "onKeyDown", 36 | "onKeyUp" 37 | ] 38 | } 39 | ], 40 | "jsx-a11y/click-events-have-key-events": [0, { "extensions": [".js", ".jsx"] }], 41 | "react/jsx-filename-extension": [ 42 | 1, 43 | { 44 | "extensions": [".js", ".jsx"] 45 | } 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /frontend/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "printWidth": 100 6 | } -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "log_app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^1.2.32", 7 | "@fortawesome/free-solid-svg-icons": "^5.15.1", 8 | "@fortawesome/react-fontawesome": "^0.1.12", 9 | "@testing-library/jest-dom": "^4.2.4", 10 | "@testing-library/react": "^9.5.0", 11 | "@testing-library/user-event": "^7.2.1", 12 | "axios": "^0.21.0", 13 | "node-sass": "^4.14.1", 14 | "normalize.css": "^8.0.1", 15 | "prop-types": "^15.7.2", 16 | "react": "^16.13.1", 17 | "react-dom": "^16.13.1", 18 | "react-loader-spinner": "^3.1.14", 19 | "react-promise-tracker": "^2.1.0", 20 | "react-router-dom": "^5.2.0", 21 | "react-scripts": "3.4.3" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | }, 41 | "devDependencies": { 42 | "dotenv": "^8.2.0", 43 | "eslint": "^6.6.0", 44 | "eslint-config-airbnb": "^18.2.0", 45 | "eslint-config-prettier": "^6.15.0", 46 | "eslint-plugin-import": "^2.22.1", 47 | "eslint-plugin-jsx-a11y": "^6.4.1", 48 | "eslint-plugin-react": "^7.21.5", 49 | "eslint-plugin-react-hooks": "^4.0.0", 50 | "prettier": "^2.1.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /frontend/public/favicon-apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/frontend/public/favicon-apple.png -------------------------------------------------------------------------------- /frontend/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/frontend/public/favicon.png -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | -------------------------------------------------------------------------------- /frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | const { getByText } = render(); 7 | const linkElement = getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /frontend/src/assets/images/404.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/frontend/src/assets/images/404.png -------------------------------------------------------------------------------- /frontend/src/assets/images/LogAppLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/frontend/src/assets/images/LogAppLogo.png -------------------------------------------------------------------------------- /frontend/src/components/Header/Header.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useRef } from 'react'; 2 | import { NavLink } from 'react-router-dom'; 3 | import styles from './Header.module.scss'; 4 | import { useStateWithLabel, isLogged } from '../../helpers/helpers'; 5 | import { StoreContext } from '../../store/StoreProvider'; 6 | import LoginInfo from '../LoginInfo/LoginInfo'; 7 | 8 | const Header = () => { 9 | const { routerLinks, isOpenMenu, setIsOpenMenu, setUserData, userData } = useContext( 10 | StoreContext, 11 | ); 12 | 13 | // eslint-disable-next-line no-unused-vars 14 | const [clickedOutsideMenu, setClickedOutsideMenu] = useStateWithLabel('clickedOutside', false); 15 | 16 | const myRef = useRef(); 17 | 18 | const handleClickOutsideMenu = (e) => { 19 | if (!myRef.current.contains(e.target)) { 20 | setClickedOutsideMenu(true); 21 | setIsOpenMenu(false); 22 | } 23 | }; 24 | 25 | useEffect(() => { 26 | if (isLogged() && !userData.isLogged) { 27 | const data = JSON.parse(localStorage.getItem('LogAppUser')); 28 | 29 | setUserData({ 30 | username: data.username, 31 | email: data.email, 32 | isLogged: data.isLogged, 33 | token: data.token, 34 | }); 35 | } 36 | 37 | document.addEventListener('mousedown', handleClickOutsideMenu); 38 | return () => document.removeEventListener('mousedown', handleClickOutsideMenu); 39 | }); 40 | 41 | const menu = routerLinks.map((item) => ( 42 |
  • 43 | 44 | {item.name} 45 | 46 |
  • 47 | )); 48 | 49 | const handleHamburgerClick = (e) => { 50 | e.preventDefault(); 51 | setIsOpenMenu(!isOpenMenu); 52 | setClickedOutsideMenu(false); 53 | }; 54 | const handleCloseMenu = (e) => { 55 | e.preventDefault(); 56 | setIsOpenMenu(false); 57 | }; 58 | 59 | return ( 60 | <> 61 |
    62 |
    63 | 64 | 77 |
    78 | 79 | ); 80 | }; 81 | export default Header; 82 | -------------------------------------------------------------------------------- /frontend/src/components/Header/Header.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../views/Root/common.scss'; 2 | .header { 3 | display: flex; 4 | flex-wrap: nowrap; 5 | justify-content: space-between; 6 | padding: 10px; 7 | .logo { 8 | height: 200px; 9 | width: 300px; 10 | min-width: 70px; 11 | background-image: url('../../assets/images/LogAppLogo.png'); 12 | background-size: contain; 13 | background-repeat: no-repeat; 14 | } 15 | .title { 16 | margin: 10px; 17 | text-align: center; 18 | font-size: $m-font-size * 1.2; 19 | color: $text-first-color; 20 | } 21 | .info { 22 | flex-basis: 40%; 23 | } 24 | @media (orientation: landscape) and (min-width: 1024px) { 25 | .logo { 26 | height: 200px; 27 | width: 300px; 28 | background-image: url('../../assets/images/LogAppLogo.png'); 29 | background-size: auto; 30 | background-repeat: no-repeat; 31 | } 32 | .title { 33 | margin: 20px; 34 | font-size: $x-font-size * 1.8; 35 | } 36 | .info { 37 | flex-basis: 60%; 38 | } 39 | } 40 | } 41 | 42 | .nav { 43 | min-width: 100px; 44 | .menu { 45 | position: absolute; 46 | top: 3em; 47 | margin: 0.5em 0; 48 | right: 1em; 49 | display: none; 50 | // display: flex; 51 | // visibility: hidden; 52 | flex-direction: column; 53 | justify-content: flex-end; 54 | align-items: flex-start; 55 | 56 | padding: 0.4em; 57 | z-index: 100; 58 | border: 1px solid $fourth-color; 59 | border-radius: 5px; 60 | transition: 0.6s ease-in-out all; 61 | li { 62 | list-style: none; 63 | text-align: left; 64 | overflow: hidden; 65 | 66 | a { 67 | position: relative; 68 | color: $fourth-color; 69 | display: block; 70 | width: 100%; 71 | height: 100%; 72 | font-size: $m-font-size; 73 | text-transform: uppercase; 74 | text-decoration: none; 75 | text-align: center; 76 | line-height: $x-font-size !important; 77 | cursor: pointer; 78 | transition: 0.3s ease-in-out all; 79 | 80 | &::before { 81 | content: ''; 82 | position: absolute; 83 | bottom: 0; 84 | left: -150%; 85 | height: 2px; 86 | width: 100%; 87 | background-color: $fourth-color; 88 | transition: 0.2s ease-in-out all; 89 | } 90 | 91 | &:hover::before { 92 | left: 0; 93 | } 94 | } 95 | } 96 | } 97 | .hamburger { 98 | display: block; 99 | position: absolute; 100 | width: 35px; 101 | font-size: 1em; 102 | right: 1.5em; 103 | cursor: pointer; 104 | 105 | & .bar1, 106 | & .bar2, 107 | & .bar3 { 108 | width: 35px; 109 | height: 5px; 110 | margin: 6px 0; 111 | -webkit-transition: 0.4s; 112 | transition: 0.4s; 113 | color: $fourth-color; 114 | background-color: $fourth-color; 115 | } 116 | 117 | & .bar1Change { 118 | width: 35px; 119 | transform: rotate(-45deg) translate(-9px, 6px); 120 | } 121 | 122 | & .bar2Change { 123 | width: 35px; 124 | opacity: 0; 125 | } 126 | 127 | & .bar3Change { 128 | width: 35px; 129 | transform: rotate(45deg) translate(-8px, -8px); 130 | } 131 | } 132 | .menuShow { 133 | // visibility: visible; 134 | display: flex; 135 | } 136 | } 137 | 138 | @media (orientation: landscape) and (min-width: 1024px) { 139 | .nav { 140 | .menu { 141 | display: flex; 142 | flex-direction: row; 143 | border: none; 144 | li { 145 | width: 200px; 146 | margin-right: 10px; 147 | overflow: visible; 148 | 149 | a { 150 | @include button; 151 | font-size: $x-font-size; 152 | line-height: 30px !important; 153 | 154 | &::before { 155 | display: none; 156 | } 157 | } 158 | } 159 | } 160 | 161 | .hamburger { 162 | display: none; 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /frontend/src/components/LoginInfo/LoginInfo.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 3 | import { faSignInAlt, faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; 4 | 5 | import { NavLink } from 'react-router-dom'; 6 | 7 | import { StoreContext } from '../../store/StoreProvider'; 8 | import styles from './LoginInfo.module.scss'; 9 | 10 | const LoginInfo = () => { 11 | const { userData, setUserData } = useContext(StoreContext); 12 | 13 | const Logut = (e) => { 14 | e.preventDefault(); 15 | setUserData({ 16 | username: null, 17 | email: null, 18 | isLogged: false, 19 | token: null, 20 | }); 21 | 22 | localStorage.removeItem('LogAppUser'); 23 | }; 24 | 25 | return ( 26 |
    27 | {!userData.isLogged ? ( 28 | 29 | Zaloguj się 30 | 31 | ) : ( 32 |
    33 | 34 | Witaj {userData.username} 35 | 36 |
    37 | )} 38 |
    39 | ); 40 | }; 41 | 42 | export default LoginInfo; 43 | -------------------------------------------------------------------------------- /frontend/src/components/LoginInfo/LoginInfo.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../views/Root/common.scss'; 2 | 3 | .loginInfo { 4 | position: absolute; 5 | margin-right: 15px; 6 | top: 17px; 7 | right: 69px; 8 | 9 | @media (orientation: landscape) and (min-width: 1024px) { 10 | right: 20px; 11 | } 12 | & .link { 13 | text-decoration: none; 14 | color: $text-first-color; 15 | & a { 16 | text-decoration: none; 17 | color: $text-first-color; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/components/Message/Message.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-array-index-key */ 2 | import React from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import styles from './Message.module.scss'; 5 | 6 | const Message = ({ message, alert }) => { 7 | return ( 8 |
    9 | {Array.isArray(message) ? message.map((v, i) =>

    {v}

    ) : message} 10 |
    11 | ); 12 | }; 13 | // Definiuje domyślne wartości dla właściwości: 14 | Message.defaultProps = { 15 | alert: false, 16 | }; 17 | 18 | Message.propTypes = { 19 | message: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]) 20 | .isRequired, 21 | alert: PropTypes.bool, 22 | }; 23 | 24 | export default Message; 25 | -------------------------------------------------------------------------------- /frontend/src/components/Message/Message.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../views/Root/common.scss'; 2 | 3 | .message { 4 | position: fixed; 5 | display: flex; 6 | flex-direction: column; 7 | align-items: center; 8 | justify-content: center; 9 | width: 100%; 10 | min-height: 50px; 11 | top: -100%; 12 | left: 0; 13 | text-align: center; 14 | background-color: green; 15 | animation: messageAnimation 5s linear; 16 | animation-iteration-count: 1; 17 | animation-direction: normal; 18 | animation-fill-mode: both; 19 | box-shadow: 0px 5px 14px 0px rgba(0, 0, 0, 0.54); 20 | z-index: 999; 21 | } 22 | 23 | @keyframes messageAnimation { 24 | 0% { 25 | top: -100%; 26 | } 27 | 20% { 28 | top: 0; 29 | } 30 | 80% { 31 | top: 0; 32 | } 33 | 100% { 34 | top: -100%; 35 | } 36 | } 37 | 38 | .messageAlert { 39 | background-color: red; 40 | } 41 | -------------------------------------------------------------------------------- /frontend/src/components/Modal/Modal.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from "react"; 2 | import ReactDOM from "react-dom"; 3 | 4 | const Modal = ({ 5 | children, 6 | handleOnClose, 7 | isOpen, 8 | shouldBeClosedOnOutsideClick, 9 | }) => { 10 | const modalRef = useRef(null); 11 | const previousActiveElement = useRef(null); 12 | 13 | useEffect(() => { 14 | if (!modalRef) { 15 | return; 16 | } 17 | const { current: modal } = modalRef; 18 | 19 | if (isOpen) { 20 | previousActiveElement.current = document.activeElement; 21 | modal.showModal(); 22 | } else if (previousActiveElement.current) { 23 | modal.close(); 24 | previousActiveElement.current.focus(); 25 | } 26 | }, [isOpen]); 27 | 28 | useEffect(() => { 29 | const { current: modal } = modalRef; 30 | 31 | const handleCancel = (event) => { 32 | event.preventDefauldt(); 33 | handleOnClose(); 34 | }; 35 | 36 | modal.addEventListener("cancel", handleCancel); 37 | 38 | return () => { 39 | modal.removeEventListener("cancel", handleCancel); 40 | }; 41 | }, [handleOnClose]); 42 | 43 | const handleOutsideClick = ({ target }) => { 44 | const { current } = modalRef; 45 | 46 | if (shouldBeClosedOnOutsideClick && target === current) { 47 | handleOnClose(); 48 | } 49 | }; 50 | 51 | return ReactDOM.createPortal( 52 | 53 | {children} 54 | , 55 | document.body 56 | ); 57 | }; 58 | 59 | export default Modal; 60 | -------------------------------------------------------------------------------- /frontend/src/components/ReturnButton/ReturnButton.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useHistory } from 'react-router-dom'; 3 | import styles from './ReturnButton.module.scss'; 4 | 5 | const ReturnButton = () => { 6 | const history = useHistory(); 7 | const handleOnClick = () => history.goBack(); 8 | return ( 9 | 12 | ); 13 | }; 14 | 15 | export default ReturnButton; 16 | -------------------------------------------------------------------------------- /frontend/src/components/ReturnButton/ReturnButton.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../views/Root/common.scss'; 2 | .returnButton { 3 | @include button($first-color); 4 | background-color: $first-color; 5 | &:hover { 6 | color: $text-first-color; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/components/Spinner/Spinner.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { usePromiseTracker } from 'react-promise-tracker'; 3 | import Loader from 'react-loader-spinner'; 4 | import styles from './Spinner.module.scss'; 5 | 6 | const Spinner = () => { 7 | const { promiseInProgress } = usePromiseTracker(); 8 | return ( 9 | <> 10 | {promiseInProgress && ( 11 |
    12 | 13 |
    14 | )} 15 | 16 | ); 17 | }; 18 | export default Spinner; 19 | -------------------------------------------------------------------------------- /frontend/src/components/Spinner/Spinner.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../views/Root/common.scss'; 2 | @import '../../../node_modules/react-loader-spinner/dist/loader/css/react-spinner-loader.css'; 3 | 4 | .loader { 5 | position: fixed; 6 | display: flex; 7 | justify-content: center; 8 | align-items: center; 9 | background-color: rgba(0, 0, 0, 0.3); 10 | width: 100%; 11 | height: 100%; 12 | z-index: 9999; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/helpers/helpers.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | import { useState, useDebugValue } from 'react'; 3 | 4 | export const useStateWithLabel = (name, initialValue) => { 5 | const [value, setValue] = useState(initialValue); 6 | useDebugValue(`${name}: ${value}`); 7 | return [value, setValue]; 8 | }; 9 | 10 | export const checkEmail = (email = false) => { 11 | // don't remember from where i copied this code, but this works. 12 | const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 13 | 14 | return re.test(email); 15 | }; 16 | 17 | export const isLogged = () => { 18 | return JSON.parse(localStorage.getItem('LogAppUser')) || false; 19 | }; 20 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './views/Root/index.scss'; 4 | import Root from './views/Root/Root'; 5 | import Spiner from './components/Spinner/Spinner'; 6 | import * as serviceWorker from './serviceWorker'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | 12 | , 13 | document.getElementById('root'), 14 | ); 15 | 16 | // If you want your app to work offline and load faster, you can change 17 | // unregister() to register() below. Note this comes with some pitfalls. 18 | // Learn more about service workers: https://bit.ly/CRA-PWA 19 | serviceWorker.unregister(); 20 | -------------------------------------------------------------------------------- /frontend/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl, { 104 | headers: { 'Service-Worker': 'script' }, 105 | }) 106 | .then(response => { 107 | // Ensure service worker exists, and that we really are getting a JS file. 108 | const contentType = response.headers.get('content-type'); 109 | if ( 110 | response.status === 404 || 111 | (contentType != null && contentType.indexOf('javascript') === -1) 112 | ) { 113 | // No service worker found. Probably a different app. Reload the page. 114 | navigator.serviceWorker.ready.then(registration => { 115 | registration.unregister().then(() => { 116 | window.location.reload(); 117 | }); 118 | }); 119 | } else { 120 | // Service worker found. Proceed as normal. 121 | registerValidSW(swUrl, config); 122 | } 123 | }) 124 | .catch(() => { 125 | console.log( 126 | 'No internet connection found. App is running in offline mode.' 127 | ); 128 | }); 129 | } 130 | 131 | export function unregister() { 132 | if ('serviceWorker' in navigator) { 133 | navigator.serviceWorker.ready 134 | .then(registration => { 135 | registration.unregister(); 136 | }) 137 | .catch(error => { 138 | console.error(error.message); 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /frontend/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom/extend-expect'; 6 | -------------------------------------------------------------------------------- /frontend/src/store/StoreProvider.jsx: -------------------------------------------------------------------------------- 1 | import React, { createContext } from 'react'; 2 | import { useStateWithLabel } from '../helpers/helpers'; 3 | 4 | import Message from '../components/Message/Message'; 5 | 6 | const VECHICLES_DATA = [ 7 | { name: 'BUS', dim: [420, 220, 220] }, 8 | { name: 'SOLO', dim: [1200, 250, 250] }, 9 | { name: 'NACZEPA', dim: [1360, 250, 275] }, 10 | ]; 11 | 12 | // const LOADS_DATA = []; 13 | export const StoreContext = createContext(null); 14 | 15 | const StoreProvider = (props) => { 16 | // Vehicles 17 | const [vechicleData, setVechicleData] = useStateWithLabel('vechicleData', null); 18 | const [takeVechicle, setTakeVechicle] = useStateWithLabel('takeVechicle', false); 19 | 20 | // Load 21 | 22 | const [loadData, setLoadData] = useStateWithLabel('loadData', null); 23 | const [takeLoad, setTakeLoad] = useStateWithLabel('takeLoad', false); 24 | 25 | // Menu 26 | const [isOpenMenu, setIsOpenMenu] = useStateWithLabel('isOpenMenu', false); 27 | 28 | // User data 29 | const [userData, setUserData] = useStateWithLabel('userData', { 30 | username: null, 31 | email: null, 32 | isLogged: false, 33 | token: null, 34 | }); 35 | 36 | // Message 37 | const [isVisibleMessage, setIsVisibleMessage] = useStateWithLabel('isVisibleMessage', false); 38 | const [messageText, setMessageText] = useStateWithLabel('messageText', ''); 39 | const [isMessageAlert, setIsMessageAlert] = useStateWithLabel('isMessageAlert', false); 40 | 41 | // Router links 42 | const routerLinks = [ 43 | { name: 'start', path: '/', exact: true }, 44 | { name: 'kontakt', path: '/contact' }, 45 | { name: 'pomoc', path: '/help' }, 46 | ]; 47 | 48 | const takeVechicleData = () => { 49 | if (takeVechicle === false) { 50 | return; 51 | } 52 | const datas = VECHICLES_DATA.map((data) => { 53 | if (data.name === takeVechicle) { 54 | return ` ${data.name} / dł: ${data.dim[0] / 100}m / szer: ${ 55 | data.dim[1] / 100 56 | }m / wys: ${data.dim[2] / 100}m`; 57 | } 58 | }); 59 | setVechicleData(datas); 60 | setTakeVechicle(true); 61 | }; 62 | 63 | const showMessage = (text, isAlert) => { 64 | setMessageText(text); 65 | setIsMessageAlert(isAlert); 66 | setIsVisibleMessage(true); 67 | 68 | setTimeout(() => { 69 | setIsVisibleMessage(false); 70 | }, 5000); 71 | }; 72 | 73 | return ( 74 | 92 | {isVisibleMessage ? : ''} 93 | {props.children} 94 | 95 | ); 96 | }; 97 | 98 | export default StoreProvider; 99 | -------------------------------------------------------------------------------- /frontend/src/views/Contact/Contact.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Contact.module.scss'; 3 | 4 | const ContactPage = () => { 5 | return ( 6 |
    7 |

    Contact_Page

    8 |
    9 | ); 10 | }; 11 | 12 | export default ContactPage; 13 | -------------------------------------------------------------------------------- /frontend/src/views/Contact/Contact.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .wrapper { 3 | margin: 100px auto; 4 | h1 { 5 | text-align: center; 6 | } 7 | } 8 | 9 | -------------------------------------------------------------------------------- /frontend/src/views/Error/Error.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Error.module.scss'; 3 | import img404 from '../../assets/images/404.png'; 4 | 5 | const ErrorPage = () => { 6 | return ( 7 |
    8 |
    9 |

    404

    10 |

    Niestety nie znaleziono strony.

    11 |
    12 | Error 404 13 |
    14 | ); 15 | }; 16 | 17 | export default ErrorPage; 18 | -------------------------------------------------------------------------------- /frontend/src/views/Error/Error.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | 3 | .wrapper { 4 | display: flex; 5 | flex-direction: column; 6 | 7 | align-items: center; 8 | 9 | @media (orientation: landscape) and (min-width: 1024px) { 10 | flex-direction: row-reverse; 11 | justify-content: center; 12 | align-items: flex-end; 13 | } 14 | 15 | .info { 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; 19 | justify-content: flex-start; 20 | & h1 { 21 | font-size: $l-font-size * 4; 22 | margin: 0; 23 | margin-bottom: 0.3em; 24 | text-align: center; 25 | text-shadow: 3px 3px 12px #000000; 26 | @media (orientation: landscape) and (min-width: 1024px) { 27 | font-size: $l-font-size * 5; 28 | } 29 | } 30 | & p { 31 | font-size: $m-font-size * 1.2; 32 | text-align: center; 33 | } 34 | } 35 | img { 36 | margin: 1em 0 0 0; 37 | 38 | @media (orientation: landscape) and (min-width: 1024px) { 39 | margin: 0 40px 0 0; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/views/Footer/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Footer.module.scss'; 3 | 4 | const Footer = () => { 5 | return
    ; 6 | }; 7 | 8 | export default Footer; 9 | -------------------------------------------------------------------------------- /frontend/src/views/Footer/Footer.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | 3 | .wrapper { 4 | display: flex; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/FreeStart.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './FreeStart.module.scss'; 3 | 4 | import VechicleDetails from './subcomponents/VechicleDetails'; 5 | import LoadDetails from './subcomponents/LoadsDetails'; 6 | import ReturnButton from '../../components/ReturnButton/ReturnButton'; 7 | 8 | const FreeStartPage = () => { 9 | return ( 10 |
    11 |

    Free-Start

    12 |

    13 | To wersja bez logowania, po wyjściu Twoja praca zostanie utracona. Zaloguj się aby 14 | zapisywać swoją pracę. 15 |

    16 |
    17 |
    18 | 19 |
    20 |
    21 |
    22 | 23 |
    24 |
    25 |
    26 | 27 |
    28 |
    29 | ); 30 | }; 31 | 32 | export default FreeStartPage; 33 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/FreeStart.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .freeStart { 3 | position: relative; 4 | width: 95vw; 5 | margin: -20px auto 0 auto; 6 | text-align: center; 7 | .main { 8 | width: 100%; 9 | height: 900px; 10 | display: flex; 11 | flex-direction: column; 12 | .vechicleDetails, 13 | .infoDetails, 14 | .loadDetails { 15 | flex-basis: 33%; 16 | @include element; 17 | } 18 | } 19 | .returnButton { 20 | position: absolute; 21 | margin-bottom: 20px; 22 | bottom: -70px; 23 | right: 0; 24 | } 25 | @media (orientation: landscape) and (min-width: 1024px) { 26 | margin: -70px auto 0 auto; 27 | .main { 28 | flex-direction: row; 29 | height: auto; 30 | } 31 | .returnButton { 32 | bottom: -80px; 33 | right: 50px; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/InfoDetails.jsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logappopen/Log_app/4c22d52c01f5df123481e69105b8b60091bf9370/frontend/src/views/FreeStart/subcomponents/InfoDetails.jsx -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/LoadDetails.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../Root/common.scss'; 2 | 3 | .loadDetails { 4 | // margin: 100px; 5 | button { 6 | @include button; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/LoadInfo.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | 3 | import { StoreContext } from '../../../store/StoreProvider'; 4 | 5 | const LoadInfo = () => { 6 | const { loadData } = useContext(StoreContext); 7 | 8 | return ( 9 |
    10 |

    {loadData ? `Wybrany pojazd:${loadData}` : null}

    11 |
    12 | ); 13 | }; 14 | 15 | export default LoadInfo; 16 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/LoadPopup.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | // import PropTypes from 'prop-types'; 3 | 4 | import Modal from '../../../components/Modal/Modal'; 5 | import { StoreContext } from '../../../store/StoreProvider'; 6 | 7 | import styles from './LoadPopup.module.scss'; 8 | 9 | const LoadPopup = ({ isPopupOpen, hidePopup }) => { 10 | return ( 11 | 12 |
    13 |
    14 | 15 | 23 | 24 | 32 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 45 |
    46 |
    47 |
    48 | ); 49 | }; 50 | 51 | // VechiclePopup.propTypes = { 52 | // isPopupOpen: PropTypes.bool.isRequired, 53 | // hidePopup: PropTypes.func.isRequired, 54 | // }; 55 | 56 | export default LoadPopup; 57 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/LoadPopup.module.scss: -------------------------------------------------------------------------------- 1 | @import '../../Root/common.scss'; 2 | 3 | .LoadPopup { 4 | position: fixed; 5 | top: 50%; 6 | left: 50%; 7 | transform: translate(-50%, -50%); 8 | width: 280px; 9 | height: 520px; 10 | background-color: $text-third-color; 11 | @include button; 12 | form { 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: space-around; 16 | height: 100%; 17 | label { 18 | display: flex; 19 | justify-content: space-between; 20 | align-items: center; 21 | margin: 20px 0 5px 0; 22 | } 23 | input { 24 | width: 80px; 25 | } 26 | button { 27 | @include button($first-color); 28 | background-color: $first-color; 29 | &:hover { 30 | color: $text-first-color; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/LoadsDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { StoreContext } from '../../../store/StoreProvider'; 3 | 4 | import LoadPopup from './LoadPopup'; 5 | 6 | import LoadInfo from './LoadInfo'; 7 | 8 | import styles from './LoadDetails.module.scss'; 9 | 10 | const LoadDetails = () => { 11 | const [isPopupOpen, setIsPopupOpen] = useState(false); 12 | 13 | const showPopup = () => { 14 | setIsPopupOpen(true); 15 | }; 16 | 17 | const hidePopup = (event) => { 18 | if (event) { 19 | event.preventDefault(); 20 | } 21 | setIsPopupOpen(false); 22 | }; 23 | return ( 24 |
    25 | 26 | 27 | 28 |
    29 | ); 30 | }; 31 | export default LoadDetails; 32 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/VechicleDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from 'react'; 2 | import { StoreContext } from '../../../store/StoreProvider'; 3 | 4 | import VechiclePopup from './VechiclePopup'; 5 | 6 | import VechicleInfo from './VechicleInfo'; 7 | 8 | import styles from './VechicleDetails.module.scss'; 9 | 10 | const VechicleDetails = () => { 11 | const [isPopupOpen, setIsPopupOpen] = useState(false); 12 | 13 | const takeVechicle = useContext(StoreContext); 14 | 15 | const showPopup = () => { 16 | setIsPopupOpen(true); 17 | }; 18 | const hidePopup = (event) => { 19 | if (event) { 20 | event.preventDefault(); 21 | } 22 | setIsPopupOpen(false); 23 | }; 24 | 25 | return ( 26 |
    27 | 30 | 31 | 32 |
    33 | ); 34 | }; 35 | export default VechicleDetails; 36 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/VechicleDetails.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Root/common.scss"; 2 | 3 | .vechicleDetails { 4 | // margin: 100px; 5 | button { 6 | @include button; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/VechicleInfo.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | 3 | import { StoreContext } from '../../../store/StoreProvider'; 4 | 5 | const VechicleInfo = () => { 6 | const { vechicleData } = useContext(StoreContext); 7 | 8 | return ( 9 |
    10 |

    {vechicleData ? `Wybrany pojazd:${vechicleData}` : 'Nie wybrano pojazdu'}

    11 |
    12 | ); 13 | }; 14 | 15 | export default VechicleInfo; 16 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/VechiclePopup.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Modal from '../../../components/Modal/Modal'; 5 | import { StoreContext } from '../../../store/StoreProvider'; 6 | 7 | import styles from './VechiclePopup.module.scss'; 8 | 9 | const VechiclePopup = ({ isPopupOpen, hidePopup }) => { 10 | const { setTakeVechicle, takeVechicleData } = useContext(StoreContext); 11 | 12 | const handlOnSendData = () => { 13 | takeVechicleData(); 14 | hidePopup(); 15 | }; 16 | 17 | const handleOnChange = (event) => { 18 | setTakeVechicle(event.target.value); 19 | }; 20 | 21 | return ( 22 | 23 |
    24 |
    25 | 35 | 45 | 55 | 58 |
    59 |
    60 |
    61 | ); 62 | }; 63 | 64 | VechiclePopup.propTypes = { 65 | isPopupOpen: PropTypes.bool.isRequired, 66 | hidePopup: PropTypes.func.isRequired, 67 | }; 68 | 69 | export default VechiclePopup; 70 | -------------------------------------------------------------------------------- /frontend/src/views/FreeStart/subcomponents/VechiclePopup.module.scss: -------------------------------------------------------------------------------- 1 | @import "../../Root/common.scss"; 2 | 3 | .vechiclePopup { 4 | position: fixed; 5 | top: 50%; 6 | left: 50%; 7 | transform: translate(-50%, -50%); 8 | width: 250px; 9 | height: 300px; 10 | background-color: $text-third-color; 11 | @include button; 12 | form { 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: space-around; 16 | height: 100%; 17 | label { 18 | display: flex; 19 | justify-content: space-between; 20 | align-items: center; 21 | } 22 | button { 23 | @include button($first-color); 24 | background-color: $first-color; 25 | &:hover { 26 | color: $text-first-color; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/views/Help/Help.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './Help.modules.scss'; 3 | 4 | const HelpPage = () => { 5 | return ( 6 |
    7 |

    Help_Page

    8 |
    9 | ); 10 | }; 11 | 12 | export default HelpPage; 13 | -------------------------------------------------------------------------------- /frontend/src/views/Help/Help.modules.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .wrapper { 3 | margin: 100px auto; 4 | h1 { 5 | text-align: center; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/views/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter as Router } from 'react-router-dom'; 3 | import styles from './Home.module.scss'; 4 | import StoreProvider from '../../store/StoreProvider'; 5 | 6 | import Header from '../../components/Header/Header'; 7 | import Main from '../Main/Main'; 8 | import Footer from '../Footer/Footer'; 9 | 10 | const Home = () => { 11 | return ( 12 | 13 | 14 |
    15 |
    16 |
    17 |
    18 |
    19 |
    20 |
    21 |
    22 |
    23 |
    24 |
    25 |
    26 |
    27 | ); 28 | }; 29 | 30 | export default Home; 31 | -------------------------------------------------------------------------------- /frontend/src/views/Home/Home.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .container { 3 | display: flex; 4 | flex-direction: column; 5 | flex-wrap: nowrap; 6 | flex-grow: 1; 7 | width: 100vw; 8 | height: 100vh; 9 | margin: 0 auto; 10 | & .header { 11 | flex-basis: 20%; 12 | } 13 | & .section { 14 | flex-basis: 60%; 15 | } 16 | & .footer { 17 | flex-basis: 10%; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/views/Login/Login.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { NavLink, Redirect } from 'react-router-dom'; 3 | import axios from 'axios'; 4 | import { trackPromise } from 'react-promise-tracker'; 5 | import styles from './Login.module.scss'; 6 | 7 | import { StoreContext } from '../../store/StoreProvider'; 8 | import { useStateWithLabel, checkEmail, isLogged } from '../../helpers/helpers'; 9 | import ReturnButton from '../../components/ReturnButton/ReturnButton'; 10 | 11 | const LoginPage = () => { 12 | const [email, setEmail] = useStateWithLabel('email', ''); 13 | const [isValidEmail, setIsValidEmail] = useStateWithLabel('isValidemail', false); 14 | const [password, setPassword] = useStateWithLabel('password', ''); 15 | 16 | const { setUserData, showMessage } = useContext(StoreContext); 17 | 18 | const handleOnPushEmail = (e) => { 19 | setIsValidEmail(checkEmail(e.target.value)); 20 | setEmail(e.target.value); 21 | }; 22 | 23 | const sendCredentials = () => { 24 | trackPromise( 25 | axios 26 | .post(process.env.REACT_APP_API_LOGIN_URL, { 27 | email, 28 | password, 29 | }) 30 | .then(({ data }) => { 31 | // console.log(data) 32 | localStorage.setItem( 33 | 'LogAppUser', 34 | JSON.stringify({ 35 | isLogged: true, 36 | id: data.user.id, 37 | username: data.user.username, 38 | email: data.user.email, 39 | token: data.token, 40 | }), 41 | ); 42 | return data; 43 | }) 44 | .then((data) => { 45 | setUserData({ 46 | username: data.user.username, 47 | email: data.user.email, 48 | isLogged: true, 49 | token: data.token, 50 | }); 51 | 52 | return data; 53 | }) 54 | .then((data) => { 55 | console.log(data); 56 | 57 | isLogged(); 58 | showMessage(`Zalogowałeś się poprawnie jako ${data.user.username}`); 59 | }) 60 | .catch((error) => { 61 | setUserData({ 62 | username: null, 63 | email: null, 64 | isLogged: false, 65 | token: null, 66 | }); 67 | localStorage.removeItem('LogAppUser'); 68 | const errorsMsg = [`Wystąpiły błędy podczas logowania:`]; 69 | 70 | Object.keys(error.response.data).map((v) => { 71 | return errorsMsg.push(error.response.data[v][0]); 72 | }); 73 | showMessage(errorsMsg, true); 74 | }), 75 | ); 76 | }; 77 | 78 | const handleOnPushPassword = (e) => { 79 | setPassword(e.target.value); 80 | }; 81 | 82 | const handleOnClickLogin = (e) => { 83 | e.preventDefault(); 84 | 85 | const errorsMsg = [`Wypełnij poprawnie formularz:`]; 86 | 87 | if (isValidEmail) { 88 | console.log('Wpisano poprawny email'); 89 | sendCredentials(); 90 | } else { 91 | console.log('Wpisano błędny email'); 92 | errorsMsg.push(`Wpisz poprawny email`); 93 | } 94 | 95 | if (!password.length) errorsMsg.push(`Wpisz hasło.`); 96 | showMessage(errorsMsg, true); 97 | }; 98 | 99 | if (isLogged()) { 100 | return ; 101 | } 102 | return ( 103 |
    104 |
    105 | 112 | 113 | 120 | 123 |
    124 | 129 |
    130 | 131 |
    132 |
    133 | ); 134 | }; 135 | 136 | export default LoginPage; 137 | -------------------------------------------------------------------------------- /frontend/src/views/Login/Login.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .sectionLogin { 3 | position: relative; 4 | width: 95vw; 5 | margin: 10px auto; 6 | display: flex; 7 | align-items: center; 8 | flex-direction: column; 9 | .form { 10 | margin: 0 auto; 11 | } 12 | .nav { 13 | ul { 14 | // margin-top: 30px; 15 | list-style: none; 16 | text-align: center; 17 | a { 18 | text-decoration: none; 19 | color: $text-first-color; 20 | cursor: pointer; 21 | } 22 | } 23 | } 24 | .returnButton { 25 | position: absolute; 26 | bottom: -50px; 27 | right: 0; 28 | } 29 | @media (orientation: landscape) and (min-width: 1024px) { 30 | .nav { 31 | ul { 32 | margin-top: 30px; 33 | } 34 | } 35 | .returnButton { 36 | bottom: -150px; 37 | right: 50px; 38 | } 39 | } 40 | } 41 | 42 | .form { 43 | display: flex; 44 | flex-direction: column; 45 | justify-content: flex-start; 46 | align-items: center; 47 | 48 | .input { 49 | @include input; 50 | } 51 | .button { 52 | @include button; 53 | } 54 | @media (orientation: landscape) and (min-width: 1024px) { 55 | width: 30%; 56 | 57 | .input { 58 | height: 50px; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /frontend/src/views/LostPassword/LostPassword.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import ReturnButton from '../../components/ReturnButton/ReturnButton'; 3 | import styles from './LostPassword.module.scss'; 4 | 5 | const EMAILS = []; 6 | 7 | const LostPasswordPage = () => { 8 | const [viewMessage, setViewMessage] = useState(''); 9 | const [emailValue, setEmailValue] = useState(''); 10 | 11 | const handleOnPushEmail = (event) => { 12 | const eMail = event.target.value; 13 | 14 | if (eMail) { 15 | setEmailValue(eMail); 16 | EMAILS.push(eMail); 17 | } 18 | return null; 19 | }; 20 | const handleOnClickLogin = () => { 21 | if (EMAILS.lenght > 0) { 22 | setViewMessage(`${viewMessage}na podanego maila został wysłany reset hasła`); 23 | 24 | // setTimeout(() => { 25 | // // setEmailValue(""); 26 | // setViewMessage(viewMessage + ""); 27 | // }, 4000); 28 | } else { 29 | setViewMessage(`${viewMessage}nie podano adresu eMail`); 30 | } 31 | }; 32 | 33 | return ( 34 |
    35 |
    36 | 45 |

    {viewMessage}

    46 | 49 |
    50 |
    51 | 52 |
    53 |
    54 | ); 55 | }; 56 | 57 | export default LostPasswordPage; 58 | -------------------------------------------------------------------------------- /frontend/src/views/LostPassword/LostPassword.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .wrapper { 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | width: 95vw; 7 | & .form { 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | width: 100%; 12 | & .label { 13 | display: flex; 14 | flex-direction: column; 15 | flex-basis: 30%; 16 | margin: 10px 2em; 17 | text-align: center; 18 | flex-basis: 70%; 19 | text-align: center; 20 | 21 | & .input { 22 | @include input; 23 | margin-top: 1em; 24 | } 25 | } 26 | 27 | & .button { 28 | @include button; 29 | } 30 | } 31 | & .info { 32 | text-align: center; 33 | color: $second-color; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /frontend/src/views/Main/Main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Switch, Route } from 'react-router-dom'; 3 | 4 | import StartPage from '../Start/Start'; 5 | import ContactPage from '../Contact/Contact'; 6 | import HelpPage from '../Help/Help'; 7 | import LoginPage from '../Login/Login'; 8 | import RegistrationPage from '../Registration/Registration'; 9 | import FreeStartPage from '../FreeStart/FreeStart'; 10 | import LostPasswordPage from '../LostPassword/LostPassword'; 11 | import ErrorPage from '../Error/Error'; 12 | 13 | const Main = () => { 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default Main; 29 | -------------------------------------------------------------------------------- /frontend/src/views/Main/Main.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | -------------------------------------------------------------------------------- /frontend/src/views/Registration/Registration.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink, Redirect } from 'react-router-dom'; 3 | import axios from 'axios'; 4 | 5 | import { trackPromise } from 'react-promise-tracker'; 6 | import styles from './Registration.module.scss'; 7 | 8 | import { checkEmail, useStateWithLabel, isLogged } from '../../helpers/helpers'; 9 | import ReturnButton from '../../components/ReturnButton/ReturnButton'; 10 | import Message from '../../components/Message/Message'; 11 | 12 | const RegistrationPage = () => { 13 | const [username, setUsername] = useStateWithLabel('username', ''); 14 | const [email, setEmail] = useStateWithLabel('email', ''); 15 | const [userPassword, setUserPassword] = useStateWithLabel('userPassword', ''); 16 | const [userPasswordRepeat, setUserPasswordRepeat] = useStateWithLabel('userPasswordRepeat', ''); 17 | const [isVisibleMessage, setIsVisibleMessage] = useStateWithLabel('isVisibleMessage', false); 18 | const [messageText, setMessageText] = useStateWithLabel('messageText', []); 19 | const [isMessageAlert, setIsMessageAlert] = useStateWithLabel('isMessageAlert', false); 20 | 21 | const showMessage = (text = messageText, isAlert) => { 22 | setMessageText(text); 23 | setIsMessageAlert(isAlert); 24 | setIsVisibleMessage(true); 25 | 26 | setTimeout(() => { 27 | setIsVisibleMessage(false); 28 | }, 5000); 29 | }; 30 | 31 | const checkFrom = () => { 32 | const errors = []; 33 | const message = []; 34 | 35 | if (!email) { 36 | message.push('Brak email-a'); 37 | errors.push(false); 38 | } 39 | if (!username) { 40 | message.push('Brak username'); 41 | errors.push(false); 42 | } 43 | if (!userPassword) { 44 | message.push('Brak hasła'); 45 | errors.push(false); 46 | } 47 | if (!userPasswordRepeat) { 48 | message.push('Brak powtórzenia hasła'); 49 | errors.push(false); 50 | } 51 | 52 | if (userPassword !== userPasswordRepeat) { 53 | message.push('Hasła nie są jednakowe'); 54 | errors.push(false); 55 | } 56 | if (!checkEmail(email)) { 57 | message.push('Email jest niepoprawny'); 58 | errors.push(false); 59 | } 60 | 61 | return [!errors.length, message]; 62 | }; 63 | 64 | const sendCredentials = () => { 65 | trackPromise( 66 | axios 67 | .post(process.env.REACT_APP_API_REGISTER_URL, { 68 | username, 69 | email, 70 | password: userPassword, 71 | }) 72 | .then(({ data }) => { 73 | console.log(data); 74 | showMessage(`Zarejestrowałeś się poprawnie jako ${data.user.username}`); 75 | return data; 76 | }) 77 | .catch((error) => { 78 | console.log(error); 79 | console.log(error.response.data); 80 | 81 | const errorsMsg = [`Wystąpiły błędy w rejestracji:`]; 82 | 83 | Object.keys(error.response.data).map((v) => { 84 | return errorsMsg.push(error.response.data[v][0]); 85 | }); 86 | showMessage(errorsMsg, true); 87 | return error; 88 | }), 89 | ); 90 | }; 91 | 92 | const handleRegistration = (e) => { 93 | e.preventDefault(); 94 | if (checkFrom()[0]) { 95 | sendCredentials(); 96 | } else { 97 | showMessage(checkFrom()[1], true); 98 | } 99 | }; 100 | 101 | if (isLogged()) { 102 | return ; 103 | } 104 | return ( 105 |
    106 |

    Zarejestruj się

    107 | {isVisibleMessage ? : ''} 108 |
    109 | setUsername(e.target.value)} 113 | value={username} 114 | placeholder="Username" 115 | /> 116 | setEmail(e.target.value)} 120 | value={email} 121 | placeholder="Email" 122 | /> 123 | setUserPassword(e.target.value)} 127 | value={userPassword} 128 | placeholder="Hasło" 129 | /> 130 | setUserPasswordRepeat(e.target.value)} 134 | value={userPasswordRepeat} 135 | placeholder="Powtórz hasło" 136 | /> 137 | 138 |
    139 | 144 | 145 |
    146 | ); 147 | }; 148 | 149 | export default RegistrationPage; 150 | -------------------------------------------------------------------------------- /frontend/src/views/Registration/Registration.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .wrapper { 3 | position: relative; 4 | width: 95vw; 5 | margin: 30px auto; 6 | text-align: center; 7 | // &__return-button { 8 | // position: absolute; 9 | // bottom: -50px; 10 | // right: 0; 11 | // } 12 | // @media (orientation: landscape) and (min-width: 1024px) { 13 | // &__return-button { 14 | // bottom: -150px; 15 | // right: 50px; 16 | // } 17 | // } 18 | & .nav { 19 | ul { 20 | margin-top: 20px; 21 | list-style: none; 22 | text-align: center; 23 | a { 24 | text-decoration: none; 25 | color: $text-first-color; 26 | cursor: pointer; 27 | } 28 | } 29 | } 30 | } 31 | .form { 32 | display: flex; 33 | align-items: center; 34 | flex-direction: column; 35 | & .input { 36 | @include input // padding: 10px; 37 | // width: 100%; 38 | // color: white; 39 | // background: transparent; 40 | // border: none; 41 | // border-bottom: 1px solid #ccc; 42 | // max-width: 600px; 43 | // outline: none; 44 | // margin-bottom: 15px; 45 | // :placeholder { 46 | // color: white; 47 | // } 48 | ; 49 | } 50 | & .button { 51 | @include button // margin-top: 20px; 52 | // max-width: 150px; 53 | // background: white; 54 | // border: none; 55 | // color: #1b83de; 56 | // border-radius: 3px; 57 | // padding: 15px 30px; 58 | // text-transform: uppercase; 59 | // font-weight: 600; 60 | // outline: none; 61 | // cursor: pointer; 62 | // transition: 0.3s; 63 | // &:hover { 64 | // transform: scale(1.1); 65 | // } 66 | ; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /frontend/src/views/Root/Root.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import 'normalize.css'; 3 | import Home from '../Home/Home'; 4 | 5 | const Root = () => { 6 | return ( 7 |
    8 | 9 |
    10 | ); 11 | }; 12 | 13 | export default Root; 14 | -------------------------------------------------------------------------------- /frontend/src/views/Root/common.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | @import './mixins.scss'; 3 | -------------------------------------------------------------------------------- /frontend/src/views/Root/index.scss: -------------------------------------------------------------------------------- 1 | @import './reset'; 2 | @import './common'; 3 | 4 | body { 5 | background-color: $basic-color; 6 | color: $text-first-color; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/views/Root/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin neustyle( 2 | $color: $basic-color, 3 | $hover: true, 4 | $direction: topleft, 5 | $inset: false, 6 | $distance: 2px 7 | ) { 8 | border-radius: 20px; 9 | border: none; 10 | outline: none; 11 | $v: 2px; 12 | 13 | @if $distance { 14 | $v: $distance; 15 | } 16 | 17 | $topX: ($v * 2 * -1); 18 | $topY: ($v * 2 * -1); 19 | 20 | @if $direction == 'topcenter' { 21 | $topX: 0px; 22 | $topY: ($v * 2 * -1); 23 | } 24 | @if $direction == 'topright' { 25 | $topX: ($v * 2); 26 | $topY: ($v * 2 * -1); 27 | } 28 | 29 | $out: $topX $topY ($v * 3) lighten($color, 12), 30 | $topX * -1 $topY * -1 ($v * 3) darken($color, 12), 31 | inset $topX $topY ($v * 6) lighten($color, 0), 32 | inset $topX * -1 $topY * -1 ($v * 6) darken($color, 0); 33 | 34 | $in: $topX $topY ($v * 5) lighten($color, 0), $topX * -1 $topY * -1 ($v * 3) darken($color, 0), 35 | inset $topX $topY ($v * 6) lighten($color, 12), 36 | inset $topX/2 $topY/2 ($v) lighten($color, 12), 37 | inset $topX * -1 $topY * -1 ($v * 3) darken($color, 10); 38 | 39 | @if $inset { 40 | box-shadow: $in; 41 | } @else { 42 | box-shadow: $out; 43 | } 44 | 45 | @if $hover { 46 | &:hover { 47 | @if $inset { 48 | box-shadow: $out; 49 | } @else { 50 | box-shadow: $in; 51 | } 52 | } 53 | } 54 | } 55 | 56 | @mixin button( 57 | $color: $basic-color, 58 | $hover: true, 59 | $direction: topleft, 60 | $inset: false, 61 | $distance: 2px 62 | ) { 63 | margin: 20px 0; 64 | padding: 10px 20px; 65 | border: none; 66 | color: $text-first-color; 67 | background-color: $basic-color; 68 | @include neustyle($color, $hover, $direction, $inset, $distance); 69 | font-size: $m-font-size; 70 | cursor: pointer; 71 | transition: 0.3s; 72 | &:hover { 73 | color: $text-second-color; 74 | } 75 | } 76 | 77 | @mixin input( 78 | $color: $basic-color, 79 | $hover: false, 80 | $direction: topleft, 81 | $inset: true, 82 | $distance: 2px 83 | ) { 84 | @include neustyle($color, $hover, $direction, $inset, $distance); 85 | flex-basis: 90%; 86 | // height: 20px; 87 | line-height: 1.3em; 88 | background: transparent; 89 | margin: 0 1.5em; 90 | color: $text-first-color; 91 | padding: 12px; 92 | cursor: auto; 93 | &::placeholder { 94 | color: white; 95 | } 96 | } 97 | @mixin element($color: $basic-color, $direction: topright, $inset: false, $distance: 2px) { 98 | margin: 20px 0; 99 | padding: 10px 20px; 100 | border: none; 101 | color: $text-first-color; 102 | background-color: $basic-color; 103 | @include neustyle($color, $direction, $inset, $distance); 104 | font-size: $m-font-size; 105 | } 106 | -------------------------------------------------------------------------------- /frontend/src/views/Root/reset.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap'); 2 | 3 | /* Box sizing rules */ 4 | *, 5 | *::before, 6 | *::after { 7 | margin: 0; 8 | padding: 0; 9 | box-sizing: border-box; 10 | font-family: 'Lato', sans-serif; 11 | } 12 | 13 | /* Remove default padding */ 14 | ul[class], 15 | ol[class] { 16 | padding: 0; 17 | } 18 | 19 | /* Remove default margin */ 20 | body, 21 | h1, 22 | h2, 23 | h3, 24 | h4, 25 | p, 26 | ul[class], 27 | ol[class], 28 | li, 29 | figure, 30 | figcaption, 31 | blockquote, 32 | dl, 33 | dd { 34 | margin: 0; 35 | } 36 | 37 | /* Set core body defaults */ 38 | body { 39 | min-height: 100vh; 40 | scroll-behavior: smooth; 41 | text-rendering: optimizeSpeed; 42 | line-height: 1.5; 43 | } 44 | 45 | /* Remove list styles on ul, ol elements with a class attribute */ 46 | ul[class], 47 | ol[class] { 48 | list-style: none; 49 | } 50 | -------------------------------------------------------------------------------- /frontend/src/views/Root/variables.scss: -------------------------------------------------------------------------------- 1 | $basic-color: #1b83de; 2 | $first-color: #3b0918; 3 | $second-color: #b8390e; 4 | $third-color: #d9ab30; 5 | $fourth-color: #00ebeb; 6 | 7 | $text-first-color: #fff; 8 | $text-second-color: #000; 9 | $text-third-color: #aaa; 10 | 11 | $s-font-size: 14px; 12 | $m-font-size: 18px; 13 | $l-font-size: 20px; 14 | $x-font-size: 24px; 15 | -------------------------------------------------------------------------------- /frontend/src/views/Start/Start.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { NavLink } from 'react-router-dom'; 3 | import styles from './Start.module.scss'; 4 | import { isLogged } from '../../helpers/helpers'; 5 | 6 | const list = [ 7 | { name: 'logowanie', path: '/login', exact: true }, 8 | { name: 'rejestracja', path: '/registration' }, 9 | { name: 'szybki start', path: '/free_start' }, 10 | ]; 11 | 12 | const StartPage = () => { 13 | const menu = list.map((item) => { 14 | if ((item.name === 'logowanie' || item.name === 'rejestracja') && isLogged()) { 15 | return null; 16 | } 17 | return ( 18 |
  • 19 | 20 | {item.name} 21 | 22 |
  • 23 | ); 24 | }); 25 | 26 | return ( 27 | <> 28 |
    29 | 32 |
    33 | 34 | ); 35 | }; 36 | 37 | export default StartPage; 38 | -------------------------------------------------------------------------------- /frontend/src/views/Start/Start.module.scss: -------------------------------------------------------------------------------- 1 | @import '../Root/common.scss'; 2 | .wrapper { 3 | margin: 50px auto; 4 | & .nav { 5 | width: 200px; 6 | height: 200px; 7 | margin: 0 auto; 8 | & .link { 9 | list-style: none; 10 | display: flex; 11 | flex-direction: column; 12 | justify-content: space-around; 13 | align-items: center; 14 | li a { 15 | display: block; 16 | width: 140px; 17 | height: 40px; 18 | margin: 10px; 19 | border: 1px solid $basic-color; 20 | text-decoration: none; 21 | text-transform: uppercase; 22 | text-align: center; 23 | color: $text-second-color; 24 | line-height: 40px; 25 | transition: 0.3s; 26 | } 27 | li a:hover { 28 | background-color: $basic-color; 29 | color: $text-first-color; 30 | } 31 | @media (orientation: landscape) and (min-width: 1024px) { 32 | li a { 33 | width: 160px; 34 | height: 50px; 35 | margin: 20px; 36 | line-height: 50px; 37 | font-size: $l-font-size; 38 | } 39 | } 40 | } 41 | } 42 | } 43 | --------------------------------------------------------------------------------