diff --git a/.gitattributes b/.gitattributes index 516857104..ea2a81515 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,3 +8,6 @@ yarn.lock linguist-generated # Mark any vendored files as having been vendored. vendor/* linguist-vendored + +Gemfile merge=ours +Gemfile.lock merge=ours \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8ac3419f0..3bea7feff 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,16 @@ .tool-versions # Ignore ENV variable file -.env \ No newline at end of file +.env + +# Ignore Gemfiles +Gemfile +Gemfile.lock + +# ignore emacs backup files +*~ +\#*\# +.idea + +config/master.key + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..82cf78194 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.exclude": { + "**/.git": false + } +} \ No newline at end of file diff --git a/Gemfile b/Gemfile index 5efe339e6..2843f3eb7 100644 --- a/Gemfile +++ b/Gemfile @@ -34,10 +34,10 @@ gem "jbuilder" gem "redis", "~> 4.0" # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] -# gem "kredis" +gem "kredis" # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] -# gem "bcrypt", "~> 3.1.7" +gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] @@ -45,8 +45,11 @@ gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false +# Boostrap +gem 'bootstrap', '~> 4.1.1' + # Use Sass to process CSS -# gem "sassc-rails" +gem "sass-rails", '~> 5.0' # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" @@ -83,3 +86,13 @@ gem 'dotenv-rails' # gem 'paperclip # gem 'uniquify' # gem 'will_paginate' + +gem "nio4r", "~> 2.5" + +gem 'geocoder', '~> 1.3', '>= 1.3.7' + +gem 'stripe' + +# for pfp +gem 'carrierwave', '~> 3.0' +gem 'rmagick' diff --git a/Gemfile.lock b/Gemfile.lock index c3e104938..a718e5ce2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,244 +1,321 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.3.1) - actionpack (= 7.0.3.1) - activesupport (= 7.0.3.1) + actioncable (7.0.8.6) + actionpack (= 7.0.8.6) + activesupport (= 7.0.8.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.3.1) - actionpack (= 7.0.3.1) - activejob (= 7.0.3.1) - activerecord (= 7.0.3.1) - activestorage (= 7.0.3.1) - activesupport (= 7.0.3.1) + actionmailbox (7.0.8.6) + actionpack (= 7.0.8.6) + activejob (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.3.1) - actionpack (= 7.0.3.1) - actionview (= 7.0.3.1) - activejob (= 7.0.3.1) - activesupport (= 7.0.3.1) + actionmailer (7.0.8.6) + actionpack (= 7.0.8.6) + actionview (= 7.0.8.6) + activejob (= 7.0.8.6) + activesupport (= 7.0.8.6) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.3.1) - actionview (= 7.0.3.1) - activesupport (= 7.0.3.1) - rack (~> 2.0, >= 2.2.0) + actionpack (7.0.8.6) + actionview (= 7.0.8.6) + activesupport (= 7.0.8.6) + rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.3.1) - actionpack (= 7.0.3.1) - activerecord (= 7.0.3.1) - activestorage (= 7.0.3.1) - activesupport (= 7.0.3.1) + actiontext (7.0.8.6) + actionpack (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.3.1) - activesupport (= 7.0.3.1) + actionview (7.0.8.6) + activesupport (= 7.0.8.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.3.1) - activesupport (= 7.0.3.1) + activejob (7.0.8.6) + activesupport (= 7.0.8.6) globalid (>= 0.3.6) - activemodel (7.0.3.1) - activesupport (= 7.0.3.1) - activerecord (7.0.3.1) - activemodel (= 7.0.3.1) - activesupport (= 7.0.3.1) - activestorage (7.0.3.1) - actionpack (= 7.0.3.1) - activejob (= 7.0.3.1) - activerecord (= 7.0.3.1) - activesupport (= 7.0.3.1) + activemodel (7.0.8.6) + activesupport (= 7.0.8.6) + activerecord (7.0.8.6) + activemodel (= 7.0.8.6) + activesupport (= 7.0.8.6) + activestorage (7.0.8.6) + actionpack (= 7.0.8.6) + activejob (= 7.0.8.6) + activerecord (= 7.0.8.6) + activesupport (= 7.0.8.6) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.3.1) + activesupport (7.0.8.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + autoprefixer-rails (10.4.19.0) + execjs (~> 2) + base64 (0.2.0) + bcrypt (3.1.20) bindex (0.8.1) - bootsnap (1.13.0) + bootsnap (1.18.4) msgpack (~> 1.2) - builder (3.2.4) - capybara (3.37.1) + bootstrap (4.1.3) + autoprefixer-rails (>= 6.0.3) + popper_js (>= 1.12.9, < 2) + sass (>= 3.5.2) + builder (3.3.0) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - childprocess (4.1.0) - concurrent-ruby (1.1.10) + carrierwave (3.0.7) + activemodel (>= 6.0.0) + activesupport (>= 6.0.0) + addressable (~> 2.6) + image_processing (~> 1.1) + marcel (~> 1.0.0) + ssrf_filter (~> 1.0) + concurrent-ruby (1.3.4) crass (1.0.6) - debug (1.6.2) - irb (>= 1.3.6) - reline (>= 0.3.1) - digest (3.1.0) - dotenv (2.8.1) - dotenv-rails (2.8.1) - dotenv (= 2.8.1) - railties (>= 3.2) - erubi (1.11.0) - globalid (1.0.0) - activesupport (>= 5.0) - i18n (1.12.0) + csv (3.3.0) + date (3.4.0) + debug (1.9.2) + irb (~> 1.10) + reline (>= 0.3.8) + dotenv (3.1.4) + dotenv-rails (3.1.4) + dotenv (= 3.1.4) + railties (>= 6.1) + erubi (1.13.0) + execjs (2.10.0) + ffi (1.17.0) + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86_64-darwin) + geocoder (1.8.3) + base64 (>= 0.1.0) + csv (>= 3.0.0) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.6) concurrent-ruby (~> 1.0) - importmap-rails (1.1.5) + image_processing (1.13.0) + mini_magick (>= 4.9.5, < 5) + ruby-vips (>= 2.0.17, < 3) + importmap-rails (2.0.3) actionpack (>= 6.0.0) + activesupport (>= 6.0.0) railties (>= 6.0.0) - io-console (0.5.11) - irb (1.4.1) - reline (>= 0.3.0) - jbuilder (2.11.5) + io-console (0.7.2) + irb (1.14.1) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - loofah (2.18.0) + kredis (1.7.0) + activemodel (>= 6.0.0) + activesupport (>= 6.0.0) + redis (>= 4.2, < 6) + logger (1.6.1) + loofah (2.23.1) crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) + nokogiri (>= 1.12.0) + mail (2.8.1) mini_mime (>= 0.1.1) - marcel (1.0.2) + net-imap + net-pop + net-smtp + marcel (1.0.4) matrix (0.4.2) - method_source (1.0.0) - mini_mime (1.1.2) - minitest (5.16.3) - msgpack (1.5.6) - mysql2 (0.5.4) - net-imap (0.2.3) - digest + method_source (1.1.0) + mini_magick (4.13.2) + mini_mime (1.1.5) + minitest (5.25.1) + msgpack (1.7.3) + mysql2 (0.5.6) + net-imap (0.5.0) + date net-protocol - strscan - net-pop (0.1.1) - digest + net-pop (0.1.2) net-protocol + net-protocol (0.2.2) timeout - net-protocol (0.1.3) - timeout - net-smtp (0.3.1) - digest + net-smtp (0.5.0) net-protocol - timeout - nio4r (2.5.8) - nokogiri (1.13.8-arm64-darwin) + nio4r (2.7.4) + nokogiri (1.16.7-arm64-darwin) + racc (~> 1.4) + nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.8-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) - public_suffix (5.0.0) - puma (5.6.5) + observer (0.1.2) + pkg-config (1.5.8) + popper_js (1.16.1) + psych (5.1.2) + stringio + public_suffix (6.0.1) + puma (5.6.9) nio4r (~> 2.0) - racc (1.6.0) - rack (2.2.4) - rack-test (2.0.2) + racc (1.8.1) + rack (2.2.10) + rack-test (2.1.0) rack (>= 1.3) - rails (7.0.3.1) - actioncable (= 7.0.3.1) - actionmailbox (= 7.0.3.1) - actionmailer (= 7.0.3.1) - actionpack (= 7.0.3.1) - actiontext (= 7.0.3.1) - actionview (= 7.0.3.1) - activejob (= 7.0.3.1) - activemodel (= 7.0.3.1) - activerecord (= 7.0.3.1) - activestorage (= 7.0.3.1) - activesupport (= 7.0.3.1) + rails (7.0.8.6) + actioncable (= 7.0.8.6) + actionmailbox (= 7.0.8.6) + actionmailer (= 7.0.8.6) + actionpack (= 7.0.8.6) + actiontext (= 7.0.8.6) + actionview (= 7.0.8.6) + activejob (= 7.0.8.6) + activemodel (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) bundler (>= 1.15.0) - railties (= 7.0.3.1) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 7.0.8.6) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.4.3) - loofah (~> 2.3) - railties (7.0.3.1) - actionpack (= 7.0.3.1) - activesupport (= 7.0.3.1) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (7.0.8.6) + actionpack (= 7.0.8.6) + activesupport (= 7.0.8.6) method_source rake (>= 12.2) thor (~> 1.0) zeitwerk (~> 2.5) - rake (13.0.6) - redis (4.8.0) - regexp_parser (2.5.0) - reline (0.3.1) + rake (13.2.1) + rb-fsevent (0.11.2) + rb-inotify (0.11.1) + ffi (~> 1.0) + rdoc (6.7.0) + psych (>= 4.0.0) + redis (4.8.1) + regexp_parser (2.9.2) + reline (0.5.10) io-console (~> 0.5) - rexml (3.2.5) + rexml (3.3.9) + rmagick (6.0.1) + observer (~> 0.1) + pkg-config (~> 1.4) + ruby-vips (2.2.2) + ffi (~> 1.12) + logger rubyzip (2.3.2) - selenium-webdriver (4.4.0) - childprocess (>= 0.5, < 5.0) + sass (3.7.4) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sass-rails (5.1.0) + railties (>= 5.2.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + selenium-webdriver (4.10.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - sprockets (4.1.1) + sprockets (3.7.5) + base64 concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) - stimulus-rails (1.1.0) - railties (>= 6.0.0) - strscan (3.0.4) - tailwindcss-rails (2.0.12-arm64-darwin) - railties (>= 6.0.0) - tailwindcss-rails (2.0.12-x86_64-linux) + ssrf_filter (1.2.0) + stimulus-rails (1.3.4) railties (>= 6.0.0) - thor (1.2.1) - timeout (0.3.0) - turbo-rails (1.1.1) + stringio (3.1.1) + stripe (13.2.0) + tailwindcss-rails (3.0.0) + railties (>= 7.0.0) + tailwindcss-ruby + tailwindcss-ruby (3.4.14-arm64-darwin) + tailwindcss-ruby (3.4.14-x86_64-darwin) + tailwindcss-ruby (3.4.14-x86_64-linux) + thor (1.3.2) + tilt (2.4.0) + timeout (0.4.1) + turbo-rails (2.0.11) actionpack (>= 6.0.0) - activejob (>= 6.0.0) railties (>= 6.0.0) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) - web-console (4.2.0) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webdrivers (5.0.0) + webdrivers (5.3.1) nokogiri (~> 1.6) rubyzip (>= 1.3.0) - selenium-webdriver (~> 4.0) - websocket (1.2.9) - websocket-driver (0.7.5) + selenium-webdriver (~> 4.0, < 4.11) + websocket (1.2.11) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.0) + zeitwerk (2.6.18) PLATFORMS - arm64-darwin-20 + arm64-darwin + arm64-darwin-23 + x86_64-darwin x86_64-linux DEPENDENCIES + bcrypt (~> 3.1.7) bootsnap + bootstrap (~> 4.1.1) capybara + carrierwave (~> 3.0) debug dotenv-rails + geocoder (~> 1.3, >= 1.3.7) importmap-rails jbuilder + kredis mysql2 (~> 0.5) + nio4r (~> 2.5) puma (~> 5.0) rails (~> 7.0.3, >= 7.0.3.1) redis (~> 4.0) + rmagick + sass-rails (~> 5.0) selenium-webdriver sprockets-rails stimulus-rails + stripe tailwindcss-rails turbo-rails tzinfo-data @@ -249,4 +326,4 @@ RUBY VERSION ruby 3.1.2p20 BUNDLED WITH - 2.3.18 + 2.5.18 diff --git a/README.md b/README.md index 85f6c86ae..8ac3209fb 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ Smith College CSC223: Software Engineering\ Starter App for ValetBike project +#katie was here :3 + ## Environment Configuration As you configure your environment you should **keep a log** where you **write down all the steps you take** including **each command you type**. You will inevitably run into errors setting up your development environment and maintaining a meticulous log will allow others to help you troubleshoot. Ignore this recommendation at your own peril, but don't say you haven't been warned :] diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index b06fc42ac..a2d906a5b 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,5 +1,6 @@ //= link_tree ../images -//= link_directory ../stylesheets .css +//= link application.css +//= link_directory ../stylesheets .scss //= link_tree ../../javascript .js //= link_tree ../../../vendor/javascript .js //= link_tree ../builds diff --git a/app/assets/images/MHBike.png b/app/assets/images/MHBike.png new file mode 100644 index 000000000..27e6e0eca Binary files /dev/null and b/app/assets/images/MHBike.png differ diff --git a/app/assets/images/MHEndTrip.png b/app/assets/images/MHEndTrip.png new file mode 100644 index 000000000..619a52b75 Binary files /dev/null and b/app/assets/images/MHEndTrip.png differ diff --git a/app/assets/images/MHPaymentSuccess.png b/app/assets/images/MHPaymentSuccess.png new file mode 100644 index 000000000..24f4ccc3f Binary files /dev/null and b/app/assets/images/MHPaymentSuccess.png differ diff --git a/app/assets/images/MHmoney.jpg b/app/assets/images/MHmoney.jpg new file mode 100644 index 000000000..1fc457e69 Binary files /dev/null and b/app/assets/images/MHmoney.jpg differ diff --git a/app/assets/images/MHvehicle.webp b/app/assets/images/MHvehicle.webp new file mode 100644 index 000000000..bf632d45a Binary files /dev/null and b/app/assets/images/MHvehicle.webp differ diff --git a/app/assets/images/bike.svg b/app/assets/images/bike.svg new file mode 100644 index 000000000..6a3d09430 --- /dev/null +++ b/app/assets/images/bike.svg @@ -0,0 +1,10 @@ + diff --git a/app/assets/images/color-theme.svg b/app/assets/images/color-theme.svg new file mode 100644 index 000000000..caeb069d4 --- /dev/null +++ b/app/assets/images/color-theme.svg @@ -0,0 +1,12 @@ + + \ No newline at end of file diff --git a/app/assets/images/cycling.svg b/app/assets/images/cycling.svg new file mode 100644 index 000000000..9c2234cc1 --- /dev/null +++ b/app/assets/images/cycling.svg @@ -0,0 +1,33 @@ + + + + \ No newline at end of file diff --git a/app/assets/images/edit.svg b/app/assets/images/edit.svg new file mode 100644 index 000000000..54bc42433 --- /dev/null +++ b/app/assets/images/edit.svg @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/app/assets/images/fallback/default.png b/app/assets/images/fallback/default.png new file mode 100644 index 000000000..a83bbd969 Binary files /dev/null and b/app/assets/images/fallback/default.png differ diff --git a/app/assets/images/favicon.ico b/app/assets/images/favicon.ico new file mode 100644 index 000000000..ffb2aed28 Binary files /dev/null and b/app/assets/images/favicon.ico differ diff --git a/app/assets/images/ghoulia.jpg b/app/assets/images/ghoulia.jpg new file mode 100644 index 000000000..f165cad2c Binary files /dev/null and b/app/assets/images/ghoulia.jpg differ diff --git a/app/assets/images/locations.svg b/app/assets/images/locations.svg new file mode 100644 index 000000000..ac5ad7615 --- /dev/null +++ b/app/assets/images/locations.svg @@ -0,0 +1,27 @@ + + + + \ No newline at end of file diff --git a/app/assets/images/logo.png b/app/assets/images/logo.png new file mode 100644 index 000000000..7184b3aaa Binary files /dev/null and b/app/assets/images/logo.png differ diff --git a/app/assets/images/map-marker.png b/app/assets/images/map-marker.png new file mode 100644 index 000000000..9f85490c0 Binary files /dev/null and b/app/assets/images/map-marker.png differ diff --git a/app/assets/images/pin.svg b/app/assets/images/pin.svg new file mode 100644 index 000000000..993e648bd --- /dev/null +++ b/app/assets/images/pin.svg @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/app/assets/stylesheets/account.css b/app/assets/stylesheets/account.css new file mode 100644 index 000000000..0b255e07a --- /dev/null +++ b/app/assets/stylesheets/account.css @@ -0,0 +1,16 @@ +.avatar-wrapper { + margin: 0 auto; + width: 150px; + height: 150px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 50%; + border: 3px solid var(--theme-color); +} + +.avatar-wrapper img { + width: 100%; + height: 100%; + border-radius: 50%; +} \ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 288b9ab71..7c35026b8 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -12,4 +12,5 @@ * *= require_tree . *= require_self - */ + + */ \ No newline at end of file diff --git a/app/assets/stylesheets/footer.css b/app/assets/stylesheets/footer.css new file mode 100644 index 000000000..2bfd0828f --- /dev/null +++ b/app/assets/stylesheets/footer.css @@ -0,0 +1,11 @@ +footer { + background-color: var(--theme-color); + width: 100%; + padding: 3rem; + margin-top: 5rem; + min-height: 300px; +} + +footer .page-section { + margin: 5rem auto; +} \ No newline at end of file diff --git a/app/assets/stylesheets/form.css b/app/assets/stylesheets/form.css new file mode 100644 index 000000000..1ca78a081 --- /dev/null +++ b/app/assets/stylesheets/form.css @@ -0,0 +1,63 @@ +.form-container { + background-color: var(--white-color); + margin-top: 5rem; + padding: 2rem; + border-radius: var(--widget-radius); +} + +.form-wrapper { + margin-top: 2rem; +} + +.form-wrapper input[type=submit], .form-wrapper button { + display: block; + margin: auto; + width: 100%; +} + +.form-title { + font-family: var(--title-font); + font-weight: 500; + font-size: 1.5em; + text-align: center; +} + +.form-field label { + font-size: 0.8em; +} + +.form-field .form-control { + border-radius: var(--btn-radius); + border: var(--btn-thickness) solid var(--gray-color); +} + +.error-message { + font-size: 0.8em; + margin-bottom: 0; +} + +.error-message li { + list-style-type: circle; +} + +.form-links { + margin-top: 1em; + text-align: center; +} + +.form-links p a { + color: var(--theme-color); +} + +.logo-header { + height: 6em; + width: auto; + margin: 0 auto; +} + +/** Account page **/ + +.sm-icon { + width: 15px; + height: 15px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/global.css b/app/assets/stylesheets/global.css index ff48f1abe..2848f7042 100644 --- a/app/assets/stylesheets/global.css +++ b/app/assets/stylesheets/global.css @@ -5,7 +5,6 @@ * { margin: 0; padding: 0; - z-index: 1; } html, body { @@ -22,6 +21,30 @@ body { -ms-text-size-adjust:100%; } +caption{ + font-size:15pt; + -webkit-text-size-adjust:100%; + -moz-text-size-adjust:100%; + -ms-text-size-adjust:100%; + text-align: center; +} + +sub-caption{ + font-size:12pt; + -webkit-text-size-adjust:100%; + -moz-text-size-adjust:100%; + -ms-text-size-adjust:100%; + text-align: center; +} + +a.link-regular { + color: var(--theme-color); +} + +a.link-black { + color: var(--black-color); +} + #site-container{ position: relative; width: 100%; @@ -29,7 +52,146 @@ body { height: auto !important; min-height: 100%; font-family: var(--body-font); - font-weight: 400; + font-weight: 100; color: var(--black-color); background: var(--white-color); } + +input[type=submit]:disabled { + background-color: var(--gray-color); + color: var(--white-color); + border-color: var(--gray-color); +} + +.bg-fill { + background-color: var(--theme-color); + position: absolute; + width: 100%; + height: auto; + min-height: 100%; + padding-bottom: 3rem; +} + +.section-heading { + font-size: 1.3em; + font-family: var(--title-font); + margin-bottom: 0.8rem; +} + +.section-heading-h2 { + font-size: 1em; + font-family: var(--title-font); + margin-bottom: 0.8rem; +} + +.custom-btn { + padding: 0.5rem 1.5rem; + border-radius: var(--btn-radius); + transition: 0.1s ease; +} + +.button-container { + display: flex; + align-items: center; + gap: 10px; /* Optional: adds some space between the button and the link */ +} + +.btn-fill { + background: var(--theme-color) !important; + color: var(--white-color) !important; + border: var(--btn-thickness) solid var(--theme-color) !important; +} + +.btn-fill:hover { + background: var(--white-color) !important; + color: var(--black-color) !important; +} + +.btn-outline { + background: var(--white-color) !important; + border: var(--btn-thickness) solid var(--theme-color) !important; +} + +.togglestuff .btn-toggle { + font-family: var(--body-font) !important; + font-weight: 200; + padding: 0.5rem 1.5rem; + border-radius: var(--btn-radius); + transition: 0.1s ease; +} + +.togglestuff .btn-toggle-outline { + background: var(--white-color) !important; + border: var(--btn-thickness) solid var(--theme-color) !important; +} + +.togglestuff .btn-toggle-outline:hover { + background: var(--theme-color) !important; + color: var(--white-color) !important; + border: var(--btn-thickness) solid var(--theme-color) !important; +} + +input[type="radio"]:checked + label { + background: var(--theme-color) !important; + color: var(--white-color) !important; + border: var(--btn-thickness) solid var(--theme-color) !important; +} + +.btn-outline:hover { + background: var(--theme-color) !important; + color: var(--white-color) !important; +} + +.btn-fill-danger { + background: var(--danger-color); + color: var(--white-color); + border: var(--btn-thickness) solid var(--danger-color); +} + +.btn-fill-danger:hover { + background-color: var(--white-color); + color: var(--danger-color); +} + +.btn-invalid { + background: var(--invalid_fill-color); + color: var(--invalid_text-color); + border: var(--btn-thickness) solid var(--invalid_fill-color); +} + +.btn-underline { + position: relative; + display: flex; + align-items: center; + justify-content: space-between; + transition: 0.2s ease-in-out; +} + +.btn-underline::before { + content: ''; + position: absolute; + left: 0; + bottom: -2px; + height: 1.5px; + width: 100%; +} + +.btn-underline.regular::before { + background-color: var(--black-color); +} + +.btn-underline.danger::before { + background-color: var(--danger-color); +} + +.btn-underline:hover { + opacity: 0.7; +} + +.highlighter { + color: var(--theme-color); +} + +.danger { + color: var(--danger-color); +} \ No newline at end of file diff --git a/app/assets/stylesheets/header.css b/app/assets/stylesheets/header.css new file mode 100644 index 000000000..0d723548b --- /dev/null +++ b/app/assets/stylesheets/header.css @@ -0,0 +1,63 @@ +.navbar { + margin: 3em auto; + width: 70%; + background: rgba(255, 255, 255, 0.2); + box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(5px); + border-radius: var(--widget-radius); +} + +ul.header { + list-style: none; + padding: 1rem 2rem; + margin: 0; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; +} + +ul.header li { + display: block; +} + +.navbar li a { + text-decoration: none; + font-family: var(--title-font); + font-size: 1rem; + color: var(--black-color); + font-weight: 300; + transition: 0.2s ease-in-out; +} + +.navbar li a:hover { + color: var(--theme-color); +} + +.navbar.navbar-mobile { + display: none; + background: rgba(255, 255, 255, 0.2); + box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(5px); + width: 100%; + margin: 0; + padding: 1em; +} + +/***********************************/ +/* Responsiveness */ +/***********************************/ + +@media (max-width:868px) { + .navbar.navbar-desktop { + display: none; + } + + .navbar.navbar-mobile { + display: block; + } + + .navbar.navbar-mobile .show.collapse { + visibility: visible; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/pages.css b/app/assets/stylesheets/pages.css index 16bd64b55..0b2caf208 100644 --- a/app/assets/stylesheets/pages.css +++ b/app/assets/stylesheets/pages.css @@ -5,7 +5,7 @@ .page-section { max-width: 80em; width: 100%; - margin-top: 4em; + margin-top: 10em; } .page-section .section-inner { @@ -15,33 +15,114 @@ .page-section .section-title { font-family: var(--title-font); - font-weight: 500; + font-weight: 300; font-size: 2.5em; margin-bottom: 1em; } -.record-row { - padding: 0.5em 1.25em 0.5em 1.25em; - font-size: 0.85em; - line-height: 1.75em; +.page-section .section-caption { + font-family: var(--body-font); + font-weight: 200; + font-size: 1.2em; + overflow-wrap: break-word; + margin-bottom: 1em; +} + +.page-section .section-banner { + max-height: 300px; + margin: auto; +} + +.step-block { + margin: 1rem; + padding: 1rem; + display: block; + position: relative; + border: 1px solid var(--light-black-color); + border-radius: var(--widget-radius); + background-color: var(--white-color); +} + +.step-block.small { + height: 180px; +} + +.step-block.medium { + height: 300px; + padding: 2rem; +} + +.step-block::before { + content: ''; + opacity: 0; + display: block; + position: absolute; + left: 5px; + top: 5px; + width: 100%; + height: 100%; + background-color: var(--theme-color); + border: 1px solid var(--theme-color); + border-radius: var(--widget-radius); + z-index: -1; +} + +.step-block:hover { + transition: all 0.2s ease-in; + background-color: var(--theme-color); } -.record-row.even { - background: var(--medium-white-color); +.step-block h4 { + font-family: var(--title-font); + text-align: center; + margin-bottom: 2rem; } -.record-row.odd { - background: var(--dark-white-color); +.step-block p { + text-align: center; } +.step-block .svg-icon { + width: auto; + height: 3em; + margin: 1em auto; +} + +.leaflet-popup-content { + font-family: var(--body-font) !important; + font-weight: 200 !important; +} + +.leaflet-popup-content .title { + font-size: 1rem !important; + color: var(--theme-color) !important; +} + +.leaflet-popup-content .body { + font-weight: 100 !important; + font-size: 1em !important; +} + +.record-row { + padding: 2em 1.25em; + font-size: 0.85em; + border-bottom: 1px solid var(--gray-color); +} + +.record-row .record-name { + font-family: var(--title-font); + font-size: 1rem; + margin-bottom: 0.8rem; + color: var(--theme-color); +} /***********************************/ /* Responsiveness */ /***********************************/ -@media (max-width:48em) { +@media (max-width:868px) { .page-section { - margin-top: 3em; + margin-top: 3em; } .page-section .section-title { diff --git a/app/assets/stylesheets/stations.css b/app/assets/stylesheets/stations.css new file mode 100644 index 000000000..d3fcb949e --- /dev/null +++ b/app/assets/stylesheets/stations.css @@ -0,0 +1,5 @@ +.breadcrumb-container { + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/app/assets/stylesheets/variables.css b/app/assets/stylesheets/variables.css index 915c14dd3..c96fe840d 100644 --- a/app/assets/stylesheets/variables.css +++ b/app/assets/stylesheets/variables.css @@ -1,6 +1,8 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,100..900&display=swap'); + :root { - --title-font: 'Rubik', 'Arial'; - --body-font: 'Rubik', 'Arial'; + --title-font: "Climate Crisis", sans-serif; + --body-font: "Inter", sans-serif; --black-color: #160919; --light-black-color: #2E2230; @@ -9,5 +11,12 @@ --dark-white-color: #F3F2F3; --medium-white-color: #FDFCFD; --white-color: #FFFFFF; + --invalid_text-color: #818181; + --invalid_fill-color: #f2f2f2; + --theme-color: #7C88F4; + --btn-radius: 0.3rem; + --widget-radius: 0.5rem; + --btn-thickness: 2px; + --danger-color: #8B0000; } \ No newline at end of file diff --git a/app/controllers/access_controller.rb b/app/controllers/access_controller.rb new file mode 100644 index 000000000..71cc9f352 --- /dev/null +++ b/app/controllers/access_controller.rb @@ -0,0 +1,20 @@ +class AccessController < ApplicationController + before_action :disable_navigation + + def create + # Process log in information + @user = User.find_by(email: params[:email]) + if !!@user && @user&.authenticate(params[:password]) + session[:user_id] = @user[:id] + redirect_to account_index_path + else + flash[:notice] = "Something went wrong. Please check your email and password." + redirect_to log_in_path + end + end + + def destroy + session[:user_id] = nil + redirect_to root_path + end +end diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb new file mode 100644 index 000000000..b642f771d --- /dev/null +++ b/app/controllers/account_controller.rb @@ -0,0 +1,109 @@ +require 'date' + +class AccountController < ApplicationController + before_action :get_user_info_from_session + before_action :redirect_edit, only: [:edit, :update] + before_action :remove_pfp_upload, only: [:edit_profile_img, :upload_profile_img] + def index + @trips = Trip.all + if !logged_in? || !@user + redirect_to log_in_path + else + set_up_edit_mode() + + if !!@user.subscription_id + # Search for the user's available subscription + @subscription = Stripe::Subscription.retrieve(@user.subscription_id) + + @subscription.items.data.each do |item| + @meter_id = item.plan.meter + @start_date = Time.at(item.created).to_datetime.strftime('%F %H:%M') + @status = item.plan.active ? "Active" : "Inactive" + end + + # Get the product by meter_id + @product = Product.find_by(meter_id: @meter_id) + + @upcoming_invoice = Stripe::Invoice.upcoming({customer: @user.stripe_customer_id}) + + @invoice_total = @upcoming_invoice.amount_due + @created_time = Time.at(@upcoming_invoice.created).to_datetime.strftime('%F %H:%M') + @attempted = Time.now < Time.at(@upcoming_invoice.created) ? 'Payment not started' : @upcoming_invoice.attempted ? 'Paid' : 'Unpaid' + + end + end + end + + def cancel_subscription + if !!@user && !!@user.subscription_id + # Search for the user's available subscription + subscription_id = @user.subscription_id + Stripe::Subscription.cancel(subscription_id) + @user.update(subscription_id: nil) + redirect_to account_index_path + end + end + + def destroy + if !!@user + session[:user_id] = nil + @user.destroy + redirect_to root_path + end + end + + def edit + @enable_edit = !@enable_edit + render :index + end + + def update + if !!@user && @user.update(user_params) + flash[:notice] = "Your details were updated successfully!" + redirect_to account_index_path + else + render :index, status: 422 + end + end + + def edit_profile_img + @enable_profile_upload = !@enable_profile_upload + render :index + end + + def upload_profile_img + if !!@user && @user.update_attribute(:avatar, params[:avatar]) + flash[:notice] = "Avatar uploaded successfully!" + redirect_to account_index_path + else + render :index, status: 422, error: "Something went wrong. Please try again." + end + end + + private + + def user_params + params.require(:user).permit(:name, :phone_number) + end + + def set_up_edit_mode + @enable_edit = false + @enable_profile_upload = false + end + + def redirect_edit + # Cancel the edits + redirect_to account_index_path if params[:cancel_edit] + end + + def remove_pfp_upload + if !!@user && params[:cancel_edit_pfp] + @user.remove_avatar! + @user.remove_avatar = true + @user.save + @user.reload + redirect_to account_index_path + end + end + +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 09705d12a..c52dd4b75 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,2 +1,20 @@ class ApplicationController < ActionController::Base + + helper_method :get_user_info_from_session + helper_method :logged_in? + helper_method :disable_navigation + helper_method :station + def get_user_info_from_session + @user = User.find_by(id: session[:user_id]) + end + def logged_in? + # Check user's log in status + session[:user_id].present? + end + def disable_navigation + # For pages that don't need header/footer for navigation + # For example: sign in/up forms + @disable_header = true + @disable_footer = true + end end diff --git a/app/controllers/bikes_controller.rb b/app/controllers/bikes_controller.rb new file mode 100644 index 000000000..036a4f038 --- /dev/null +++ b/app/controllers/bikes_controller.rb @@ -0,0 +1,12 @@ +class BikesController < ApplicationController + def _row + @bikes = Bike.all.order(identifier: :asc) + end + + def index + end + def show + @bike = Bike.find(params[:id]) + end + +end diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb new file mode 100644 index 000000000..513b8c4f8 --- /dev/null +++ b/app/controllers/main_controller.rb @@ -0,0 +1,7 @@ +class MainController < ApplicationController + def index + end + + def contact + end +end diff --git a/app/controllers/password_resets_controller.rb b/app/controllers/password_resets_controller.rb new file mode 100644 index 000000000..998b29e18 --- /dev/null +++ b/app/controllers/password_resets_controller.rb @@ -0,0 +1,52 @@ +class PasswordResetsController < ApplicationController + before_action :disable_navigation + + def create + # Process email and send reset link + @user = User.find_by(email: params[:email]) + + if !!@user + # Send email in the background + PasswordMailer.with(user: @user).reset.deliver_later + flash[:notice] = "An email will be sent with a link to reset your password." + else + flash[:notice] = "An error occured. Please try again." + end + + redirect_to password_reset_url + end + + def edit + # Find the user with the given token + if params[:token] + @user = User.find_signed(params[:token], purpose: "password_reset") + else + redirect_to log_in_path + end + rescue ActiveSupport::MessageVerifier::InvalidSignature + redirect_to password_reset_url, notice: "Your token has expired. Please try again" + end + + def update + # Actually updates the password + @user = User.find_signed(params[:token], purpose: "password_reset") + + if @user.update(password_params) + flash[:notice] = "Your password was reset successfully. Please sign in." + redirect_to log_in_path + else + render :edit, status: 422 # have to set status. otherwise, the errors won't render + end + + rescue ActiveSupport::MessageVerifier::InvalidSignature + redirect_to password_reset_url, notice: "Your token has expired. Please try again" + end + + private + + def password_params + params.require(:user).permit(:password, :password_confirmation) + end + + +end diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb new file mode 100644 index 000000000..8d2b5cef7 --- /dev/null +++ b/app/controllers/payments_controller.rb @@ -0,0 +1,50 @@ +class PaymentsController < ApplicationController + before_action :set_product, only: %i[ create ] + before_action :get_user_info_from_session + + # GET /products + def index + @products = Product.all + end + + def create + if !logged_in? || !@user + redirect_to log_in_path + else + @session = Stripe::Checkout::Session.create({ + customer: @user.stripe_customer_id, + line_items: [{ + # Provide the exact Price ID (e.g. pr_1234) of the product you want to sell + price: @product.stripe_price_id + }], + mode: 'subscription', + success_url: success_url + "?session_id={CHECKOUT_SESSION_ID}&customer_email={CUSTOMER_EMAIL}", + cancel_url: payments_url, + }) + + redirect_to @session.url, status: 303, allow_other_host: true + end + end + + def success + if params[:session_id] + # Display message on successfull subscription + session_expanded = Stripe::Checkout::Session.retrieve({ + id: params[:session_id], + expand: ["line_items", "subscription"]}) + + @user.update(subscription_id: session_expanded.subscription.id) + + session_expanded.line_items.data.each do |item| + @product = Product.find_by(stripe_product_id: item.price.product) + end + else + redirect_to root_url + end + end + + private + def set_product + @product = Product.find(params[:id]) + end +end diff --git a/app/controllers/stations_controller.rb b/app/controllers/stations_controller.rb index 88090af16..f12a39aff 100644 --- a/app/controllers/stations_controller.rb +++ b/app/controllers/stations_controller.rb @@ -1,7 +1,58 @@ class StationsController < ApplicationController def index + @user = get_user_info_from_session + @uCoords = request.location.coordinates + unless @user&.current_trip_id.nil? + @trip = Trip.find(@user.current_trip_id) + end + Station.find_by(name: "State St/Mass Central Rail Trail").update(address: "298 State St Northampton MA") + @stations = Station.all.order(identifier: :asc) + + @lats = Array.new # array of latitudes + @longs = Array.new # array of longitudes + @names = Array.new # station names + @identifiers = Array.new # station identifierss + @ids = Array.new # station ids + @addresses = Array.new # REYFUCKS UP + @bikes = Array.new # REYFUCKS UP + + @userid = @user&.id.present? || false #does the user id exist? + @tripid = @user&.current_trip_id.present? || false #does trip id exist? + @iduser = @user&.id #user id + @idtrip = @user&.current_trip_id #trip id + # sorry for the terrible naming + + @stations.each do |s| + if s.latitude && s.longitude then # block when geocode fails + @lats.append(s.latitude) + @longs.append(s.longitude) + @names.append(s.name) + @identifiers.append(s.identifier) + @ids.append(s.id) + @addresses.append(s.address) #REYFUCKS UP + @bikes.append(Bike.where(current_station_id: s.id).length) #REYFUCKS UP + end + end + end + + def show + @user = get_user_info_from_session + @station = Station.find(params[:id]) + if @user + unless @user.current_trip_id.nil? + @trip = Trip.find(@user.current_trip_id) + end + end + end + + def _row + @user = get_user_info_from_session + if @user + unless @user.current_trip_id.nil? + @trip = Trip.find(@user.current_trip_id) + end + end + end end - -end diff --git a/app/controllers/trips_controller.rb b/app/controllers/trips_controller.rb new file mode 100644 index 000000000..10416cfe6 --- /dev/null +++ b/app/controllers/trips_controller.rb @@ -0,0 +1,90 @@ +class TripsController < ApplicationController + def new + @trip = Trip.new + @station = Station.find(params[:station_id]) + @user = User.find(params[:user_id]) + @bike = Bike.where(current_station_id: params[:station_id]).first + end + + def index + @user = get_user_info_from_session + @trips = Trip.all.order(end_time: :desc) + @past_trips = @trips.where.not(end_time: nil) + @curr_trip = @trips.find_by(end_time: nil) + if @curr_trip + @curr_address = Station.find(@curr_trip.start_station_is).address + end + end + + def create + @trip = Trip.new(trip_params) + if @trip.save + @bike = Bike.find(@trip.bike_id) + @station = Station.find(@trip.start_station_is) + @user = User.find(@trip.user_id) + @user.update(current_trip_id: @trip.id) + @bike.update(is_available: false, current_station_id: nil) + redirect_to confirm_path(trip_id: @trip.id) + else + render :new + end + end + def show + @trip = Trip.find(params[:trip_id]) + end + + def confirmation + @trip = Trip.find(params[:trip_id]) + end + + def end_confirmation + @user = User.find(params[:user_id]) + if !!@user.subscription_id + @trip = Trip.find(params[:id]) + user_stripe_id = @user.stripe_customer_id + # Search for the user's available subscription + subscription = Stripe::Subscription.retrieve(@user.subscription_id) + + # Get the meter event associated with the subscription + subscription.items.data.each do |item| + @meter_id = item.plan.meter + end + + # Get the product by meter_id + product = Product.find_by(meter_id: @meter_id) + + # Create the meter + @meter = Stripe::Billing::MeterEvent.create({ + event_name: product.meter_event, + payload: { + value: @trip.time_minutes.to_s, # this should be number of minutes + stripe_customer_id: user_stripe_id + } + }) + @bike = Bike.find(@trip.bike_id) + @user.update(current_trip_id: nil) + @bike.update(is_available: true, current_station_id: params[:end_station_id]) + @trip.update(end_time: DateTime.now, end_station_id: params[:end_station_id]) + else + # No subscription + # Make the trip status *Payment pending* + redirect_to payments_url + end + end + + def update + end + + def edit + end + + def trip_params + params.require(:trip).permit(:id, :bike_id, :user_id, :start_station_is, :start_time) + end + + private + def trip_time(trip) + trip + end + +end diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb new file mode 100644 index 000000000..2bb9baaab --- /dev/null +++ b/app/controllers/user_controller.rb @@ -0,0 +1,30 @@ +class UserController < ApplicationController + before_action :disable_navigation + + def new + # Display the sign up form + @user = User.new + end + + def create + # Process sign up information + @user = User.new(user_params) + if @user.save + # redirect_to log_in_path # make them log in + + session[:user_id] = @user[:id] # don't make them log in :) + redirect_to account_index_path + else + render :new, status: 422 + end + end + + private + + def user_params + # Return params that include only the given fields + # and set the permitted attribute for the object to true. + # (useful for limiting which attributes should be allowed for updating) + params.require(:user).permit(:email, :password, :password_confirmation) + end +end diff --git a/app/helpers/access_helper.rb b/app/helpers/access_helper.rb new file mode 100644 index 000000000..342c6ff9f --- /dev/null +++ b/app/helpers/access_helper.rb @@ -0,0 +1,2 @@ +module AccessHelper +end diff --git a/app/helpers/account_helper.rb b/app/helpers/account_helper.rb new file mode 100644 index 000000000..6d3694a49 --- /dev/null +++ b/app/helpers/account_helper.rb @@ -0,0 +1,2 @@ +module AccountHelper +end diff --git a/app/helpers/bikes_helper.rb b/app/helpers/bikes_helper.rb new file mode 100644 index 000000000..a2645e4e1 --- /dev/null +++ b/app/helpers/bikes_helper.rb @@ -0,0 +1,2 @@ +module BikesHelper +end diff --git a/app/helpers/main_helper.rb b/app/helpers/main_helper.rb new file mode 100644 index 000000000..826effed9 --- /dev/null +++ b/app/helpers/main_helper.rb @@ -0,0 +1,2 @@ +module MainHelper +end diff --git a/app/helpers/password_resets_helper.rb b/app/helpers/password_resets_helper.rb new file mode 100644 index 000000000..0c9d96ecf --- /dev/null +++ b/app/helpers/password_resets_helper.rb @@ -0,0 +1,2 @@ +module PasswordResetsHelper +end diff --git a/app/helpers/payments_helper.rb b/app/helpers/payments_helper.rb new file mode 100644 index 000000000..c1b884f80 --- /dev/null +++ b/app/helpers/payments_helper.rb @@ -0,0 +1,2 @@ +module PaymentsHelper +end diff --git a/app/helpers/trips_helper.rb b/app/helpers/trips_helper.rb new file mode 100644 index 000000000..04f333d46 --- /dev/null +++ b/app/helpers/trips_helper.rb @@ -0,0 +1,2 @@ +module TripsHelper +end diff --git a/app/helpers/user_helper.rb b/app/helpers/user_helper.rb new file mode 100644 index 000000000..0147c3fe6 --- /dev/null +++ b/app/helpers/user_helper.rb @@ -0,0 +1,2 @@ +module UserHelper +end diff --git a/app/javascript/application.js b/app/javascript/application.js index 0d7b49404..05e26fa16 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1,3 +1,10 @@ +//= require bootstrap-sprockets // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails import "@hotwired/turbo-rails" import "controllers" + +import "bootstrap" + +import "leaflet" +import "leaflet-providers" +import "geocoder" \ No newline at end of file diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js new file mode 100644 index 000000000..30826086c --- /dev/null +++ b/app/javascript/controllers/map_controller.js @@ -0,0 +1,161 @@ +import { Controller } from "@hotwired/stimulus" +import L from 'leaflet' + +export default class extends Controller { + static targets = [ "container" ]; + static values = { + lat: Array, + long: Array, + name: Array, + identifier: Array, + id: Array, + address: Array, + bike: Array, + userid: Boolean, + tripid: Boolean, + iduser: String, + idtrip: String, + userCoords: {type: Array, default: ['42.3172951', '-72.6386734'] }, + pfp: {type: String, default: '/images/fallback/default.png'} + }; + + + connect(){ + console.log("Controller Connected!!"); + + this.containerTarget.style.height = "400px"; // pulled this out here ig? should likely be in a css script + + this.createMap(); + + let purpleIcon = '/images/map-marker.png'; + + // Add the markers for each station + for (let i = 0; i < this.idValue.length; i++) { + console.log("loading item " + i); + let lat = this.latValue[i]; + let long = this.longValue[i]; + let name = this.nameValue[i]; + let identifier = this.identifierValue[i]; + let id = this.idValue[i]; + let address = this.addressValue[i]; + let bike = this.bikeValue[i]; + if (lat !== null && long !== null && name !== null) { + this.addMarker(lat, long, purpleIcon, name, identifier, id, address, bike); + } + } + } + + /* initializes the map for future use */ + createMap() { + // Create Leaflet map on map element. + this.map = L.map(this.containerTarget); + L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { + attribution: '© OpenStreetMap contributors' + }).addTo(this.map); + + // Add a you-are-here + let uCoords = this.userCoordsValue; // user lat long + let pfpath = this.pfpValue; // ProFile pic PATH + + this.addMarker(uCoords[0], uCoords[1], pfpath, null, null, null, null, null); + + console.log("Entering from [" + uCoords[0] + ", " + uCoords[1] + "]"); + console.log("User profile from `" + pfpath + "`"); + + // Set map's center. + const center = L.latLng(uCoords[0], uCoords[1]); + + /*const northamptonLat = '42.3255'; // what it says on the tag + const northamptonLng = '-72.646'; // rough center of northampton + const center = L.latLng(northamptonLat, northamptonLng); + */ + this.map.setView(center, 13.5); // consider changing zoom + console.log("Map Loaded!!"); + } + + /* adds a marker to the leaflet */ + addMarker(lat, long, iconPath, name, identifier, id, address, bike) { + + let size = id === null ? [30, 30] : [30, 40]; // size of the icon + + let icon = L.icon({ + iconUrl: iconPath, + iconSize: size + }); + + // Place a marker on the location with custom icon + let marker = L.marker([lat, long], {icon: icon}).addTo(this.map); + if (id !== null) { // here markers + marker.bindPopup(this.popupContent(name, identifier, id, address, bike)); + } + } + +/* helper method to get the button_to link to place in the popup */ + +/* popupContent(name, id, address, bike) { + return ` +
<%= link_to('Sign up', sign_up_path) %>
+<%= link_to('Forgot your password', password_reset_path) %>
+| Total amount | +$<%= @invoice_total.to_f/100 %> | +
|---|---|
| Due on | +<%= @created_time %> | +
| Payment status | +<%= @attempted %> | +
| Plan | +<%= @product.name %> plan | +
|---|---|
| Description | +<%= @product.desc %> | +
| Start date | +<%= @start_date %> | +
| Status | +<%= @status %> | +
You have no subscription available.
+Please go to <%= link_to('Pricing', {controller: 'payments' , action: 'index'}) %> to select a plan.
+ <% end %> +