diff --git a/.gitignore b/.gitignore index 6db3c9a5bc..cd9d8b5c66 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,63 @@ !/log/.keep /tmp +# Ignore this annoying MACOS file which is a caching file and keeps thumbnails .DS_Store + +# Hide the .env because it's full of secrets! +/.env + +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal +betsy_development +betsy_test + + +# Ignore this annoying MACOS file which is a caching file and keeps thumbnails +.DS_store + +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +#*.rbc +capybara-*.html +.rspec + +/public/system +/coverage/ +/spec/tmp +**.orig +rerun.txt +pickle-email-*.html + +# TODO Comment out this rule if you are OK with secrets being uploaded to the repo +config/initializers/secret_token.rb + +# Only include if you have production secrets in this file, which is no longer a Rails default +# config/secrets.yml + +# dotenv +# TODO Comment out this rule if environment variables can be committed + +# Hide the .env becuase of secrets +/.env + +## Environment normalization: +/.bundle +/vendor/bundle + +# these should all be checked in to normalize the environment: +# Gemfile.lock, .ruby-version, .ruby-gemset + +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: +.rvmrc + +# if using bower-rails ignore default bower_components path bower.json files +/vendor/assets/bower_components +*.bowerrc +bower.json + +# Ignore pow environment settings +.powenv + +# Ignore Byebug command history file. +.byebug_history diff --git a/.ruby-gemset b/.ruby-gemset deleted file mode 100644 index d5c660823f..0000000000 --- a/.ruby-gemset +++ /dev/null @@ -1 +0,0 @@ -betsy diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 2bf1c1ccf3..0000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.3.1 diff --git a/Gemfile b/Gemfile index c69f4ddde9..265cb49b04 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,22 @@ source 'https://rubygems.org' ruby '2.3.1' +#gem for authenticated user actions +#gem 'devise', '~> 4.2' + +#gem for oAuth github Authentication +gem 'omniauth' +gem 'omniauth-github' + +#make it easier to read +gem 'awesome_print' + + +#simpler forms? +gem 'simple_form' +#make it possible to authenticate from scratch +gem 'bcrypt' + # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.2.6' # Use postgresql as the database for Active Record @@ -34,7 +50,12 @@ gem 'sdoc', '~> 0.4.0', group: :doc group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console + gem 'factory_girl_rails', "~> 4.0" gem 'byebug' + gem 'sqlite3' + gem 'dotenv-rails' + gem 'pry' + end group :development do @@ -43,4 +64,13 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' + gem 'better_errors' +end + +group :test do + gem 'minitest-reporters' + gem 'simplecov' end + +gem 'pg', group: :production +gem 'rails_12factor', group: :production diff --git a/Gemfile.lock b/Gemfile.lock index 20975578b8..84fc1fce5b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -36,11 +36,19 @@ GEM minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) + ansi (1.5.0) arel (6.0.3) + awesome_print (1.7.0) + bcrypt (3.1.11) + better_errors (2.1.1) + coderay (>= 1.0.0) + erubis (>= 2.6.6) + rack (>= 0.9.0) binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) - byebug (8.2.5) + byebug (9.0.6) + coderay (1.1.1) coffee-rails (4.1.1) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.1.x) @@ -48,33 +56,75 @@ GEM coffee-script-source execjs coffee-script-source (1.10.0) - concurrent-ruby (1.0.1) + concurrent-ruby (1.0.2) debug_inspector (0.0.2) + docile (1.1.5) + dotenv (2.1.1) + dotenv-rails (2.1.1) + dotenv (= 2.1.1) + railties (>= 4.0, < 5.1) erubis (2.7.0) - execjs (2.6.0) - globalid (0.3.6) + execjs (2.7.0) + factory_girl (4.7.0) + activesupport (>= 3.0.0) + factory_girl_rails (4.7.0) + factory_girl (~> 4.7.0) + railties (>= 3.0.0) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + globalid (0.3.7) activesupport (>= 4.1.0) + hashie (3.4.6) i18n (0.7.0) - jbuilder (2.4.1) + jbuilder (2.6.0) activesupport (>= 3.0.0, < 5.1) multi_json (~> 1.2) - jquery-rails (4.1.1) + jquery-rails (4.2.1) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (1.8.3) + jwt (1.5.6) loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.4) mime-types (>= 1.16, < 4) - mime-types (3.0) + method_source (0.8.2) + mime-types (3.1) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0221) - mini_portile2 (2.0.0) - minitest (5.8.4) - multi_json (1.11.3) - nokogiri (1.6.7.2) - mini_portile2 (~> 2.0.0.rc2) + mime-types-data (3.2016.0521) + mini_portile2 (2.1.0) + minitest (5.9.1) + minitest-reporters (1.1.11) + ansi + builder + minitest (>= 5.0) + ruby-progressbar + multi_json (1.12.1) + multi_xml (0.5.5) + multipart-post (2.0.0) + nokogiri (1.6.8.1) + mini_portile2 (~> 2.1.0) + oauth2 (1.2.0) + faraday (>= 0.8, < 0.10) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (>= 1.2, < 3) + omniauth (1.3.1) + hashie (>= 1.2, < 4) + rack (>= 1.0, < 3) + omniauth-github (1.1.2) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) + omniauth-oauth2 (1.4.0) + oauth2 (~> 1.0) + omniauth (~> 1.2) + pg (0.19.0) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) rack (1.6.4) rack-test (0.6.3) rack (>= 1.0) @@ -97,40 +147,58 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) + rails_12factor (0.0.3) + rails_serve_static_assets + rails_stdout_logging + rails_serve_static_assets (0.0.5) + rails_stdout_logging (0.0.5) railties (4.2.6) actionpack (= 4.2.6) activesupport (= 4.2.6) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (11.1.2) + rake (11.3.0) rdoc (4.2.2) json (~> 1.4) + ruby-progressbar (1.8.1) sass (3.4.22) - sass-rails (5.0.4) - railties (>= 4.0.0, < 5.0) + sass-rails (5.0.6) + railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sdoc (0.4.1) + sdoc (0.4.2) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - spring (1.7.1) - sprockets (3.6.0) + simple_form (3.3.1) + actionpack (> 4, < 5.1) + activemodel (> 4, < 5.1) + simplecov (0.12.0) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.0) + slop (3.6.0) + spring (2.0.0) + activesupport (>= 4.2) + sprockets (3.7.0) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.0.4) + sprockets-rails (3.2.0) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + sqlite3 (1.3.12) thor (0.19.1) thread_safe (0.3.5) - tilt (2.0.2) - turbolinks (2.5.3) - coffee-rails + tilt (2.0.5) + turbolinks (5.0.1) + turbolinks-source (~> 5) + turbolinks-source (5.0.0) tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (3.0.0) + uglifier (3.0.2) execjs (>= 0.3.0, < 3) web-console (2.3.0) activemodel (>= 4.0) @@ -142,14 +210,28 @@ PLATFORMS ruby DEPENDENCIES + awesome_print + bcrypt + better_errors byebug coffee-rails (~> 4.1.0) + dotenv-rails + factory_girl_rails (~> 4.0) jbuilder (~> 2.0) jquery-rails + minitest-reporters + omniauth + omniauth-github + pg + pry rails (= 4.2.6) + rails_12factor sass-rails (~> 5.0) sdoc (~> 0.4.0) + simple_form + simplecov spring + sqlite3 turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) @@ -158,4 +240,4 @@ RUBY VERSION ruby 2.3.1p112 BUNDLED WITH - 1.13.5 + 1.13.6 diff --git a/README.md b/README.md index 220a0423c4..f37989492a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# bEtsy +# bEtsy(Vampazon) [b]Etsy will be an online store where a wide variety of products can be listed and sold by any user. In this project we will focus on reinforcing the major components of Rails, Model Validation, as well as introducing some more complex logic such as user authentication. ## Project Learning Goals @@ -104,25 +104,45 @@ As a signed-in user, I **can**: - Retire a product from being sold, which hides it from browsing - View an account page to edit/update my existing products - View an account page showing my order fulfillment -- On the order fulfillment page: - - Total Revenue - - Total Revenue by status - - Total number of orders by status - - Filter orders displayed by status - - Link to each individual order - - A list of orders including at least one of my products: - - Each order item sold by me with a quantity and line-item subtotal - - A link to the item description page - - DateTime the order was placed - - Link to transition the order item to marked as shipped - - The current status of the order ("pending", "paid", "complete", "cancelled") -- View an individual order to see the user's: - - Name - - Email address - - Mailing address - - Last four digits of their credit card - - Credit card expiration date +--- + +**[customized]** +As a signed-in user, I can see: + +- User Account that contains basic User Information; +- User Account that has Buyer Management and Seller Management Panel; +- In Buyer Management Panel, a list of all orders of the current logged in User(buyer); + - Each order linked to its order confirmation page, with detail information; + - Listing order's id#, creation time, total price, a CANCEL button; +- In Buyer Management Panel, the order can be cancelled. After pushing CANCEL button, the order status changed to "cancel". +- In Buyer Management Panel, filter orders displayed by status(pending, paid, completed, cancelled) + +--- + +**[refactored]** +- Total Revenue of all order items +- Total Revenue by status +- Total number of order items +- Total number of order items)by status +- A list of **order items** sold by me: + - Filter **order items** displayed by status + - Link to each individual order: + - Each order item sold by me with a quantity and line-item subtotal + - A link to the item description page + - DateTime the order was placed + - The current status of the order item ("pending", "paid", "fulfilled", "cancelled") + - A button to transition the order item to marked as "ship", where order item status changed to "fulfilled" +- The order# that associated with this order item: +- View the individual order to see the user's: + - Name + - Email address + - Mailing address + - Last four digits of their credit card + - Credit card expiration date + +--- + As a signed-in user, I **cannot**: - Review my own products diff --git a/README_vampazon.md b/README_vampazon.md new file mode 100644 index 0000000000..4379e68c09 --- /dev/null +++ b/README_vampazon.md @@ -0,0 +1,35 @@ +== README +# Vampazon +Shop till you drop again, at Vampazon! We have a wide array of products to meet all your bloody needs. Minions, Home Decor, dental care, and more! Commence shopping [here][ ____ herokuapp.com]. Vampazon is an e-commerce venue build with Ruby on Rails. + +### Authors +-[Elle Vargas][https://github.com/ellevargas] +-[Maya Wang][https://github.com/mayawang] +-[Sassa Kitka][https://github.com/RedSquirrelious] +-[Trish Griego][https://github.com/Trishthedish] + + ### + All authors are students at [Ada Developers Academy](http://adadevelopersacademy.org/) + +### Ruby Version +- 4.7..? + +### Built with +* [foundations](#) - The CSS framework +* [OAuth](#) - Session management... +* [Rails](#) - to general? +* [factory_girl][https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md] + +### Best Practices/key take aways. +- Maybe a link to each of our own take aways? + + +## Dont know where to put this: + +- Assignment Guidelines can be found [here][https://github.com/mayawang/Vampazon]. + + +### known Bugs - idea for grouping + + +Examples of good readme: https://gist.github.com/PurpleBooth/109311bb0361f32d87a2 diff --git a/app/assets/images/Fashion/Armor.jpg b/app/assets/images/Fashion/Armor.jpg new file mode 100644 index 0000000000..c85cee8b6e Binary files /dev/null and b/app/assets/images/Fashion/Armor.jpg differ diff --git a/app/assets/images/Fashion/Cape.jpg b/app/assets/images/Fashion/Cape.jpg new file mode 100644 index 0000000000..7982adccd7 Binary files /dev/null and b/app/assets/images/Fashion/Cape.jpg differ diff --git a/app/assets/images/Fashion/Capes.gif b/app/assets/images/Fashion/Capes.gif new file mode 100644 index 0000000000..f6840624f6 Binary files /dev/null and b/app/assets/images/Fashion/Capes.gif differ diff --git a/app/assets/images/Fashion/Goggles.jpg b/app/assets/images/Fashion/Goggles.jpg new file mode 100644 index 0000000000..4440b021e8 Binary files /dev/null and b/app/assets/images/Fashion/Goggles.jpg differ diff --git a/app/assets/images/Fashion/Pajamas.png b/app/assets/images/Fashion/Pajamas.png new file mode 100644 index 0000000000..bccd68c712 Binary files /dev/null and b/app/assets/images/Fashion/Pajamas.png differ diff --git a/app/assets/images/Fashion/Spandex.gif b/app/assets/images/Fashion/Spandex.gif new file mode 100644 index 0000000000..b6a44f435d Binary files /dev/null and b/app/assets/images/Fashion/Spandex.gif differ diff --git a/app/assets/images/Fashion/Spandex.jpg b/app/assets/images/Fashion/Spandex.jpg new file mode 100644 index 0000000000..4ac69cac84 Binary files /dev/null and b/app/assets/images/Fashion/Spandex.jpg differ diff --git a/app/assets/images/Fashion/Tuxedo.jpg b/app/assets/images/Fashion/Tuxedo.jpg new file mode 100644 index 0000000000..aaf6de690b Binary files /dev/null and b/app/assets/images/Fashion/Tuxedo.jpg differ diff --git a/app/assets/images/Fashion/Tuxedoes.gif b/app/assets/images/Fashion/Tuxedoes.gif new file mode 100644 index 0000000000..8885ee56b9 Binary files /dev/null and b/app/assets/images/Fashion/Tuxedoes.gif differ diff --git a/app/assets/images/Home_Decor/Candles.jpg b/app/assets/images/Home_Decor/Candles.jpg new file mode 100644 index 0000000000..b5a245b244 Binary files /dev/null and b/app/assets/images/Home_Decor/Candles.jpg differ diff --git a/app/assets/images/Home_Decor/Coffins.jpg b/app/assets/images/Home_Decor/Coffins.jpg new file mode 100644 index 0000000000..7ebf5ab01e Binary files /dev/null and b/app/assets/images/Home_Decor/Coffins.jpg differ diff --git a/app/assets/images/Home_Decor/Curtains.jpg b/app/assets/images/Home_Decor/Curtains.jpg new file mode 100644 index 0000000000..7424551b9e Binary files /dev/null and b/app/assets/images/Home_Decor/Curtains.jpg differ diff --git a/app/assets/images/Home_Decor/Goblets.jpg b/app/assets/images/Home_Decor/Goblets.jpg new file mode 100644 index 0000000000..15439dc768 Binary files /dev/null and b/app/assets/images/Home_Decor/Goblets.jpg differ diff --git a/app/assets/images/Home_Decor/Roses.jpg b/app/assets/images/Home_Decor/Roses.jpg new file mode 100644 index 0000000000..63d91f4017 Binary files /dev/null and b/app/assets/images/Home_Decor/Roses.jpg differ diff --git a/app/assets/images/Home_Decor/Snackles.jpg b/app/assets/images/Home_Decor/Snackles.jpg new file mode 100644 index 0000000000..ad2276392c Binary files /dev/null and b/app/assets/images/Home_Decor/Snackles.jpg differ diff --git a/app/assets/images/Homepage/MLogo.png b/app/assets/images/Homepage/MLogo.png new file mode 100644 index 0000000000..b7a52a3e4f Binary files /dev/null and b/app/assets/images/Homepage/MLogo.png differ diff --git a/app/assets/images/Homepage/Vampazon.png b/app/assets/images/Homepage/Vampazon.png new file mode 100644 index 0000000000..47ca00e708 Binary files /dev/null and b/app/assets/images/Homepage/Vampazon.png differ diff --git a/app/assets/images/Homepage/Vampire1.jpg b/app/assets/images/Homepage/Vampire1.jpg new file mode 100644 index 0000000000..6e7b2ede98 Binary files /dev/null and b/app/assets/images/Homepage/Vampire1.jpg differ diff --git a/app/assets/images/Minions/Bats.jpg b/app/assets/images/Minions/Bats.jpg new file mode 100644 index 0000000000..ed75b40596 Binary files /dev/null and b/app/assets/images/Minions/Bats.jpg differ diff --git a/app/assets/images/Minions/Chad.png b/app/assets/images/Minions/Chad.png new file mode 100644 index 0000000000..6a074713dd Binary files /dev/null and b/app/assets/images/Minions/Chad.png differ diff --git a/app/assets/images/Minions/Gargoyles.png b/app/assets/images/Minions/Gargoyles.png new file mode 100644 index 0000000000..419add148a Binary files /dev/null and b/app/assets/images/Minions/Gargoyles.png differ diff --git a/app/assets/images/Minions/Ghosts.png b/app/assets/images/Minions/Ghosts.png new file mode 100644 index 0000000000..4151f1a459 Binary files /dev/null and b/app/assets/images/Minions/Ghosts.png differ diff --git a/app/assets/images/Minions/Igor.gif b/app/assets/images/Minions/Igor.gif new file mode 100644 index 0000000000..6412b81ead Binary files /dev/null and b/app/assets/images/Minions/Igor.gif differ diff --git a/app/assets/images/Minions/Igor.jpg b/app/assets/images/Minions/Igor.jpg new file mode 100644 index 0000000000..a901e04908 Binary files /dev/null and b/app/assets/images/Minions/Igor.jpg differ diff --git a/app/assets/images/Minions/Wolves.jpg b/app/assets/images/Minions/Wolves.jpg new file mode 100644 index 0000000000..75b9584701 Binary files /dev/null and b/app/assets/images/Minions/Wolves.jpg differ diff --git a/app/assets/images/Personal_Care/Biteguard.jpg b/app/assets/images/Personal_Care/Biteguard.jpg new file mode 100644 index 0000000000..b8de944690 Binary files /dev/null and b/app/assets/images/Personal_Care/Biteguard.jpg differ diff --git a/app/assets/images/Personal_Care/Book.jpg b/app/assets/images/Personal_Care/Book.jpg new file mode 100644 index 0000000000..db386e807a Binary files /dev/null and b/app/assets/images/Personal_Care/Book.jpg differ diff --git a/app/assets/images/Personal_Care/Bronzer.jpg b/app/assets/images/Personal_Care/Bronzer.jpg new file mode 100644 index 0000000000..72d589b3b7 Binary files /dev/null and b/app/assets/images/Personal_Care/Bronzer.jpg differ diff --git a/app/assets/images/Personal_Care/Mask.png b/app/assets/images/Personal_Care/Mask.png new file mode 100644 index 0000000000..8af067a31e Binary files /dev/null and b/app/assets/images/Personal_Care/Mask.png differ diff --git a/app/assets/images/Personal_Care/Sunscreen.jpg b/app/assets/images/Personal_Care/Sunscreen.jpg new file mode 100644 index 0000000000..97551a1d14 Binary files /dev/null and b/app/assets/images/Personal_Care/Sunscreen.jpg differ diff --git a/app/assets/images/Personal_Care/Toothbrushes.jpg b/app/assets/images/Personal_Care/Toothbrushes.jpg new file mode 100644 index 0000000000..ebd876d887 Binary files /dev/null and b/app/assets/images/Personal_Care/Toothbrushes.jpg differ diff --git a/app/assets/images/count_zero.jpg b/app/assets/images/count_zero.jpg new file mode 100644 index 0000000000..e3b2c42da6 Binary files /dev/null and b/app/assets/images/count_zero.jpg differ diff --git a/app/assets/images/vamp_favicon.ico b/app/assets/images/vamp_favicon.ico new file mode 100644 index 0000000000..0d8ce7e7ec Binary files /dev/null and b/app/assets/images/vamp_favicon.ico differ diff --git a/app/assets/javascripts/homepages.coffee b/app/assets/javascripts/homepages.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/homepages.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/orders.coffee b/app/assets/javascripts/orders.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/orders.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/products.coffee b/app/assets/javascripts/products.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/products.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/reviews.coffee b/app/assets/javascripts/reviews.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/reviews.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/sessions.coffee b/app/assets/javascripts/sessions.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/sessions.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/users.coffee b/app/assets/javascripts/users.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/users.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/app.css b/app/assets/stylesheets/app.css new file mode 100644 index 0000000000..897a4ca797 --- /dev/null +++ b/app/assets/stylesheets/app.css @@ -0,0 +1,190 @@ +/************************* OVERALL *************************/ + +body { + min-width: 100%; + font-size: 14pt; + font-family: Arial, Helvetica, sans-serif; +} + +.basic { + margin: 2% 12% 1% 12%; +} + +.basic h2 { + font-size: 2.5rem; + font-weight: bold; + margin-bottom: 2%; +} + +.basic p { + padding: 1%; + font-weight: bold; +} + +header { + background-color: black; + height: 17%; + margin-bottom: 2%; + padding: 3% 3% 3% 0; +} + +img.logo { + margin: auto; + height: auto; + width: auto; + max-width: 100%; + max-height: 100%; +} + +img.frontpage { + float: left; + display: inline-block; +} + +/*.top-bar ul { + background-color: black; +}*/ + +/*.top-bar-left { + max-width: 50%; +}*/ + +/*.top-bar-left img { + height: auto; + width: auto; + max-width: 100%; + max-height: 100%; + float:center; +}*/ + +/*.top-bar-right a { + font-size: 1.75rem; +}*/ + +#product-navigation { + text-align: center; +} + +nav li { + background-color: black; + display: inline-block; + padding-right: 5%; +} + +nav li a { + background-color: black; + color: white; +} + +h3 { + font-size: 2.75rem; + font-weight: bold; + text-align: center; + margin: 2% 0 3% 0; +} + +.column { + padding: 1% 1.5% 3% 1.5%; +} + +.quantity { + width: 15%; +} + +.headline { + font-size: 1.75rem; + font-weight: bold; + text-align: center; +} + +.headline a { + color: black; +} + +.headline a:hover, .headline a:focus { + color: #680604; +} + +img.product_photo { + display: inline-block; + margin: 10% 0; + max-height: 9em; +} + +.row ul { + list-style: none; +} + +/*.product-detail { + max-height: 9em; +}*/ + + /**************************************/ +/**HERO SECTION **/ + /**************************************/ +/* +.hero { + background-color: gray; + padding: 50px 30px; + height: 15%; +} + + /************************************** +/**FOOTER **/ + /**************************************/ + + +/*#login-logout a { + color: white; + display: inline-block; + float: right; + min-width: 20%; +}*/ + + + +/*.row ul a { + color: black; +} + +.row ul a:hover { + color: #680604; +}*/ + + +/*.columns { + column-count: 3; + /*column-gap: 8vw; + }*/ + + + + +/*.card p { + float: center; +} + + +/*.product-info { + min-height: 6.5em; +}*/ + +/*.product-info ul { + list-style: none; + margin-left: 0; + margin-bottom: .25em; + font-size: 1rem; + text-align: center; +}*/ + +/*.product-info ul a { + color: black; +}*/ + +/*.product-info ul a:hover { + color: red; +}*/ + +/*.product-info li { + float: center; +}*/ diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index f9cd5b3483..19e6687f7c 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -13,3 +13,11 @@ *= require_tree . *= require_self */ + @import url('foundation.css'); + + /*@import url('foundation_and_overrides.css');*/ + +@import url('app.css'); + +/*require 'foundation'*/ +/*require 'app' */ diff --git a/app/assets/stylesheets/foundation.css b/app/assets/stylesheets/foundation.css new file mode 100644 index 0000000000..66aca962de --- /dev/null +++ b/app/assets/stylesheets/foundation.css @@ -0,0 +1,4194 @@ +@charset "UTF-8"; +/** + * Foundation for Sites by ZURB + * Version 6.2.3 + * foundation.zurb.com + * Licensed under MIT Open Source + */ +/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS and IE text size adjust after device orientation change, + * without disabling user zoom. + */ +html { + font-family: sans-serif; + /* 1 */ + -ms-text-size-adjust: 100%; + /* 2 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } + +/** + * Remove default margin. + */ +body { + margin: 0; } + +/* HTML5 display definitions + ========================================================================== */ +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; } + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ +audio, +canvas, +progress, +video { + display: inline-block; + /* 1 */ + vertical-align: baseline; + /* 2 */ } + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ +audio:not([controls]) { + display: none; + height: 0; } + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22. + */ +[hidden], +template { + display: none; } + +/* Links + ========================================================================== */ +/** + * Remove the gray background color from active links in IE 10. + */ +a { + background-color: transparent; } + +/** + * Improve readability of focused elements when they are also in an + * active/hover state. + */ +a:active, +a:hover { + outline: 0; } + +/* Text-level semantics + ========================================================================== */ +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ +abbr[title] { + border-bottom: 1px dotted; } + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ +b, +strong { + font-weight: bold; } + +/** + * Address styling not present in Safari and Chrome. + */ +dfn { + font-style: italic; } + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ +h1 { + font-size: 2em; + margin: 0.67em 0; } + +/** + * Address styling not present in IE 8/9. + */ +mark { + background: #ff0; + color: #000; } + +/** + * Address inconsistent and variable font size in all browsers. + */ +small { + font-size: 80%; } + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } + +sup { + top: -0.5em; } + +sub { + bottom: -0.25em; } + +/* Embedded content + ========================================================================== */ +/** + * Remove border when inside `a` element in IE 8/9/10. + */ +img { + border: 0; } + +/** + * Correct overflow not hidden in IE 9/10/11. + */ +svg:not(:root) { + overflow: hidden; } + +/* Grouping content + ========================================================================== */ +/** + * Address margin not present in IE 8/9 and Safari. + */ +figure { + margin: 1em 40px; } + +/** + * Address differences between Firefox and other browsers. + */ +hr { + box-sizing: content-box; + height: 0; } + +/** + * Contain overflow in all browsers. + */ +pre { + overflow: auto; } + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; } + +/* Forms + ========================================================================== */ +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ +button, +input, +optgroup, +select, +textarea { + color: inherit; + /* 1 */ + font: inherit; + /* 2 */ + margin: 0; + /* 3 */ } + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ +button { + overflow: visible; } + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ +button, +select { + text-transform: none; } + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + /* 2 */ + cursor: pointer; + /* 3 */ } + +/** + * Re-set default cursor for disabled elements. + */ +button[disabled], +html input[disabled] { + cursor: not-allowed; } + +/** + * Remove inner padding and border in Firefox 4+. + */ +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; } + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ +input { + line-height: normal; } + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; } + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome. + */ +input[type="search"] { + -webkit-appearance: textfield; + /* 1 */ + box-sizing: content-box; + /* 2 */ } + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; } + +/** + * Define consistent border, margin, and padding. + * [NOTE] We don't enable this ruleset in Foundation, because we want the
element to have plain styling. + */ +/* fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; + } */ +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ +legend { + border: 0; + /* 1 */ + padding: 0; + /* 2 */ } + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ +textarea { + overflow: auto; } + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ +optgroup { + font-weight: bold; } + +/* Tables + ========================================================================== */ +/** + * Remove most spacing between table cells. + */ +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; } + +.foundation-mq { + font-family: "small=0em&medium=40em&large=64em&xlarge=75em&xxlarge=90em"; } + +html { + font-size: 100%; + box-sizing: border-box; } + +*, +*::before, +*::after { + box-sizing: inherit; } + +body { + padding: 0; + margin: 0; + font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; + font-weight: normal; + line-height: 1.5; + color: #0a0a0a; + background: #fefefe; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +img { + max-width: 100%; + height: auto; + -ms-interpolation-mode: bicubic; + display: inline-block; + vertical-align: middle; } + +textarea { + height: auto; + min-height: 50px; + border-radius: 0; } + +select { + width: 100%; + border-radius: 0; } + +#map_canvas img, +#map_canvas embed, +#map_canvas object, +.map_canvas img, +.map_canvas embed, +.map_canvas object, +.mqa-display img, +.mqa-display embed, +.mqa-display object { + max-width: none !important; } + +button { + -webkit-appearance: none; + -moz-appearance: none; + background: transparent; + padding: 0; + border: 0; + border-radius: 0; + line-height: 1; } + [data-whatinput='mouse'] button { + outline: 0; } + +.is-visible { + display: block !important; } + +.is-hidden { + display: none !important; } + +.row { + max-width: 75rem; + margin-left: auto; + margin-right: auto; } + .row::before, .row::after { + content: ' '; + display: table; } + .row::after { + clear: both; } + .row.collapse > .column, .row.collapse > .columns { + padding-left: 0; + padding-right: 0; } + .row .row { + max-width: none; + margin-left: -0.625rem; + margin-right: -0.625rem; } + @media screen and (min-width: 40em) { + .row .row { + margin-left: -0.9375rem; + margin-right: -0.9375rem; } } + .row .row.collapse { + margin-left: 0; + margin-right: 0; } + .row.expanded { + max-width: none; } + .row.expanded .row { + margin-left: auto; + margin-right: auto; } + +.column, .columns { + width: 100%; + float: left; + padding-left: 0.625rem; + padding-right: 0.625rem; } + @media screen and (min-width: 40em) { + .column, .columns { + padding-left: 0.9375rem; + padding-right: 0.9375rem; } } + .column:last-child:not(:first-child), .columns:last-child:not(:first-child) { + float: right; } + .column.end:last-child:last-child, .end.columns:last-child:last-child { + float: left; } + +.column.row.row, .row.row.columns { + float: none; } + .row .column.row.row, .row .row.row.columns { + padding-left: 0; + padding-right: 0; + margin-left: 0; + margin-right: 0; } + +.small-1 { + width: 8.33333%; } + +.small-push-1 { + position: relative; + left: 8.33333%; } + +.small-pull-1 { + position: relative; + left: -8.33333%; } + +.small-offset-0 { + margin-left: 0%; } + +.small-2 { + width: 16.66667%; } + +.small-push-2 { + position: relative; + left: 16.66667%; } + +.small-pull-2 { + position: relative; + left: -16.66667%; } + +.small-offset-1 { + margin-left: 8.33333%; } + +.small-3 { + width: 25%; } + +.small-push-3 { + position: relative; + left: 25%; } + +.small-pull-3 { + position: relative; + left: -25%; } + +.small-offset-2 { + margin-left: 16.66667%; } + +.small-4 { + width: 33.33333%; } + +.small-push-4 { + position: relative; + left: 33.33333%; } + +.small-pull-4 { + position: relative; + left: -33.33333%; } + +.small-offset-3 { + margin-left: 25%; } + +.small-5 { + width: 41.66667%; } + +.small-push-5 { + position: relative; + left: 41.66667%; } + +.small-pull-5 { + position: relative; + left: -41.66667%; } + +.small-offset-4 { + margin-left: 33.33333%; } + +.small-6 { + width: 50%; } + +.small-push-6 { + position: relative; + left: 50%; } + +.small-pull-6 { + position: relative; + left: -50%; } + +.small-offset-5 { + margin-left: 41.66667%; } + +.small-7 { + width: 58.33333%; } + +.small-push-7 { + position: relative; + left: 58.33333%; } + +.small-pull-7 { + position: relative; + left: -58.33333%; } + +.small-offset-6 { + margin-left: 50%; } + +.small-8 { + width: 66.66667%; } + +.small-push-8 { + position: relative; + left: 66.66667%; } + +.small-pull-8 { + position: relative; + left: -66.66667%; } + +.small-offset-7 { + margin-left: 58.33333%; } + +.small-9 { + width: 75%; } + +.small-push-9 { + position: relative; + left: 75%; } + +.small-pull-9 { + position: relative; + left: -75%; } + +.small-offset-8 { + margin-left: 66.66667%; } + +.small-10 { + width: 83.33333%; } + +.small-push-10 { + position: relative; + left: 83.33333%; } + +.small-pull-10 { + position: relative; + left: -83.33333%; } + +.small-offset-9 { + margin-left: 75%; } + +.small-11 { + width: 91.66667%; } + +.small-push-11 { + position: relative; + left: 91.66667%; } + +.small-pull-11 { + position: relative; + left: -91.66667%; } + +.small-offset-10 { + margin-left: 83.33333%; } + +.small-12 { + width: 100%; } + +.small-offset-11 { + margin-left: 91.66667%; } + +.small-up-1 > .column, .small-up-1 > .columns { + width: 100%; + float: left; } + .small-up-1 > .column:nth-of-type(1n), .small-up-1 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-1 > .column:nth-of-type(1n+1), .small-up-1 > .columns:nth-of-type(1n+1) { + clear: both; } + .small-up-1 > .column:last-child, .small-up-1 > .columns:last-child { + float: left; } + +.small-up-2 > .column, .small-up-2 > .columns { + width: 50%; + float: left; } + .small-up-2 > .column:nth-of-type(1n), .small-up-2 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-2 > .column:nth-of-type(2n+1), .small-up-2 > .columns:nth-of-type(2n+1) { + clear: both; } + .small-up-2 > .column:last-child, .small-up-2 > .columns:last-child { + float: left; } + +.small-up-3 > .column, .small-up-3 > .columns { + width: 33.33333%; + float: left; } + .small-up-3 > .column:nth-of-type(1n), .small-up-3 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-3 > .column:nth-of-type(3n+1), .small-up-3 > .columns:nth-of-type(3n+1) { + clear: both; } + .small-up-3 > .column:last-child, .small-up-3 > .columns:last-child { + float: left; } + +.small-up-4 > .column, .small-up-4 > .columns { + width: 25%; + float: left; } + .small-up-4 > .column:nth-of-type(1n), .small-up-4 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-4 > .column:nth-of-type(4n+1), .small-up-4 > .columns:nth-of-type(4n+1) { + clear: both; } + .small-up-4 > .column:last-child, .small-up-4 > .columns:last-child { + float: left; } + +.small-up-5 > .column, .small-up-5 > .columns { + width: 20%; + float: left; } + .small-up-5 > .column:nth-of-type(1n), .small-up-5 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-5 > .column:nth-of-type(5n+1), .small-up-5 > .columns:nth-of-type(5n+1) { + clear: both; } + .small-up-5 > .column:last-child, .small-up-5 > .columns:last-child { + float: left; } + +.small-up-6 > .column, .small-up-6 > .columns { + width: 16.66667%; + float: left; } + .small-up-6 > .column:nth-of-type(1n), .small-up-6 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-6 > .column:nth-of-type(6n+1), .small-up-6 > .columns:nth-of-type(6n+1) { + clear: both; } + .small-up-6 > .column:last-child, .small-up-6 > .columns:last-child { + float: left; } + +.small-up-7 > .column, .small-up-7 > .columns { + width: 14.28571%; + float: left; } + .small-up-7 > .column:nth-of-type(1n), .small-up-7 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-7 > .column:nth-of-type(7n+1), .small-up-7 > .columns:nth-of-type(7n+1) { + clear: both; } + .small-up-7 > .column:last-child, .small-up-7 > .columns:last-child { + float: left; } + +.small-up-8 > .column, .small-up-8 > .columns { + width: 12.5%; + float: left; } + .small-up-8 > .column:nth-of-type(1n), .small-up-8 > .columns:nth-of-type(1n) { + clear: none; } + .small-up-8 > .column:nth-of-type(8n+1), .small-up-8 > .columns:nth-of-type(8n+1) { + clear: both; } + .small-up-8 > .column:last-child, .small-up-8 > .columns:last-child { + float: left; } + +.small-collapse > .column, .small-collapse > .columns { + padding-left: 0; + padding-right: 0; } + +.small-collapse .row, +.expanded.row .small-collapse.row { + margin-left: 0; + margin-right: 0; } + +.small-uncollapse > .column, .small-uncollapse > .columns { + padding-left: 0.625rem; + padding-right: 0.625rem; } + +.small-centered { + float: none; + margin-left: auto; + margin-right: auto; } + +.small-uncentered, +.small-push-0, +.small-pull-0 { + position: static; + margin-left: 0; + margin-right: 0; + float: left; } + +@media screen and (min-width: 40em) { + .medium-1 { + width: 8.33333%; } + .medium-push-1 { + position: relative; + left: 8.33333%; } + .medium-pull-1 { + position: relative; + left: -8.33333%; } + .medium-offset-0 { + margin-left: 0%; } + .medium-2 { + width: 16.66667%; } + .medium-push-2 { + position: relative; + left: 16.66667%; } + .medium-pull-2 { + position: relative; + left: -16.66667%; } + .medium-offset-1 { + margin-left: 8.33333%; } + .medium-3 { + width: 25%; } + .medium-push-3 { + position: relative; + left: 25%; } + .medium-pull-3 { + position: relative; + left: -25%; } + .medium-offset-2 { + margin-left: 16.66667%; } + .medium-4 { + width: 33.33333%; } + .medium-push-4 { + position: relative; + left: 33.33333%; } + .medium-pull-4 { + position: relative; + left: -33.33333%; } + .medium-offset-3 { + margin-left: 25%; } + .medium-5 { + width: 41.66667%; } + .medium-push-5 { + position: relative; + left: 41.66667%; } + .medium-pull-5 { + position: relative; + left: -41.66667%; } + .medium-offset-4 { + margin-left: 33.33333%; } + .medium-6 { + width: 50%; } + .medium-push-6 { + position: relative; + left: 50%; } + .medium-pull-6 { + position: relative; + left: -50%; } + .medium-offset-5 { + margin-left: 41.66667%; } + .medium-7 { + width: 58.33333%; } + .medium-push-7 { + position: relative; + left: 58.33333%; } + .medium-pull-7 { + position: relative; + left: -58.33333%; } + .medium-offset-6 { + margin-left: 50%; } + .medium-8 { + width: 66.66667%; } + .medium-push-8 { + position: relative; + left: 66.66667%; } + .medium-pull-8 { + position: relative; + left: -66.66667%; } + .medium-offset-7 { + margin-left: 58.33333%; } + .medium-9 { + width: 75%; } + .medium-push-9 { + position: relative; + left: 75%; } + .medium-pull-9 { + position: relative; + left: -75%; } + .medium-offset-8 { + margin-left: 66.66667%; } + .medium-10 { + width: 83.33333%; } + .medium-push-10 { + position: relative; + left: 83.33333%; } + .medium-pull-10 { + position: relative; + left: -83.33333%; } + .medium-offset-9 { + margin-left: 75%; } + .medium-11 { + width: 91.66667%; } + .medium-push-11 { + position: relative; + left: 91.66667%; } + .medium-pull-11 { + position: relative; + left: -91.66667%; } + .medium-offset-10 { + margin-left: 83.33333%; } + .medium-12 { + width: 100%; } + .medium-offset-11 { + margin-left: 91.66667%; } + .medium-up-1 > .column, .medium-up-1 > .columns { + width: 100%; + float: left; } + .medium-up-1 > .column:nth-of-type(1n), .medium-up-1 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-1 > .column:nth-of-type(1n+1), .medium-up-1 > .columns:nth-of-type(1n+1) { + clear: both; } + .medium-up-1 > .column:last-child, .medium-up-1 > .columns:last-child { + float: left; } + .medium-up-2 > .column, .medium-up-2 > .columns { + width: 50%; + float: left; } + .medium-up-2 > .column:nth-of-type(1n), .medium-up-2 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-2 > .column:nth-of-type(2n+1), .medium-up-2 > .columns:nth-of-type(2n+1) { + clear: both; } + .medium-up-2 > .column:last-child, .medium-up-2 > .columns:last-child { + float: left; } + .medium-up-3 > .column, .medium-up-3 > .columns { + width: 33.33333%; + float: left; } + .medium-up-3 > .column:nth-of-type(1n), .medium-up-3 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-3 > .column:nth-of-type(3n+1), .medium-up-3 > .columns:nth-of-type(3n+1) { + clear: both; } + .medium-up-3 > .column:last-child, .medium-up-3 > .columns:last-child { + float: left; } + .medium-up-4 > .column, .medium-up-4 > .columns { + width: 25%; + float: left; } + .medium-up-4 > .column:nth-of-type(1n), .medium-up-4 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-4 > .column:nth-of-type(4n+1), .medium-up-4 > .columns:nth-of-type(4n+1) { + clear: both; } + .medium-up-4 > .column:last-child, .medium-up-4 > .columns:last-child { + float: left; } + .medium-up-5 > .column, .medium-up-5 > .columns { + width: 20%; + float: left; } + .medium-up-5 > .column:nth-of-type(1n), .medium-up-5 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-5 > .column:nth-of-type(5n+1), .medium-up-5 > .columns:nth-of-type(5n+1) { + clear: both; } + .medium-up-5 > .column:last-child, .medium-up-5 > .columns:last-child { + float: left; } + .medium-up-6 > .column, .medium-up-6 > .columns { + width: 16.66667%; + float: left; } + .medium-up-6 > .column:nth-of-type(1n), .medium-up-6 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-6 > .column:nth-of-type(6n+1), .medium-up-6 > .columns:nth-of-type(6n+1) { + clear: both; } + .medium-up-6 > .column:last-child, .medium-up-6 > .columns:last-child { + float: left; } + .medium-up-7 > .column, .medium-up-7 > .columns { + width: 14.28571%; + float: left; } + .medium-up-7 > .column:nth-of-type(1n), .medium-up-7 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-7 > .column:nth-of-type(7n+1), .medium-up-7 > .columns:nth-of-type(7n+1) { + clear: both; } + .medium-up-7 > .column:last-child, .medium-up-7 > .columns:last-child { + float: left; } + .medium-up-8 > .column, .medium-up-8 > .columns { + width: 12.5%; + float: left; } + .medium-up-8 > .column:nth-of-type(1n), .medium-up-8 > .columns:nth-of-type(1n) { + clear: none; } + .medium-up-8 > .column:nth-of-type(8n+1), .medium-up-8 > .columns:nth-of-type(8n+1) { + clear: both; } + .medium-up-8 > .column:last-child, .medium-up-8 > .columns:last-child { + float: left; } + .medium-collapse > .column, .medium-collapse > .columns { + padding-left: 0; + padding-right: 0; } + .medium-collapse .row, + .expanded.row .medium-collapse.row { + margin-left: 0; + margin-right: 0; } + .medium-uncollapse > .column, .medium-uncollapse > .columns { + padding-left: 0.9375rem; + padding-right: 0.9375rem; } + .medium-centered { + float: none; + margin-left: auto; + margin-right: auto; } + .medium-uncentered, + .medium-push-0, + .medium-pull-0 { + position: static; + margin-left: 0; + margin-right: 0; + float: left; } } + +@media screen and (min-width: 64em) { + .large-1 { + width: 8.33333%; } + .large-push-1 { + position: relative; + left: 8.33333%; } + .large-pull-1 { + position: relative; + left: -8.33333%; } + .large-offset-0 { + margin-left: 0%; } + .large-2 { + width: 16.66667%; } + .large-push-2 { + position: relative; + left: 16.66667%; } + .large-pull-2 { + position: relative; + left: -16.66667%; } + .large-offset-1 { + margin-left: 8.33333%; } + .large-3 { + width: 25%; } + .large-push-3 { + position: relative; + left: 25%; } + .large-pull-3 { + position: relative; + left: -25%; } + .large-offset-2 { + margin-left: 16.66667%; } + .large-4 { + width: 33.33333%; } + .large-push-4 { + position: relative; + left: 33.33333%; } + .large-pull-4 { + position: relative; + left: -33.33333%; } + .large-offset-3 { + margin-left: 25%; } + .large-5 { + width: 41.66667%; } + .large-push-5 { + position: relative; + left: 41.66667%; } + .large-pull-5 { + position: relative; + left: -41.66667%; } + .large-offset-4 { + margin-left: 33.33333%; } + .large-6 { + width: 50%; } + .large-push-6 { + position: relative; + left: 50%; } + .large-pull-6 { + position: relative; + left: -50%; } + .large-offset-5 { + margin-left: 41.66667%; } + .large-7 { + width: 58.33333%; } + .large-push-7 { + position: relative; + left: 58.33333%; } + .large-pull-7 { + position: relative; + left: -58.33333%; } + .large-offset-6 { + margin-left: 50%; } + .large-8 { + width: 66.66667%; } + .large-push-8 { + position: relative; + left: 66.66667%; } + .large-pull-8 { + position: relative; + left: -66.66667%; } + .large-offset-7 { + margin-left: 58.33333%; } + .large-9 { + width: 75%; } + .large-push-9 { + position: relative; + left: 75%; } + .large-pull-9 { + position: relative; + left: -75%; } + .large-offset-8 { + margin-left: 66.66667%; } + .large-10 { + width: 83.33333%; } + .large-push-10 { + position: relative; + left: 83.33333%; } + .large-pull-10 { + position: relative; + left: -83.33333%; } + .large-offset-9 { + margin-left: 75%; } + .large-11 { + width: 91.66667%; } + .large-push-11 { + position: relative; + left: 91.66667%; } + .large-pull-11 { + position: relative; + left: -91.66667%; } + .large-offset-10 { + margin-left: 83.33333%; } + .large-12 { + width: 100%; } + .large-offset-11 { + margin-left: 91.66667%; } + .large-up-1 > .column, .large-up-1 > .columns { + width: 100%; + float: left; } + .large-up-1 > .column:nth-of-type(1n), .large-up-1 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-1 > .column:nth-of-type(1n+1), .large-up-1 > .columns:nth-of-type(1n+1) { + clear: both; } + .large-up-1 > .column:last-child, .large-up-1 > .columns:last-child { + float: left; } + .large-up-2 > .column, .large-up-2 > .columns { + width: 50%; + float: left; } + .large-up-2 > .column:nth-of-type(1n), .large-up-2 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-2 > .column:nth-of-type(2n+1), .large-up-2 > .columns:nth-of-type(2n+1) { + clear: both; } + .large-up-2 > .column:last-child, .large-up-2 > .columns:last-child { + float: left; } + .large-up-3 > .column, .large-up-3 > .columns { + width: 33.33333%; + float: left; } + .large-up-3 > .column:nth-of-type(1n), .large-up-3 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-3 > .column:nth-of-type(3n+1), .large-up-3 > .columns:nth-of-type(3n+1) { + clear: both; } + .large-up-3 > .column:last-child, .large-up-3 > .columns:last-child { + float: left; } + .large-up-4 > .column, .large-up-4 > .columns { + width: 25%; + float: left; } + .large-up-4 > .column:nth-of-type(1n), .large-up-4 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-4 > .column:nth-of-type(4n+1), .large-up-4 > .columns:nth-of-type(4n+1) { + clear: both; } + .large-up-4 > .column:last-child, .large-up-4 > .columns:last-child { + float: left; } + .large-up-5 > .column, .large-up-5 > .columns { + width: 20%; + float: left; } + .large-up-5 > .column:nth-of-type(1n), .large-up-5 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-5 > .column:nth-of-type(5n+1), .large-up-5 > .columns:nth-of-type(5n+1) { + clear: both; } + .large-up-5 > .column:last-child, .large-up-5 > .columns:last-child { + float: left; } + .large-up-6 > .column, .large-up-6 > .columns { + width: 16.66667%; + float: left; } + .large-up-6 > .column:nth-of-type(1n), .large-up-6 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-6 > .column:nth-of-type(6n+1), .large-up-6 > .columns:nth-of-type(6n+1) { + clear: both; } + .large-up-6 > .column:last-child, .large-up-6 > .columns:last-child { + float: left; } + .large-up-7 > .column, .large-up-7 > .columns { + width: 14.28571%; + float: left; } + .large-up-7 > .column:nth-of-type(1n), .large-up-7 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-7 > .column:nth-of-type(7n+1), .large-up-7 > .columns:nth-of-type(7n+1) { + clear: both; } + .large-up-7 > .column:last-child, .large-up-7 > .columns:last-child { + float: left; } + .large-up-8 > .column, .large-up-8 > .columns { + width: 12.5%; + float: left; } + .large-up-8 > .column:nth-of-type(1n), .large-up-8 > .columns:nth-of-type(1n) { + clear: none; } + .large-up-8 > .column:nth-of-type(8n+1), .large-up-8 > .columns:nth-of-type(8n+1) { + clear: both; } + .large-up-8 > .column:last-child, .large-up-8 > .columns:last-child { + float: left; } + .large-collapse > .column, .large-collapse > .columns { + padding-left: 0; + padding-right: 0; } + .large-collapse .row, + .expanded.row .large-collapse.row { + margin-left: 0; + margin-right: 0; } + .large-uncollapse > .column, .large-uncollapse > .columns { + padding-left: 0.9375rem; + padding-right: 0.9375rem; } + .large-centered { + float: none; + margin-left: auto; + margin-right: auto; } + .large-uncentered, + .large-push-0, + .large-pull-0 { + position: static; + margin-left: 0; + margin-right: 0; + float: left; } } + +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6, +pre, +form, +p, +blockquote, +th, +td { + margin: 0; + padding: 0; } + +p { + font-size: inherit; + line-height: 1.6; + margin-bottom: 1rem; + text-rendering: optimizeLegibility; } + +em, +i { + font-style: italic; + line-height: inherit; } + +strong, +b { + font-weight: bold; + line-height: inherit; } + +small { + font-size: 80%; + line-height: inherit; } + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; + font-weight: normal; + font-style: normal; + color: inherit; + text-rendering: optimizeLegibility; + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.4; } + h1 small, + h2 small, + h3 small, + h4 small, + h5 small, + h6 small { + color: #cacaca; + line-height: 0; } + +h1 { + font-size: 1.5rem; } + +h2 { + font-size: 1.25rem; } + +h3 { + font-size: 1.1875rem; } + +h4 { + font-size: 1.125rem; } + +h5 { + font-size: 1.0625rem; } + +h6 { + font-size: 1rem; } + +@media screen and (min-width: 40em) { + h1 { + font-size: 3rem; } + h2 { + font-size: 2.5rem; } + h3 { + font-size: 1.9375rem; } + h4 { + font-size: 1.5625rem; } + h5 { + font-size: 1.25rem; } + h6 { + font-size: 1rem; } } + +a { + color: #2199e8; + text-decoration: none; + line-height: inherit; + cursor: pointer; } + a:hover, a:focus { + color: #1585cf; } + a img { + border: 0; } + +hr { + max-width: 75rem; + height: 0; + border-right: 0; + border-top: 0; + border-bottom: 1px solid #cacaca; + border-left: 0; + margin: 1.25rem auto; + clear: both; } + +ul, +ol, +dl { + line-height: 1.6; + margin-bottom: 1rem; + list-style-position: outside; } + +li { + font-size: inherit; } + +ul { + list-style-type: disc; + margin-left: 1.25rem; } + +ol { + margin-left: 1.25rem; } + +ul ul, ol ul, ul ol, ol ol { + margin-left: 1.25rem; + margin-bottom: 0; } + +dl { + margin-bottom: 1rem; } + dl dt { + margin-bottom: 0.3rem; + font-weight: bold; } + +blockquote { + margin: 0 0 1rem; + padding: 0.5625rem 1.25rem 0 1.1875rem; + border-left: 1px solid #cacaca; } + blockquote, blockquote p { + line-height: 1.6; + color: #8a8a8a; } + +cite { + display: block; + font-size: 0.8125rem; + color: #8a8a8a; } + cite:before { + content: '\2014 \0020'; } + +abbr { + color: #0a0a0a; + cursor: help; + border-bottom: 1px dotted #0a0a0a; } + +code { + font-family: Consolas, "Liberation Mono", Courier, monospace; + font-weight: normal; + color: #0a0a0a; + background-color: #e6e6e6; + border: 1px solid #cacaca; + padding: 0.125rem 0.3125rem 0.0625rem; } + +kbd { + padding: 0.125rem 0.25rem 0; + margin: 0; + background-color: #e6e6e6; + color: #0a0a0a; + font-family: Consolas, "Liberation Mono", Courier, monospace; } + +.subheader { + margin-top: 0.2rem; + margin-bottom: 0.5rem; + font-weight: normal; + line-height: 1.4; + color: #8a8a8a; } + +.lead { + font-size: 125%; + line-height: 1.6; } + +.stat { + font-size: 2.5rem; + line-height: 1; } + p + .stat { + margin-top: -1rem; } + +.no-bullet { + margin-left: 0; + list-style: none; } + +.text-left { + text-align: left; } + +.text-right { + text-align: right; } + +.text-center { + text-align: center; } + +.text-justify { + text-align: justify; } + +@media screen and (min-width: 40em) { + .medium-text-left { + text-align: left; } + .medium-text-right { + text-align: right; } + .medium-text-center { + text-align: center; } + .medium-text-justify { + text-align: justify; } } + +@media screen and (min-width: 64em) { + .large-text-left { + text-align: left; } + .large-text-right { + text-align: right; } + .large-text-center { + text-align: center; } + .large-text-justify { + text-align: justify; } } + +.show-for-print { + display: none !important; } + +@media print { + * { + background: transparent !important; + color: black !important; + box-shadow: none !important; + text-shadow: none !important; } + .show-for-print { + display: block !important; } + .hide-for-print { + display: none !important; } + table.show-for-print { + display: table !important; } + thead.show-for-print { + display: table-header-group !important; } + tbody.show-for-print { + display: table-row-group !important; } + tr.show-for-print { + display: table-row !important; } + td.show-for-print { + display: table-cell !important; } + th.show-for-print { + display: table-cell !important; } + a, + a:visited { + text-decoration: underline; } + a[href]:after { + content: " (" attr(href) ")"; } + .ir a:after, + a[href^='javascript:']:after, + a[href^='#']:after { + content: ''; } + abbr[title]:after { + content: " (" attr(title) ")"; } + pre, + blockquote { + border: 1px solid #8a8a8a; + page-break-inside: avoid; } + thead { + display: table-header-group; } + tr, + img { + page-break-inside: avoid; } + img { + max-width: 100% !important; } + @page { + margin: 0.5cm; } + p, + h2, + h3 { + orphans: 3; + widows: 3; } + h2, + h3 { + page-break-after: avoid; } } + +.button { + display: inline-block; + text-align: center; + line-height: 1; + cursor: pointer; + -webkit-appearance: none; + transition: background-color 0.25s ease-out, color 0.25s ease-out; + vertical-align: middle; + border: 1px solid transparent; + border-radius: 0; + padding: 0.85em 1em; + margin: 0 0 1rem 0; + font-size: 0.9rem; + background-color: #2199e8; + color: #fefefe; } + [data-whatinput='mouse'] .button { + outline: 0; } + .button:hover, .button:focus { + background-color: #1583cc; + color: #fefefe; } + .button.tiny { + font-size: 0.6rem; } + .button.small { + font-size: 0.75rem; } + .button.large { + font-size: 1.25rem; } + .button.expanded { + display: block; + width: 100%; + margin-left: 0; + margin-right: 0; } + .button.primary { + background-color: #2199e8; + color: #fefefe; } + .button.primary:hover, .button.primary:focus { + background-color: #147cc0; + color: #fefefe; } + .button.secondary { + background-color: #777; + color: #fefefe; } + .button.secondary:hover, .button.secondary:focus { + background-color: #5f5f5f; + color: #fefefe; } + .button.success { + background-color: #3adb76; + color: #fefefe; } + .button.success:hover, .button.success:focus { + background-color: #22bb5b; + color: #fefefe; } + .button.warning { + background-color: #ffae00; + color: #fefefe; } + .button.warning:hover, .button.warning:focus { + background-color: #cc8b00; + color: #fefefe; } + .button.alert { + background-color: #ec5840; + color: #fefefe; } + .button.alert:hover, .button.alert:focus { + background-color: #da3116; + color: #fefefe; } + .button.hollow { + border: 1px solid #2199e8; + color: #2199e8; } + .button.hollow, .button.hollow:hover, .button.hollow:focus { + background-color: transparent; } + .button.hollow:hover, .button.hollow:focus { + border-color: #0c4d78; + color: #0c4d78; } + .button.hollow.primary { + border: 1px solid #2199e8; + color: #2199e8; } + .button.hollow.primary:hover, .button.hollow.primary:focus { + border-color: #0c4d78; + color: #0c4d78; } + .button.hollow.secondary { + border: 1px solid #777; + color: #777; } + .button.hollow.secondary:hover, .button.hollow.secondary:focus { + border-color: #3c3c3c; + color: #3c3c3c; } + .button.hollow.success { + border: 1px solid #3adb76; + color: #3adb76; } + .button.hollow.success:hover, .button.hollow.success:focus { + border-color: #157539; + color: #157539; } + .button.hollow.warning { + border: 1px solid #ffae00; + color: #ffae00; } + .button.hollow.warning:hover, .button.hollow.warning:focus { + border-color: #805700; + color: #805700; } + .button.hollow.alert { + border: 1px solid #ec5840; + color: #ec5840; } + .button.hollow.alert:hover, .button.hollow.alert:focus { + border-color: #881f0e; + color: #881f0e; } + .button.disabled, .button[disabled] { + opacity: 0.25; + cursor: not-allowed; } + .button.disabled:hover, .button.disabled:focus, .button[disabled]:hover, .button[disabled]:focus { + background-color: #2199e8; + color: #fefefe; } + .button.dropdown::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 0.4em; + border-color: #fefefe transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + position: relative; + top: 0.4em; + float: right; + margin-left: 1em; + display: inline-block; } + .button.arrow-only::after { + margin-left: 0; + float: none; + top: -0.1em; } + +[type='text'], [type='password'], [type='date'], [type='datetime'], [type='datetime-local'], [type='month'], [type='week'], [type='email'], [type='number'], [type='search'], [type='tel'], [type='time'], [type='url'], [type='color'], +textarea { + display: block; + box-sizing: border-box; + width: 100%; + height: 2.4375rem; + padding: 0.5rem; + border: 1px solid #cacaca; + margin: 0 0 1rem; + font-family: inherit; + font-size: 1rem; + color: #0a0a0a; + background-color: #fefefe; + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1); + border-radius: 0; + transition: box-shadow 0.5s, border-color 0.25s ease-in-out; + -webkit-appearance: none; + -moz-appearance: none; } + [type='text']:focus, [type='password']:focus, [type='date']:focus, [type='datetime']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='week']:focus, [type='email']:focus, [type='number']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='url']:focus, [type='color']:focus, + textarea:focus { + border: 1px solid #8a8a8a; + background-color: #fefefe; + outline: none; + box-shadow: 0 0 5px #cacaca; + transition: box-shadow 0.5s, border-color 0.25s ease-in-out; } + +textarea { + max-width: 100%; } + textarea[rows] { + height: auto; } + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #cacaca; } + +input::-moz-placeholder, +textarea::-moz-placeholder { + color: #cacaca; } + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #cacaca; } + +input::placeholder, +textarea::placeholder { + color: #cacaca; } + +input:disabled, input[readonly], +textarea:disabled, +textarea[readonly] { + background-color: #e6e6e6; + cursor: not-allowed; } + +[type='submit'], +[type='button'] { + border-radius: 0; + -webkit-appearance: none; + -moz-appearance: none; } + +input[type='search'] { + box-sizing: border-box; } + +[type='file'], +[type='checkbox'], +[type='radio'] { + margin: 0 0 1rem; } + +[type='checkbox'] + label, +[type='radio'] + label { + display: inline-block; + margin-left: 0.5rem; + margin-right: 1rem; + margin-bottom: 0; + vertical-align: baseline; } + [type='checkbox'] + label[for], + [type='radio'] + label[for] { + cursor: pointer; } + +label > [type='checkbox'], +label > [type='radio'] { + margin-right: 0.5rem; } + +[type='file'] { + width: 100%; } + +label { + display: block; + margin: 0; + font-size: 0.875rem; + font-weight: normal; + line-height: 1.8; + color: #0a0a0a; } + label.middle { + margin: 0 0 1rem; + padding: 0.5625rem 0; } + +.help-text { + margin-top: -0.5rem; + font-size: 0.8125rem; + font-style: italic; + color: #0a0a0a; } + +.input-group { + display: table; + width: 100%; + margin-bottom: 1rem; } + .input-group > :first-child { + border-radius: 0 0 0 0; } + .input-group > :last-child > * { + border-radius: 0 0 0 0; } + +.input-group-label, .input-group-field, .input-group-button { + margin: 0; + white-space: nowrap; + display: table-cell; + vertical-align: middle; } + +.input-group-label { + text-align: center; + padding: 0 1rem; + background: #e6e6e6; + color: #0a0a0a; + border: 1px solid #cacaca; + white-space: nowrap; + width: 1%; + height: 100%; } + .input-group-label:first-child { + border-right: 0; } + .input-group-label:last-child { + border-left: 0; } + +.input-group-field { + border-radius: 0; + height: 2.5rem; } + +.input-group-button { + padding-top: 0; + padding-bottom: 0; + text-align: center; + height: 100%; + width: 1%; } + .input-group-button a, + .input-group-button input, + .input-group-button button { + margin: 0; } + +.input-group .input-group-button { + display: table-cell; } + +fieldset { + border: 0; + padding: 0; + margin: 0; } + +legend { + margin-bottom: 0.5rem; + max-width: 100%; } + +.fieldset { + border: 1px solid #cacaca; + padding: 1.25rem; + margin: 1.125rem 0; } + .fieldset legend { + background: #fefefe; + padding: 0 0.1875rem; + margin: 0; + margin-left: -0.1875rem; } + +select { + height: 2.4375rem; + padding: 0.5rem; + border: 1px solid #cacaca; + margin: 0 0 1rem; + font-size: 1rem; + font-family: inherit; + line-height: normal; + color: #0a0a0a; + background-color: #fefefe; + border-radius: 0; + -webkit-appearance: none; + -moz-appearance: none; + background-image: url("data:image/svg+xml;utf8,"); + background-size: 9px 6px; + background-position: right -1rem center; + background-origin: content-box; + background-repeat: no-repeat; + padding-right: 1.5rem; } + @media screen and (min-width: 0\0) { + select { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIpJREFUeNrEkckNgDAMBBfRkEt0ObRBBdsGXUDgmQfK4XhH2m8czQAAy27R3tsw4Qfe2x8uOO6oYLb6GlOor3GF+swURAOmUJ+RwtEJs9WvTGEYxBXqI1MQAZhCfUQKRzDMVj+TwrAIV6jvSUEkYAr1LSkcyTBb/V+KYfX7xAeusq3sLDtGH3kEGACPWIflNZfhRQAAAABJRU5ErkJggg=="); } } + select:disabled { + background-color: #e6e6e6; + cursor: not-allowed; } + select::-ms-expand { + display: none; } + select[multiple] { + height: auto; + background-image: none; } + +.is-invalid-input:not(:focus) { + background-color: rgba(236, 88, 64, 0.1); + border-color: #ec5840; } + +.is-invalid-label { + color: #ec5840; } + +.form-error { + display: none; + margin-top: -0.5rem; + margin-bottom: 1rem; + font-size: 0.75rem; + font-weight: bold; + color: #ec5840; } + .form-error.is-visible { + display: block; } + +.accordion { + list-style-type: none; + background: #fefefe; + margin-left: 0; } + +.accordion-item:first-child > :first-child { + border-radius: 0 0 0 0; } + +.accordion-item:last-child > :last-child { + border-radius: 0 0 0 0; } + +.accordion-title { + display: block; + padding: 1.25rem 1rem; + line-height: 1; + font-size: 0.75rem; + color: #2199e8; + position: relative; + border: 1px solid #e6e6e6; + border-bottom: 0; } + :last-child:not(.is-active) > .accordion-title { + border-radius: 0 0 0 0; + border-bottom: 1px solid #e6e6e6; } + .accordion-title:hover, .accordion-title:focus { + background-color: #e6e6e6; } + .accordion-title::before { + content: '+'; + position: absolute; + right: 1rem; + top: 50%; + margin-top: -0.5rem; } + .is-active > .accordion-title::before { + content: '–'; } + +.accordion-content { + padding: 1rem; + display: none; + border: 1px solid #e6e6e6; + border-bottom: 0; + background-color: #fefefe; + color: #0a0a0a; } + :last-child > .accordion-content:last-child { + border-bottom: 1px solid #e6e6e6; } + +.is-accordion-submenu-parent > a { + position: relative; } + .is-accordion-submenu-parent > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 6px; + border-color: #2199e8 transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + position: absolute; + top: 50%; + margin-top: -4px; + right: 1rem; } + +.is-accordion-submenu-parent[aria-expanded='true'] > a::after { + -webkit-transform-origin: 50% 50%; + -ms-transform-origin: 50% 50%; + transform-origin: 50% 50%; + -webkit-transform: scaleY(-1); + -ms-transform: scaleY(-1); + transform: scaleY(-1); } + +.badge { + display: inline-block; + padding: 0.3em; + min-width: 2.1em; + font-size: 0.6rem; + text-align: center; + border-radius: 50%; + background: #2199e8; + color: #fefefe; } + .badge.secondary { + background: #777; + color: #fefefe; } + .badge.success { + background: #3adb76; + color: #fefefe; } + .badge.warning { + background: #ffae00; + color: #fefefe; } + .badge.alert { + background: #ec5840; + color: #fefefe; } + +.breadcrumbs { + list-style: none; + margin: 0 0 1rem 0; } + .breadcrumbs::before, .breadcrumbs::after { + content: ' '; + display: table; } + .breadcrumbs::after { + clear: both; } + .breadcrumbs li { + float: left; + color: #0a0a0a; + font-size: 0.6875rem; + cursor: default; + text-transform: uppercase; } + .breadcrumbs li:not(:last-child)::after { + color: #cacaca; + content: "/"; + margin: 0 0.75rem; + position: relative; + top: 1px; + opacity: 1; } + .breadcrumbs a { + color: #2199e8; } + .breadcrumbs a:hover { + text-decoration: underline; } + .breadcrumbs .disabled { + color: #cacaca; + cursor: not-allowed; } + +.button-group { + margin-bottom: 1rem; + font-size: 0; } + .button-group::before, .button-group::after { + content: ' '; + display: table; } + .button-group::after { + clear: both; } + .button-group .button { + margin: 0; + margin-right: 1px; + margin-bottom: 1px; + font-size: 0.9rem; } + .button-group .button:last-child { + margin-right: 0; } + .button-group.tiny .button { + font-size: 0.6rem; } + .button-group.small .button { + font-size: 0.75rem; } + .button-group.large .button { + font-size: 1.25rem; } + .button-group.expanded { + margin-right: -1px; } + .button-group.expanded::before, .button-group.expanded::after { + display: none; } + .button-group.expanded .button:first-child:nth-last-child(2), .button-group.expanded .button:first-child:nth-last-child(2):first-child:nth-last-child(2) ~ .button { + display: inline-block; + width: calc(50% - 1px); + margin-right: 1px; } + .button-group.expanded .button:first-child:nth-last-child(2):last-child, .button-group.expanded .button:first-child:nth-last-child(2):first-child:nth-last-child(2) ~ .button:last-child { + margin-right: -6px; } + .button-group.expanded .button:first-child:nth-last-child(3), .button-group.expanded .button:first-child:nth-last-child(3):first-child:nth-last-child(3) ~ .button { + display: inline-block; + width: calc(33.33333% - 1px); + margin-right: 1px; } + .button-group.expanded .button:first-child:nth-last-child(3):last-child, .button-group.expanded .button:first-child:nth-last-child(3):first-child:nth-last-child(3) ~ .button:last-child { + margin-right: -6px; } + .button-group.expanded .button:first-child:nth-last-child(4), .button-group.expanded .button:first-child:nth-last-child(4):first-child:nth-last-child(4) ~ .button { + display: inline-block; + width: calc(25% - 1px); + margin-right: 1px; } + .button-group.expanded .button:first-child:nth-last-child(4):last-child, .button-group.expanded .button:first-child:nth-last-child(4):first-child:nth-last-child(4) ~ .button:last-child { + margin-right: -6px; } + .button-group.expanded .button:first-child:nth-last-child(5), .button-group.expanded .button:first-child:nth-last-child(5):first-child:nth-last-child(5) ~ .button { + display: inline-block; + width: calc(20% - 1px); + margin-right: 1px; } + .button-group.expanded .button:first-child:nth-last-child(5):last-child, .button-group.expanded .button:first-child:nth-last-child(5):first-child:nth-last-child(5) ~ .button:last-child { + margin-right: -6px; } + .button-group.expanded .button:first-child:nth-last-child(6), .button-group.expanded .button:first-child:nth-last-child(6):first-child:nth-last-child(6) ~ .button { + display: inline-block; + width: calc(16.66667% - 1px); + margin-right: 1px; } + .button-group.expanded .button:first-child:nth-last-child(6):last-child, .button-group.expanded .button:first-child:nth-last-child(6):first-child:nth-last-child(6) ~ .button:last-child { + margin-right: -6px; } + .button-group.primary .button { + background-color: #2199e8; + color: #fefefe; } + .button-group.primary .button:hover, .button-group.primary .button:focus { + background-color: #147cc0; + color: #fefefe; } + .button-group.secondary .button { + background-color: #777; + color: #fefefe; } + .button-group.secondary .button:hover, .button-group.secondary .button:focus { + background-color: #5f5f5f; + color: #fefefe; } + .button-group.success .button { + background-color: #3adb76; + color: #fefefe; } + .button-group.success .button:hover, .button-group.success .button:focus { + background-color: #22bb5b; + color: #fefefe; } + .button-group.warning .button { + background-color: #ffae00; + color: #fefefe; } + .button-group.warning .button:hover, .button-group.warning .button:focus { + background-color: #cc8b00; + color: #fefefe; } + .button-group.alert .button { + background-color: #ec5840; + color: #fefefe; } + .button-group.alert .button:hover, .button-group.alert .button:focus { + background-color: #da3116; + color: #fefefe; } + .button-group.stacked .button, .button-group.stacked-for-small .button, .button-group.stacked-for-medium .button { + width: 100%; } + .button-group.stacked .button:last-child, .button-group.stacked-for-small .button:last-child, .button-group.stacked-for-medium .button:last-child { + margin-bottom: 0; } + @media screen and (min-width: 40em) { + .button-group.stacked-for-small .button { + width: auto; + margin-bottom: 0; } } + @media screen and (min-width: 64em) { + .button-group.stacked-for-medium .button { + width: auto; + margin-bottom: 0; } } + @media screen and (max-width: 39.9375em) { + .button-group.stacked-for-small.expanded { + display: block; } + .button-group.stacked-for-small.expanded .button { + display: block; + margin-right: 0; } } + +.callout { + margin: 0 0 1rem 0; + padding: 1rem; + border: 1px solid rgba(10, 10, 10, 0.25); + border-radius: 0; + position: relative; + color: #0a0a0a; + background-color: white; } + .callout > :first-child { + margin-top: 0; } + .callout > :last-child { + margin-bottom: 0; } + .callout.primary { + background-color: #def0fc; } + .callout.secondary { + background-color: #ebebeb; } + .callout.success { + background-color: #e1faea; } + .callout.warning { + background-color: #fff3d9; } + .callout.alert { + background-color: #fce6e2; } + .callout.small { + padding-top: 0.5rem; + padding-right: 0.5rem; + padding-bottom: 0.5rem; + padding-left: 0.5rem; } + .callout.large { + padding-top: 3rem; + padding-right: 3rem; + padding-bottom: 3rem; + padding-left: 3rem; } + +.close-button { + position: absolute; + color: #8a8a8a; + right: 1rem; + top: 0.5rem; + font-size: 2em; + line-height: 1; + cursor: pointer; } + [data-whatinput='mouse'] .close-button { + outline: 0; } + .close-button:hover, .close-button:focus { + color: #0a0a0a; } + +.menu { + margin: 0; + list-style-type: none; } + .menu > li { + display: table-cell; + vertical-align: middle; } + [data-whatinput='mouse'] .menu > li { + outline: 0; } + .menu > li > a { + display: block; + padding: 0.7rem 1rem; + line-height: 1; } + .menu input, + .menu a, + .menu button { + margin-bottom: 0; } + .menu > li > a img, + .menu > li > a i, + .menu > li > a svg { + vertical-align: middle; } + .menu > li > a img + span, + .menu > li > a i + span, + .menu > li > a svg + span { + vertical-align: middle; } + .menu > li > a img, + .menu > li > a i, + .menu > li > a svg { + margin-right: 0.25rem; + display: inline-block; } + .menu > li { + display: table-cell; } + .menu.vertical > li { + display: block; } + @media screen and (min-width: 40em) { + .menu.medium-horizontal > li { + display: table-cell; } + .menu.medium-vertical > li { + display: block; } } + @media screen and (min-width: 64em) { + .menu.large-horizontal > li { + display: table-cell; } + .menu.large-vertical > li { + display: block; } } + .menu.simple li { + line-height: 1; + display: inline-block; + margin-right: 1rem; } + .menu.simple a { + padding: 0; } + .menu.align-right::before, .menu.align-right::after { + content: ' '; + display: table; } + .menu.align-right::after { + clear: both; } + .menu.align-right > li { + float: right; } + .menu.expanded { + width: 100%; + display: table; + table-layout: fixed; } + .menu.expanded > li:first-child:last-child { + width: 100%; } + .menu.icon-top > li > a { + text-align: center; } + .menu.icon-top > li > a img, + .menu.icon-top > li > a i, + .menu.icon-top > li > a svg { + display: block; + margin: 0 auto 0.25rem; } + .menu.nested { + margin-left: 1rem; } + .menu .active > a { + color: #fefefe; + background: #2199e8; } + +.menu-text { + font-weight: bold; + color: inherit; + line-height: 1; + padding-top: 0; + padding-bottom: 0; + padding: 0.7rem 1rem; } + +.menu-centered { + text-align: center; } + .menu-centered > .menu { + display: inline-block; } + +.no-js [data-responsive-menu] ul { + display: none; } + +.menu-icon { + position: relative; + display: inline-block; + vertical-align: middle; + cursor: pointer; + width: 20px; + height: 16px; } + .menu-icon::after { + content: ''; + position: absolute; + display: block; + width: 100%; + height: 2px; + background: #fefefe; + top: 0; + left: 0; + box-shadow: 0 7px 0 #fefefe, 0 14px 0 #fefefe; } + .menu-icon:hover::after { + background: #cacaca; + box-shadow: 0 7px 0 #cacaca, 0 14px 0 #cacaca; } + +.menu-icon.dark { + position: relative; + display: inline-block; + vertical-align: middle; + cursor: pointer; + width: 20px; + height: 16px; } + .menu-icon.dark::after { + content: ''; + position: absolute; + display: block; + width: 100%; + height: 2px; + background: #0a0a0a; + top: 0; + left: 0; + box-shadow: 0 7px 0 #0a0a0a, 0 14px 0 #0a0a0a; } + .menu-icon.dark:hover::after { + background: #8a8a8a; + box-shadow: 0 7px 0 #8a8a8a, 0 14px 0 #8a8a8a; } + +.is-drilldown { + position: relative; + overflow: hidden; } + .is-drilldown li { + display: block !important; } + +.is-drilldown-submenu { + position: absolute; + top: 0; + left: 100%; + z-index: -1; + height: 100%; + width: 100%; + background: #fefefe; + transition: -webkit-transform 0.15s linear; + transition: transform 0.15s linear; } + .is-drilldown-submenu.is-active { + z-index: 1; + display: block; + -webkit-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); } + .is-drilldown-submenu.is-closing { + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); } + +.is-drilldown-submenu-parent > a { + position: relative; } + .is-drilldown-submenu-parent > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 6px; + border-color: transparent transparent transparent #2199e8; + border-left-style: solid; + border-right-width: 0; + position: absolute; + top: 50%; + margin-top: -6px; + right: 1rem; } + +.js-drilldown-back > a::before { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 6px; + border-color: transparent #2199e8 transparent transparent; + border-right-style: solid; + border-left-width: 0; + border-left-width: 0; + display: inline-block; + vertical-align: middle; + margin-right: 0.75rem; } + +.dropdown-pane { + background-color: #fefefe; + border: 1px solid #cacaca; + border-radius: 0; + display: block; + font-size: 1rem; + padding: 1rem; + position: absolute; + visibility: hidden; + width: 300px; + z-index: 10; } + .dropdown-pane.is-open { + visibility: visible; } + +.dropdown-pane.tiny { + width: 100px; } + +.dropdown-pane.small { + width: 200px; } + +.dropdown-pane.large { + width: 400px; } + +.dropdown.menu > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 0; + top: 100%; } + +.dropdown.menu > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 0; + top: 100%; } + +.dropdown.menu > li.is-dropdown-submenu-parent > a { + padding-right: 1.5rem; + position: relative; } + +.dropdown.menu > li.is-dropdown-submenu-parent > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: #2199e8 transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + right: 5px; + margin-top: -2px; } + +[data-whatinput='mouse'] .dropdown.menu a { + outline: 0; } + +.no-js .dropdown.menu ul { + display: none; } + +.dropdown.menu.vertical > li .is-dropdown-submenu { + top: 0; } + +.dropdown.menu.vertical > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 100%; } + +.dropdown.menu.vertical > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 100%; } + +.dropdown.menu.vertical > li > a::after { + right: 14px; + margin-top: -3px; } + +.dropdown.menu.vertical > li.opens-left > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent #2199e8 transparent transparent; + border-right-style: solid; + border-left-width: 0; } + +.dropdown.menu.vertical > li.opens-right > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent transparent transparent #2199e8; + border-left-style: solid; + border-right-width: 0; } + +@media screen and (min-width: 40em) { + .dropdown.menu.medium-horizontal > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 0; + top: 100%; } + .dropdown.menu.medium-horizontal > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 0; + top: 100%; } + .dropdown.menu.medium-horizontal > li.is-dropdown-submenu-parent > a { + padding-right: 1.5rem; + position: relative; } + .dropdown.menu.medium-horizontal > li.is-dropdown-submenu-parent > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: #2199e8 transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + right: 5px; + margin-top: -2px; } + .dropdown.menu.medium-vertical > li .is-dropdown-submenu { + top: 0; } + .dropdown.menu.medium-vertical > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 100%; } + .dropdown.menu.medium-vertical > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 100%; } + .dropdown.menu.medium-vertical > li > a::after { + right: 14px; + margin-top: -3px; } + .dropdown.menu.medium-vertical > li.opens-left > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent #2199e8 transparent transparent; + border-right-style: solid; + border-left-width: 0; } + .dropdown.menu.medium-vertical > li.opens-right > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent transparent transparent #2199e8; + border-left-style: solid; + border-right-width: 0; } } + +@media screen and (min-width: 64em) { + .dropdown.menu.large-horizontal > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 0; + top: 100%; } + .dropdown.menu.large-horizontal > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 0; + top: 100%; } + .dropdown.menu.large-horizontal > li.is-dropdown-submenu-parent > a { + padding-right: 1.5rem; + position: relative; } + .dropdown.menu.large-horizontal > li.is-dropdown-submenu-parent > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: #2199e8 transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + right: 5px; + margin-top: -2px; } + .dropdown.menu.large-vertical > li .is-dropdown-submenu { + top: 0; } + .dropdown.menu.large-vertical > li.opens-left > .is-dropdown-submenu { + left: auto; + right: 100%; } + .dropdown.menu.large-vertical > li.opens-right > .is-dropdown-submenu { + right: auto; + left: 100%; } + .dropdown.menu.large-vertical > li > a::after { + right: 14px; + margin-top: -3px; } + .dropdown.menu.large-vertical > li.opens-left > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent #2199e8 transparent transparent; + border-right-style: solid; + border-left-width: 0; } + .dropdown.menu.large-vertical > li.opens-right > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent transparent transparent #2199e8; + border-left-style: solid; + border-right-width: 0; } } + +.dropdown.menu.align-right .is-dropdown-submenu.first-sub { + top: 100%; + left: auto; + right: 0; } + +.is-dropdown-menu.vertical { + width: 100px; } + .is-dropdown-menu.vertical.align-right { + float: right; } + +.is-dropdown-submenu-parent { + position: relative; } + .is-dropdown-submenu-parent a::after { + position: absolute; + top: 50%; + right: 5px; + margin-top: -2px; } + .is-dropdown-submenu-parent.opens-inner > .is-dropdown-submenu { + top: 100%; + left: auto; } + .is-dropdown-submenu-parent.opens-left > .is-dropdown-submenu { + left: auto; + right: 100%; } + .is-dropdown-submenu-parent.opens-right > .is-dropdown-submenu { + right: auto; + left: 100%; } + +.is-dropdown-submenu { + display: none; + position: absolute; + top: 0; + left: 100%; + min-width: 200px; + z-index: 1; + background: #fefefe; + border: 1px solid #cacaca; } + .is-dropdown-submenu .is-dropdown-submenu-parent > a::after { + right: 14px; + margin-top: -3px; } + .is-dropdown-submenu .is-dropdown-submenu-parent.opens-left > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent #2199e8 transparent transparent; + border-right-style: solid; + border-left-width: 0; } + .is-dropdown-submenu .is-dropdown-submenu-parent.opens-right > a::after { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 5px; + border-color: transparent transparent transparent #2199e8; + border-left-style: solid; + border-right-width: 0; } + .is-dropdown-submenu .is-dropdown-submenu { + margin-top: -1px; } + .is-dropdown-submenu > li { + width: 100%; } + .is-dropdown-submenu.js-dropdown-active { + display: block; } + +.flex-video { + position: relative; + height: 0; + padding-bottom: 75%; + margin-bottom: 1rem; + overflow: hidden; } + .flex-video iframe, + .flex-video object, + .flex-video embed, + .flex-video video { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; } + .flex-video.widescreen { + padding-bottom: 56.25%; } + .flex-video.vimeo { + padding-top: 0; } + +.label { + display: inline-block; + padding: 0.33333rem 0.5rem; + font-size: 0.8rem; + line-height: 1; + white-space: nowrap; + cursor: default; + border-radius: 0; + background: #2199e8; + color: #fefefe; } + .label.secondary { + background: #777; + color: #fefefe; } + .label.success { + background: #3adb76; + color: #fefefe; } + .label.warning { + background: #ffae00; + color: #fefefe; } + .label.alert { + background: #ec5840; + color: #fefefe; } + +.media-object { + margin-bottom: 1rem; + display: block; } + .media-object img { + max-width: none; } + @media screen and (max-width: 39.9375em) { + .media-object.stack-for-small .media-object-section { + padding: 0; + padding-bottom: 1rem; + display: block; } + .media-object.stack-for-small .media-object-section img { + width: 100%; } } + +.media-object-section { + display: table-cell; + vertical-align: top; } + .media-object-section:first-child { + padding-right: 1rem; } + .media-object-section:last-child:not(:nth-child(2)) { + padding-left: 1rem; } + .media-object-section > :last-child { + margin-bottom: 0; } + .media-object-section.middle { + vertical-align: middle; } + .media-object-section.bottom { + vertical-align: bottom; } + +html, +body { + height: 100%; } + +.off-canvas-wrapper { + width: 100%; + overflow-x: hidden; + position: relative; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-overflow-scrolling: auto; } + +.off-canvas-wrapper-inner { + position: relative; + width: 100%; + transition: -webkit-transform 0.5s ease; + transition: transform 0.5s ease; } + .off-canvas-wrapper-inner::before, .off-canvas-wrapper-inner::after { + content: ' '; + display: table; } + .off-canvas-wrapper-inner::after { + clear: both; } + +.off-canvas-content, +.off-canvas-content { + min-height: 100%; + background: #fefefe; + transition: -webkit-transform 0.5s ease; + transition: transform 0.5s ease; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + z-index: 1; + padding-bottom: 0.1px; + box-shadow: 0 0 10px rgba(10, 10, 10, 0.5); } + +.js-off-canvas-exit { + display: none; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(254, 254, 254, 0.25); + cursor: pointer; + transition: background 0.5s ease; } + +.off-canvas { + position: absolute; + background: #e6e6e6; + z-index: -1; + max-height: 100%; + overflow-y: auto; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); } + [data-whatinput='mouse'] .off-canvas { + outline: 0; } + .off-canvas.position-left { + left: -250px; + top: 0; + width: 250px; } + .is-open-left { + -webkit-transform: translateX(250px); + -ms-transform: translateX(250px); + transform: translateX(250px); } + .off-canvas.position-right { + right: -250px; + top: 0; + width: 250px; } + .is-open-right { + -webkit-transform: translateX(-250px); + -ms-transform: translateX(-250px); + transform: translateX(-250px); } + +@media screen and (min-width: 40em) { + .position-left.reveal-for-medium { + left: 0; + z-index: auto; + position: fixed; } + .position-left.reveal-for-medium ~ .off-canvas-content { + margin-left: 250px; } + .position-right.reveal-for-medium { + right: 0; + z-index: auto; + position: fixed; } + .position-right.reveal-for-medium ~ .off-canvas-content { + margin-right: 250px; } } + +@media screen and (min-width: 64em) { + .position-left.reveal-for-large { + left: 0; + z-index: auto; + position: fixed; } + .position-left.reveal-for-large ~ .off-canvas-content { + margin-left: 250px; } + .position-right.reveal-for-large { + right: 0; + z-index: auto; + position: fixed; } + .position-right.reveal-for-large ~ .off-canvas-content { + margin-right: 250px; } } + +.orbit { + position: relative; } + +.orbit-container { + position: relative; + margin: 0; + overflow: hidden; + list-style: none; } + +.orbit-slide { + width: 100%; + max-height: 100%; } + .orbit-slide.no-motionui.is-active { + top: 0; + left: 0; } + +.orbit-figure { + margin: 0; } + +.orbit-image { + margin: 0; + width: 100%; + max-width: 100%; } + +.orbit-caption { + position: absolute; + bottom: 0; + width: 100%; + padding: 1rem; + margin-bottom: 0; + color: #fefefe; + background-color: rgba(10, 10, 10, 0.5); } + +.orbit-previous, .orbit-next { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + z-index: 10; + padding: 1rem; + color: #fefefe; } + [data-whatinput='mouse'] .orbit-previous, [data-whatinput='mouse'] .orbit-next { + outline: 0; } + .orbit-previous:hover, .orbit-next:hover, .orbit-previous:active, .orbit-next:active, .orbit-previous:focus, .orbit-next:focus { + background-color: rgba(10, 10, 10, 0.5); } + +.orbit-previous { + left: 0; } + +.orbit-next { + left: auto; + right: 0; } + +.orbit-bullets { + position: relative; + margin-top: 0.8rem; + margin-bottom: 0.8rem; + text-align: center; } + [data-whatinput='mouse'] .orbit-bullets { + outline: 0; } + .orbit-bullets button { + width: 1.2rem; + height: 1.2rem; + margin: 0.1rem; + background-color: #cacaca; + border-radius: 50%; } + .orbit-bullets button:hover { + background-color: #8a8a8a; } + .orbit-bullets button.is-active { + background-color: #8a8a8a; } + +.pagination { + margin-left: 0; + margin-bottom: 1rem; } + .pagination::before, .pagination::after { + content: ' '; + display: table; } + .pagination::after { + clear: both; } + .pagination li { + font-size: 0.875rem; + margin-right: 0.0625rem; + border-radius: 0; + display: none; } + .pagination li:last-child, .pagination li:first-child { + display: inline-block; } + @media screen and (min-width: 40em) { + .pagination li { + display: inline-block; } } + .pagination a, + .pagination button { + color: #0a0a0a; + display: block; + padding: 0.1875rem 0.625rem; + border-radius: 0; } + .pagination a:hover, + .pagination button:hover { + background: #e6e6e6; } + .pagination .current { + padding: 0.1875rem 0.625rem; + background: #2199e8; + color: #fefefe; + cursor: default; } + .pagination .disabled { + padding: 0.1875rem 0.625rem; + color: #cacaca; + cursor: not-allowed; } + .pagination .disabled:hover { + background: transparent; } + .pagination .ellipsis::after { + content: '\2026'; + padding: 0.1875rem 0.625rem; + color: #0a0a0a; } + +.pagination-previous a::before, +.pagination-previous.disabled::before { + content: '\00ab'; + display: inline-block; + margin-right: 0.5rem; } + +.pagination-next a::after, +.pagination-next.disabled::after { + content: '\00bb'; + display: inline-block; + margin-left: 0.5rem; } + +.progress { + background-color: #cacaca; + height: 1rem; + margin-bottom: 1rem; + border-radius: 0; } + .progress.primary .progress-meter { + background-color: #2199e8; } + .progress.secondary .progress-meter { + background-color: #777; } + .progress.success .progress-meter { + background-color: #3adb76; } + .progress.warning .progress-meter { + background-color: #ffae00; } + .progress.alert .progress-meter { + background-color: #ec5840; } + +.progress-meter { + position: relative; + display: block; + width: 0%; + height: 100%; + background-color: #2199e8; } + +.progress-meter-text { + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + position: absolute; + margin: 0; + font-size: 0.75rem; + font-weight: bold; + color: #fefefe; + white-space: nowrap; } + +body.is-reveal-open { + overflow: hidden; } + +html.is-reveal-open, +html.is-reveal-open body { + height: 100%; + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +.reveal-overlay { + display: none; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1005; + background-color: rgba(10, 10, 10, 0.45); + overflow-y: scroll; } + +.reveal { + display: none; + z-index: 1006; + padding: 1rem; + border: 1px solid #cacaca; + background-color: #fefefe; + border-radius: 0; + position: relative; + top: 100px; + margin-left: auto; + margin-right: auto; + overflow-y: auto; } + [data-whatinput='mouse'] .reveal { + outline: 0; } + @media screen and (min-width: 40em) { + .reveal { + min-height: 0; } } + .reveal .column, .reveal .columns, + .reveal .columns { + min-width: 0; } + .reveal > :last-child { + margin-bottom: 0; } + @media screen and (min-width: 40em) { + .reveal { + width: 600px; + max-width: 75rem; } } + @media screen and (min-width: 40em) { + .reveal .reveal { + left: auto; + right: auto; + margin: 0 auto; } } + .reveal.collapse { + padding: 0; } + @media screen and (min-width: 40em) { + .reveal.tiny { + width: 30%; + max-width: 75rem; } } + @media screen and (min-width: 40em) { + .reveal.small { + width: 50%; + max-width: 75rem; } } + @media screen and (min-width: 40em) { + .reveal.large { + width: 90%; + max-width: 75rem; } } + .reveal.full { + top: 0; + left: 0; + width: 100%; + height: 100%; + height: 100vh; + min-height: 100vh; + max-width: none; + margin-left: 0; + border: 0; + border-radius: 0; } + @media screen and (max-width: 39.9375em) { + .reveal { + top: 0; + left: 0; + width: 100%; + height: 100%; + height: 100vh; + min-height: 100vh; + max-width: none; + margin-left: 0; + border: 0; + border-radius: 0; } } + .reveal.without-overlay { + position: fixed; } + +.slider { + position: relative; + height: 0.5rem; + margin-top: 1.25rem; + margin-bottom: 2.25rem; + background-color: #e6e6e6; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -ms-touch-action: none; + touch-action: none; } + +.slider-fill { + position: absolute; + top: 0; + left: 0; + display: inline-block; + max-width: 100%; + height: 0.5rem; + background-color: #cacaca; + transition: all 0.2s ease-in-out; } + .slider-fill.is-dragging { + transition: all 0s linear; } + +.slider-handle { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + position: absolute; + left: 0; + z-index: 1; + display: inline-block; + width: 1.4rem; + height: 1.4rem; + background-color: #2199e8; + transition: all 0.2s ease-in-out; + -ms-touch-action: manipulation; + touch-action: manipulation; + border-radius: 0; } + [data-whatinput='mouse'] .slider-handle { + outline: 0; } + .slider-handle:hover { + background-color: #1583cc; } + .slider-handle.is-dragging { + transition: all 0s linear; } + +.slider.disabled, +.slider[disabled] { + opacity: 0.25; + cursor: not-allowed; } + +.slider.vertical { + display: inline-block; + width: 0.5rem; + height: 12.5rem; + margin: 0 1.25rem; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); } + .slider.vertical .slider-fill { + top: 0; + width: 0.5rem; + max-height: 100%; } + .slider.vertical .slider-handle { + position: absolute; + top: 0; + left: 50%; + width: 1.4rem; + height: 1.4rem; + -webkit-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); } + +.sticky-container { + position: relative; } + +.sticky { + position: absolute; + z-index: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); } + +.sticky.is-stuck { + position: fixed; + z-index: 5; } + .sticky.is-stuck.is-at-top { + top: 0; } + .sticky.is-stuck.is-at-bottom { + bottom: 0; } + +.sticky.is-anchored { + position: absolute; + left: auto; + right: auto; } + .sticky.is-anchored.is-at-bottom { + bottom: 0; } + +.switch { + margin-bottom: 1rem; + outline: 0; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + color: #fefefe; + font-weight: bold; + font-size: 0.875rem; } + +.switch-input { + opacity: 0; + position: absolute; } + +.switch-paddle { + background: #cacaca; + cursor: pointer; + display: block; + position: relative; + width: 4rem; + height: 2rem; + transition: all 0.25s ease-out; + border-radius: 0; + color: inherit; + font-weight: inherit; } + input + .switch-paddle { + margin: 0; } + .switch-paddle::after { + background: #fefefe; + content: ''; + display: block; + position: absolute; + height: 1.5rem; + left: 0.25rem; + top: 0.25rem; + width: 1.5rem; + transition: all 0.25s ease-out; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + border-radius: 0; } + input:checked ~ .switch-paddle { + background: #2199e8; } + input:checked ~ .switch-paddle::after { + left: 2.25rem; } + [data-whatinput='mouse'] input:focus ~ .switch-paddle { + outline: 0; } + +.switch-active, .switch-inactive { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); } + +.switch-active { + left: 8%; + display: none; } + input:checked + label > .switch-active { + display: block; } + +.switch-inactive { + right: 15%; } + input:checked + label > .switch-inactive { + display: none; } + +.switch.tiny .switch-paddle { + width: 3rem; + height: 1.5rem; + font-size: 0.625rem; } + +.switch.tiny .switch-paddle::after { + width: 1rem; + height: 1rem; } + +.switch.tiny input:checked ~ .switch-paddle::after { + left: 1.75rem; } + +.switch.small .switch-paddle { + width: 3.5rem; + height: 1.75rem; + font-size: 0.75rem; } + +.switch.small .switch-paddle::after { + width: 1.25rem; + height: 1.25rem; } + +.switch.small input:checked ~ .switch-paddle::after { + left: 2rem; } + +.switch.large .switch-paddle { + width: 5rem; + height: 2.5rem; + font-size: 1rem; } + +.switch.large .switch-paddle::after { + width: 2rem; + height: 2rem; } + +.switch.large input:checked ~ .switch-paddle::after { + left: 2.75rem; } + +table { + width: 100%; + margin-bottom: 1rem; + border-radius: 0; } + table thead, + table tbody, + table tfoot { + border: 1px solid #f1f1f1; + background-color: #fefefe; } + table caption { + font-weight: bold; + padding: 0.5rem 0.625rem 0.625rem; } + table thead, + table tfoot { + background: #f8f8f8; + color: #0a0a0a; } + table thead tr, + table tfoot tr { + background: transparent; } + table thead th, + table thead td, + table tfoot th, + table tfoot td { + padding: 0.5rem 0.625rem 0.625rem; + font-weight: bold; + text-align: left; } + table tbody tr:nth-child(even) { + background-color: #f1f1f1; } + table tbody th, + table tbody td { + padding: 0.5rem 0.625rem 0.625rem; } + +@media screen and (max-width: 63.9375em) { + table.stack thead { + display: none; } + table.stack tfoot { + display: none; } + table.stack tr, + table.stack th, + table.stack td { + display: block; } + table.stack td { + border-top: 0; } } + +table.scroll { + display: block; + width: 100%; + overflow-x: auto; } + +table.hover tr:hover { + background-color: #f9f9f9; } + +table.hover tr:nth-of-type(even):hover { + background-color: #ececec; } + +.table-scroll { + overflow-x: auto; } + .table-scroll table { + width: auto; } + +.tabs { + margin: 0; + list-style-type: none; + background: #fefefe; + border: 1px solid #e6e6e6; } + .tabs::before, .tabs::after { + content: ' '; + display: table; } + .tabs::after { + clear: both; } + +.tabs.vertical > li { + width: auto; + float: none; + display: block; } + +.tabs.simple > li > a { + padding: 0; } + .tabs.simple > li > a:hover { + background: transparent; } + +.tabs.primary { + background: #2199e8; } + .tabs.primary > li > a { + color: #fefefe; } + .tabs.primary > li > a:hover, .tabs.primary > li > a:focus { + background: #1893e4; } + +.tabs-title { + float: left; } + .tabs-title > a { + display: block; + padding: 1.25rem 1.5rem; + line-height: 1; + font-size: 0.75rem; } + .tabs-title > a:hover { + background: #fefefe; } + .tabs-title > a:focus, .tabs-title > a[aria-selected='true'] { + background: #e6e6e6; } + +.tabs-content { + background: #fefefe; + transition: all 0.5s ease; + border: 1px solid #e6e6e6; + border-top: 0; } + +.tabs-content.vertical { + border: 1px solid #e6e6e6; + border-left: 0; } + +.tabs-panel { + display: none; + padding: 1rem; } + .tabs-panel.is-active { + display: block; } + +.thumbnail { + border: solid 4px #fefefe; + box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.2); + display: inline-block; + line-height: 0; + max-width: 100%; + transition: box-shadow 200ms ease-out; + border-radius: 0; + margin-bottom: 1rem; } + .thumbnail:hover, .thumbnail:focus { + box-shadow: 0 0 6px 1px rgba(33, 153, 232, 0.5); } + +.title-bar { + background: #0a0a0a; + color: #fefefe; + padding: 0.5rem; } + .title-bar::before, .title-bar::after { + content: ' '; + display: table; } + .title-bar::after { + clear: both; } + .title-bar .menu-icon { + margin-left: 0.25rem; + margin-right: 0.25rem; } + +.title-bar-left { + float: left; } + +.title-bar-right { + float: right; + text-align: right; } + +.title-bar-title { + font-weight: bold; + vertical-align: middle; + display: inline-block; } + +.menu-icon.dark { + position: relative; + display: inline-block; + vertical-align: middle; + cursor: pointer; + width: 20px; + height: 16px; } + .menu-icon.dark::after { + content: ''; + position: absolute; + display: block; + width: 100%; + height: 2px; + background: #0a0a0a; + top: 0; + left: 0; + box-shadow: 0 7px 0 #0a0a0a, 0 14px 0 #0a0a0a; } + .menu-icon.dark:hover::after { + background: #8a8a8a; + box-shadow: 0 7px 0 #8a8a8a, 0 14px 0 #8a8a8a; } + +.has-tip { + border-bottom: dotted 1px #8a8a8a; + font-weight: bold; + position: relative; + display: inline-block; + cursor: help; } + +.tooltip { + background-color: #0a0a0a; + color: #fefefe; + font-size: 80%; + padding: 0.75rem; + position: absolute; + z-index: 10; + top: calc(100% + 0.6495rem); + max-width: 10rem !important; + border-radius: 0; } + .tooltip::before { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 0.75rem; + border-color: transparent transparent #0a0a0a; + border-bottom-style: solid; + border-top-width: 0; + bottom: 100%; + position: absolute; + left: 50%; + -webkit-transform: translateX(-50%); + -ms-transform: translateX(-50%); + transform: translateX(-50%); } + .tooltip.top::before { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 0.75rem; + border-color: #0a0a0a transparent transparent; + border-top-style: solid; + border-bottom-width: 0; + top: 100%; + bottom: auto; } + .tooltip.left::before { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 0.75rem; + border-color: transparent transparent transparent #0a0a0a; + border-left-style: solid; + border-right-width: 0; + bottom: auto; + left: 100%; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); } + .tooltip.right::before { + content: ''; + display: block; + width: 0; + height: 0; + border: inset 0.75rem; + border-color: transparent #0a0a0a transparent transparent; + border-right-style: solid; + border-left-width: 0; + bottom: auto; + left: auto; + right: 100%; + top: 50%; + -webkit-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); } + +.top-bar { + padding: 0.5rem; } + .top-bar::before, .top-bar::after { + content: ' '; + display: table; } + .top-bar::after { + clear: both; } + .top-bar, + .top-bar ul { + background-color: #e6e6e6; } + .top-bar input { + max-width: 200px; + margin-right: 1rem; } + .top-bar .input-group-field { + width: 100%; + margin-right: 0; } + .top-bar input.button { + width: auto; } + .top-bar .top-bar-left, + .top-bar .top-bar-right { + width: 100%; } + @media screen and (min-width: 40em) { + .top-bar .top-bar-left, + .top-bar .top-bar-right { + width: auto; } } + @media screen and (max-width: 63.9375em) { + .top-bar.stacked-for-medium .top-bar-left, + .top-bar.stacked-for-medium .top-bar-right { + width: 100%; } } + @media screen and (max-width: 74.9375em) { + .top-bar.stacked-for-large .top-bar-left, + .top-bar.stacked-for-large .top-bar-right { + width: 100%; } } + +.top-bar-title { + float: left; + margin-right: 1rem; } + +.top-bar-left { + float: left; } + +.top-bar-right { + float: right; } + +.hide { + display: none !important; } + +.invisible { + visibility: hidden; } + +@media screen and (max-width: 39.9375em) { + .hide-for-small-only { + display: none !important; } } + +@media screen and (max-width: 0em), screen and (min-width: 40em) { + .show-for-small-only { + display: none !important; } } + +@media screen and (min-width: 40em) { + .hide-for-medium { + display: none !important; } } + +@media screen and (max-width: 39.9375em) { + .show-for-medium { + display: none !important; } } + +@media screen and (min-width: 40em) and (max-width: 63.9375em) { + .hide-for-medium-only { + display: none !important; } } + +@media screen and (max-width: 39.9375em), screen and (min-width: 64em) { + .show-for-medium-only { + display: none !important; } } + +@media screen and (min-width: 64em) { + .hide-for-large { + display: none !important; } } + +@media screen and (max-width: 63.9375em) { + .show-for-large { + display: none !important; } } + +@media screen and (min-width: 64em) and (max-width: 74.9375em) { + .hide-for-large-only { + display: none !important; } } + +@media screen and (max-width: 63.9375em), screen and (min-width: 75em) { + .show-for-large-only { + display: none !important; } } + +.show-for-sr, +.show-on-focus { + position: absolute !important; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); } + +.show-on-focus:active, .show-on-focus:focus { + position: static !important; + height: auto; + width: auto; + overflow: visible; + clip: auto; } + +.show-for-landscape, +.hide-for-portrait { + display: block !important; } + @media screen and (orientation: landscape) { + .show-for-landscape, + .hide-for-portrait { + display: block !important; } } + @media screen and (orientation: portrait) { + .show-for-landscape, + .hide-for-portrait { + display: none !important; } } + +.hide-for-landscape, +.show-for-portrait { + display: none !important; } + @media screen and (orientation: landscape) { + .hide-for-landscape, + .show-for-portrait { + display: none !important; } } + @media screen and (orientation: portrait) { + .hide-for-landscape, + .show-for-portrait { + display: block !important; } } + +.float-left { + float: left !important; } + +.float-right { + float: right !important; } + +.float-center { + display: block; + margin-left: auto; + margin-right: auto; } + +.clearfix::before, .clearfix::after { + content: ' '; + display: table; } + +.clearfix::after { + clear: both; } + +.slide-in-down.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-in-down.mui-enter.mui-enter-active { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); } + +.slide-in-left.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-in-left.mui-enter.mui-enter-active { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); } + +.slide-in-up.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateY(100%); + -ms-transform: translateY(100%); + transform: translateY(100%); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-in-up.mui-enter.mui-enter-active { + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); } + +.slide-in-right.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-in-right.mui-enter.mui-enter-active { + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); } + +.slide-out-down.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-out-down.mui-leave.mui-leave-active { + -webkit-transform: translateY(100%); + -ms-transform: translateY(100%); + transform: translateY(100%); } + +.slide-out-right.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-out-right.mui-leave.mui-leave-active { + -webkit-transform: translateX(100%); + -ms-transform: translateX(100%); + transform: translateX(100%); } + +.slide-out-up.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-out-up.mui-leave.mui-leave-active { + -webkit-transform: translateY(-100%); + -ms-transform: translateY(-100%); + transform: translateY(-100%); } + +.slide-out-left.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; } + +.slide-out-left.mui-leave.mui-leave-active { + -webkit-transform: translateX(-100%); + -ms-transform: translateX(-100%); + transform: translateX(-100%); } + +.fade-in.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + opacity: 0; + transition-property: opacity; } + +.fade-in.mui-enter.mui-enter-active { + opacity: 1; } + +.fade-out.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + opacity: 1; + transition-property: opacity; } + +.fade-out.mui-leave.mui-leave-active { + opacity: 0; } + +.hinge-in-from-top.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateX(-90deg); + transform: perspective(2000px) rotateX(-90deg); + -webkit-transform-origin: top; + -ms-transform-origin: top; + transform-origin: top; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-top.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-in-from-right.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateY(-90deg); + transform: perspective(2000px) rotateY(-90deg); + -webkit-transform-origin: right; + -ms-transform-origin: right; + transform-origin: right; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-right.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-in-from-bottom.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateX(90deg); + transform: perspective(2000px) rotateX(90deg); + -webkit-transform-origin: bottom; + -ms-transform-origin: bottom; + transform-origin: bottom; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-bottom.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-in-from-left.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateY(90deg); + transform: perspective(2000px) rotateY(90deg); + -webkit-transform-origin: left; + -ms-transform-origin: left; + transform-origin: left; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-left.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-in-from-middle-x.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateX(-90deg); + transform: perspective(2000px) rotateX(-90deg); + -webkit-transform-origin: center; + -ms-transform-origin: center; + transform-origin: center; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-middle-x.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-in-from-middle-y.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotateY(-90deg); + transform: perspective(2000px) rotateY(-90deg); + -webkit-transform-origin: center; + -ms-transform-origin: center; + transform-origin: center; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.hinge-in-from-middle-y.mui-enter.mui-enter-active { + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + opacity: 1; } + +.hinge-out-from-top.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: top; + -ms-transform-origin: top; + transform-origin: top; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-top.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateX(-90deg); + transform: perspective(2000px) rotateX(-90deg); + opacity: 0; } + +.hinge-out-from-right.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: right; + -ms-transform-origin: right; + transform-origin: right; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-right.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateY(-90deg); + transform: perspective(2000px) rotateY(-90deg); + opacity: 0; } + +.hinge-out-from-bottom.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: bottom; + -ms-transform-origin: bottom; + transform-origin: bottom; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-bottom.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateX(90deg); + transform: perspective(2000px) rotateX(90deg); + opacity: 0; } + +.hinge-out-from-left.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: left; + -ms-transform-origin: left; + transform-origin: left; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-left.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateY(90deg); + transform: perspective(2000px) rotateY(90deg); + opacity: 0; } + +.hinge-out-from-middle-x.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: center; + -ms-transform-origin: center; + transform-origin: center; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-middle-x.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateX(-90deg); + transform: perspective(2000px) rotateX(-90deg); + opacity: 0; } + +.hinge-out-from-middle-y.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: perspective(2000px) rotate(0deg); + transform: perspective(2000px) rotate(0deg); + -webkit-transform-origin: center; + -ms-transform-origin: center; + transform-origin: center; + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.hinge-out-from-middle-y.mui-leave.mui-leave-active { + -webkit-transform: perspective(2000px) rotateY(-90deg); + transform: perspective(2000px) rotateY(-90deg); + opacity: 0; } + +.scale-in-up.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: scale(0.5); + -ms-transform: scale(0.5); + transform: scale(0.5); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.scale-in-up.mui-enter.mui-enter-active { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + opacity: 1; } + +.scale-in-down.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: scale(1.5); + -ms-transform: scale(1.5); + transform: scale(1.5); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.scale-in-down.mui-enter.mui-enter-active { + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + opacity: 1; } + +.scale-out-up.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.scale-out-up.mui-leave.mui-leave-active { + -webkit-transform: scale(1.5); + -ms-transform: scale(1.5); + transform: scale(1.5); + opacity: 0; } + +.scale-out-down.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.scale-out-down.mui-leave.mui-leave-active { + -webkit-transform: scale(0.5); + -ms-transform: scale(0.5); + transform: scale(0.5); + opacity: 0; } + +.spin-in.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: rotate(-0.75turn); + -ms-transform: rotate(-0.75turn); + transform: rotate(-0.75turn); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.spin-in.mui-enter.mui-enter-active { + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; } + +.spin-out.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.spin-out.mui-leave.mui-leave-active { + -webkit-transform: rotate(0.75turn); + -ms-transform: rotate(0.75turn); + transform: rotate(0.75turn); + opacity: 0; } + +.spin-in-ccw.mui-enter { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: rotate(0.75turn); + -ms-transform: rotate(0.75turn); + transform: rotate(0.75turn); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 0; } + +.spin-in-ccw.mui-enter.mui-enter-active { + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + opacity: 1; } + +.spin-out-ccw.mui-leave { + transition-duration: 500ms; + transition-timing-function: linear; + -webkit-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + transition-property: -webkit-transform, opacity; + transition-property: transform, opacity; + opacity: 1; } + +.spin-out-ccw.mui-leave.mui-leave-active { + -webkit-transform: rotate(-0.75turn); + -ms-transform: rotate(-0.75turn); + transform: rotate(-0.75turn); + opacity: 0; } + +.slow { + transition-duration: 750ms !important; } + +.fast { + transition-duration: 250ms !important; } + +.linear { + transition-timing-function: linear !important; } + +.ease { + transition-timing-function: ease !important; } + +.ease-in { + transition-timing-function: ease-in !important; } + +.ease-out { + transition-timing-function: ease-out !important; } + +.ease-in-out { + transition-timing-function: ease-in-out !important; } + +.bounce-in { + transition-timing-function: cubic-bezier(0.485, 0.155, 0.24, 1.245) !important; } + +.bounce-out { + transition-timing-function: cubic-bezier(0.485, 0.155, 0.515, 0.845) !important; } + +.bounce-in-out { + transition-timing-function: cubic-bezier(0.76, -0.245, 0.24, 1.245) !important; } + +.short-delay { + transition-delay: 300ms !important; } + +.long-delay { + transition-delay: 700ms !important; } + +.shake { + -webkit-animation-name: shake-7; + animation-name: shake-7; } + +@-webkit-keyframes shake-7 { + 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% { + -webkit-transform: translateX(7%); + transform: translateX(7%); } + 5%, 15%, 25%, 35%, 45%, 55%, 65%, 75%, 85%, 95% { + -webkit-transform: translateX(-7%); + transform: translateX(-7%); } } + +@keyframes shake-7 { + 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% { + -webkit-transform: translateX(7%); + transform: translateX(7%); } + 5%, 15%, 25%, 35%, 45%, 55%, 65%, 75%, 85%, 95% { + -webkit-transform: translateX(-7%); + transform: translateX(-7%); } } + +.spin-cw { + -webkit-animation-name: spin-cw-1turn; + animation-name: spin-cw-1turn; } + +@-webkit-keyframes spin-cw-1turn { + 0% { + -webkit-transform: rotate(-1turn); + transform: rotate(-1turn); } + 100% { + -webkit-transform: rotate(0); + transform: rotate(0); } } + +@keyframes spin-cw-1turn { + 0% { + -webkit-transform: rotate(-1turn); + transform: rotate(-1turn); } + 100% { + -webkit-transform: rotate(0); + transform: rotate(0); } } + +.spin-ccw { + -webkit-animation-name: spin-cw-1turn; + animation-name: spin-cw-1turn; } + +@keyframes spin-cw-1turn { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); } + 100% { + -webkit-transform: rotate(1turn); + transform: rotate(1turn); } } + +.wiggle { + -webkit-animation-name: wiggle-7deg; + animation-name: wiggle-7deg; } + +@-webkit-keyframes wiggle-7deg { + 40%, 50%, 60% { + -webkit-transform: rotate(7deg); + transform: rotate(7deg); } + 35%, 45%, 55%, 65% { + -webkit-transform: rotate(-7deg); + transform: rotate(-7deg); } + 0%, 30%, 70%, 100% { + -webkit-transform: rotate(0); + transform: rotate(0); } } + +@keyframes wiggle-7deg { + 40%, 50%, 60% { + -webkit-transform: rotate(7deg); + transform: rotate(7deg); } + 35%, 45%, 55%, 65% { + -webkit-transform: rotate(-7deg); + transform: rotate(-7deg); } + 0%, 30%, 70%, 100% { + -webkit-transform: rotate(0); + transform: rotate(0); } } + +.shake, +.spin-cw, +.spin-ccw, +.wiggle { + -webkit-animation-duration: 500ms; + animation-duration: 500ms; } + +.infinite { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; } + +.slow { + -webkit-animation-duration: 750ms !important; + animation-duration: 750ms !important; } + +.fast { + -webkit-animation-duration: 250ms !important; + animation-duration: 250ms !important; } + +.linear { + -webkit-animation-timing-function: linear !important; + animation-timing-function: linear !important; } + +.ease { + -webkit-animation-timing-function: ease !important; + animation-timing-function: ease !important; } + +.ease-in { + -webkit-animation-timing-function: ease-in !important; + animation-timing-function: ease-in !important; } + +.ease-out { + -webkit-animation-timing-function: ease-out !important; + animation-timing-function: ease-out !important; } + +.ease-in-out { + -webkit-animation-timing-function: ease-in-out !important; + animation-timing-function: ease-in-out !important; } + +.bounce-in { + -webkit-animation-timing-function: cubic-bezier(0.485, 0.155, 0.24, 1.245) !important; + animation-timing-function: cubic-bezier(0.485, 0.155, 0.24, 1.245) !important; } + +.bounce-out { + -webkit-animation-timing-function: cubic-bezier(0.485, 0.155, 0.515, 0.845) !important; + animation-timing-function: cubic-bezier(0.485, 0.155, 0.515, 0.845) !important; } + +.bounce-in-out { + -webkit-animation-timing-function: cubic-bezier(0.76, -0.245, 0.24, 1.245) !important; + animation-timing-function: cubic-bezier(0.76, -0.245, 0.24, 1.245) !important; } + +.short-delay { + -webkit-animation-delay: 300ms !important; + animation-delay: 300ms !important; } + +.long-delay { + -webkit-animation-delay: 700ms !important; + animation-delay: 700ms !important; } diff --git a/app/assets/stylesheets/homepages.scss b/app/assets/stylesheets/homepages.scss new file mode 100644 index 0000000000..e42583ae81 --- /dev/null +++ b/app/assets/stylesheets/homepages.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the homepages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/orders.scss b/app/assets/stylesheets/orders.scss new file mode 100644 index 0000000000..3b0428a94e --- /dev/null +++ b/app/assets/stylesheets/orders.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/products.scss b/app/assets/stylesheets/products.scss new file mode 100644 index 0000000000..89e2e8db07 --- /dev/null +++ b/app/assets/stylesheets/products.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the products controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/reviews.scss b/app/assets/stylesheets/reviews.scss new file mode 100644 index 0000000000..6ea2454d26 --- /dev/null +++ b/app/assets/stylesheets/reviews.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the reviews controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss new file mode 100644 index 0000000000..7bef9cf826 --- /dev/null +++ b/app/assets/stylesheets/sessions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the sessions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss new file mode 100644 index 0000000000..1efc835ccd --- /dev/null +++ b/app/assets/stylesheets/users.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the users controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d83690e1b9..81bf2c8c46 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,12 @@ class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception + + helper_method :current_user +private + + def current_user + @current_user = User.find_by(id: session[:user_id] ) + end + end diff --git a/app/controllers/homepages_controller.rb b/app/controllers/homepages_controller.rb new file mode 100644 index 0000000000..23e4efbb0d --- /dev/null +++ b/app/controllers/homepages_controller.rb @@ -0,0 +1,15 @@ +class HomepagesController < ApplicationController + + def index + @product_categories = Product.uniq.pluck(:category) + # grabbing all listings + @products = Product.all + end + + def show_category + # @product = Product.find(params[:id]) + @product_category = params[:category] + @products_in_category = Product.where(:category => @product_category) + end + +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..34b715f01f --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,175 @@ +class OrdersController < ApplicationController + before_action :authenticate_user!, only: [:cancel_order] + + def add_to_cart + # if there is no cart_id in session, or the cart_id can not be found in database, which means this user has no cart at all, we will create a new one. + + # two possibilities that @order can be nil: 1) session[:cart_id] == nil, 2) session[:cart_id] != nil && database does not have order with the :cart_id. + if session[:cart_id] + @order = Order.find_by(:id => session[:cart_id].to_i) + end + + if !@order + @order = Order.new + @order.status = "pending" + @order.user_id = session[:user_id] + # save! ensure @order is saved, if not, it will raise an exception and visibly break the program. + @order.save! + session[:cart_id] = @order.id + end + + @product = Product.find(params[:product_id]) + # if user puts more than one order_items with same product_id in cart in seperate occasions, there should be only one order_item for this product in cart. + # Just update the total quantity of the order_items. + + # [TEST]write a test case here! + + order_items = OrderItem.where(:order_id => @order.id, :product_id => params[:product_id]) + + if order_items.length >= 1 + @order_item = order_items.first + @order_item.quantity += params[:quantity].to_i + @order_item.save! + else + @order_item = OrderItem.new + @order_item.order_id = session[:cart_id] + @order_item.quantity = params[:quantity].to_i + @order_item.unit_price = @product.price + @order_item.product_id = @product.id + @order_item.status = "pending" + @order_item.save! + end + redirect_to action: 'show_cart' + end + + def show_cart + if session[:cart_id] + @order_items = OrderItem.where(:order_id => session[:cart_id]) + else + @order_items = [] + end + + @order = Order.find_by(:id => session[:cart_id]) || Order.new + end + + def change_quantity + order_item_id = params[:order_item_id] + order_item = OrderItem.find_by(:id => order_item_id) + if !order_item + redirect_to action: 'show_cart' + end + + order_item.quantity = params[:quantity].to_i + order_item.save! + redirect_to action: 'show_cart' + end + + def destroy_order_item + order_item_id = params[:order_item_id] + OrderItem.destroy(order_item_id) + + redirect_to action: 'show_cart' + end + + def checkout + + if session[:cart_id] + @order_items = OrderItem.where(:order_id => session[:cart_id]) + else + @order_items = [] + end + @order = Order.find_by(:id => session[:cart_id]) || Order.new + + if @order.order_items.length == 0 + flash[:alert] = "Your cart is empty. Nothing can be checkout." + return redirect_to action: 'show_cart' + end + end + + def create_order + @order = Order.find(params[:order_id]) + # make sure all order items's inventory can be ordered + + # check if product inventory is sufficient for purchase quantity + @order.order_items.each do |order_item| + if order_item.quantity > order_item.product.inventory + flash[:notice] = "#{order_item.product.name}'s inventory is not enough to fullfill your order. Please change your Quantity and submit again." + return redirect_to action: 'show' + end + end + + @order.user_id = session[:user_id] + @order.name = params[:order][:name] + @order.email = params[:order][:email] + @order.street_address = params[:order][:street_address] + @order.city = params[:order][:city] + @order.state = params[:order][:state] + @order.zip = params[:order][:zip] + @order.phone = params[:order][:phone] + @order.cc_number = params[:order][:cc_number] + @order.exp_month = params[:order][:exp_month] + @order.exp_year = params[:order][:exp_year] + @order.cvc = params[:order][:cvc] + + @order.status = "paid" + @order.save! + + # cart has been coverted to an order, it is no + # longer a "cart", let's clear it from session + session[:cart_id] = nil + + @order.order_items.each do |order_item| + # update order item status to "sold" + order_item.status = "paid" + order_item.save! + + # when sold, product's inventory is reduced accordingly. + order_item.product.inventory -= order_item.quantity + order_item.product.save! + end + + # check if product inventory is sufficient for purchase quantity + redirect_to confirmation_path(@order.id) + end + + def confirmation + @order = Order.find(params[:order_id]) + end + + def cancel_order + order_id = params[:order_id] + order = Order.find(order_id) + order.status = "cancelled" + order.order_items.each do |order_item| + order_item.status = "cancelled" + order_item.save! + end + order.save! + + redirect_to buyer_manage_path + end + + def index + + end + + def show + + end + + def new + + end + + + + def edit + + end + + def update + + end + + +end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000000..eeb7d79fa2 --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,95 @@ +class ProductsController < ApplicationController + def index + @products = Product.all.order("name") + end + + def show + @product = Product.find_by_id(params[:id].to_i) + + if @product.user_id + @seller = @product.user + # @seller = User.find(@product.user_id) + else + @seller = User.new + end + + @reviews = Review.where(:product_id => @product.id) + + end + + def show_seller_products + @product = Product.find(params[:id].to_i) + @products = Product.where(:user_id => @product.user_id) + end + + def search + @products = Product.search(params[:query]) + # if product query matches a product(s) + # render those image(s), if any match. + render :index + end + + + def new + @product = Product.new + @post_method = :post + @post_path = 'create' + end + + def create + + @product = Product.new(name: params[:product][:name], description: params[:product][:description], price: params[:product][:price], inventory: params[:product][:inventory], category: params[:product][:category], user_id: session[:user_id]) + @product.save + + redirect_to show_seller_products_path(@product.id) + # does rails think I mean to redirect to the method instead of the path? why doesn't it need an id for this route? + end + + def edit + @product = Product.find(params[:id]) + @post_method = :patch + @post_path = 'update' + + end + + def update + # @params = params + + @post_method = :patch + @post_path = 'update' + + + + @product = Product.find(params[:id]) + + if @product == nil + render :file => 'public/404.html' + # :status => :not_found + end + + @product.name = params[:product][:name] + @product.description = params[:product][:description] + @product.inventory = params[:product][:inventory] + @product.category = params[:product][:category] + if @product.save + redirect_to show_products_path(@product.id) + # else + # @error = "Did not save successfully. Try again!" + end + + + + + end + + def destroy + @product = Product.find(params[:id]) + @product.destroy + + redirect_to root_path + end + + + + +end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..e89acaf075 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,52 @@ +class ReviewsController < ApplicationController + before_action :find_review, only: [:show] + + def index + @reviews = Review.all + end + + def show; end + + def new + @review = Review.new + @product = Product.find(params[:id]) + end + + def create + @product = Product.find(params[:id]) + @review = Review.create(review_params) + @review.description = params[:review][:description] + @review.rank = params[:review][:rank] + + @review.product_id = @product.id + @review.user_id = session[:user_id] + + if @review.save + redirect_to show_products_path(@product.id) + else + render new_review_path + end + end + + def edit + # NO EDITING + end + + def update + # NO UPDATING + end + + def destroy +#NO DELETING + end + + private + def review_params + params.require(:review).permit(:rating, :description) + end + + def find_review + @review = Review.find(params[:id]) + end + +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000000..8efdec61f7 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,52 @@ +class SessionsController < ApplicationController + def index + @user = User.find(session[:user_id]) # < recalls the value set in a previous request + end + + def show + end + + def new + + end + + def create + + #GITHUB AUTHENTICATION START + auth_hash = request.env['omniauth.auth'] + #raise can go here too to get auth hash + return redirect_to root_path unless auth_hash['uid'] + + @user = User.find_by(uid: auth_hash[:uid], provider: 'github') + + if @user.nil? + @user = User.build_from_github(auth_hash) + flash[:notice] = "Unable to Save the User" +#using method below to save time + return redirect_to root_path unless @user.save! + # render :creation_failure unless @user.save + end + + # Save the user ID in the session + session[:user_id] = @user.id + + + # redirect_to sessions_path +#doing this other thing to save time + flash[:notice] = "Successfully Logged in!" + redirect_to root_path + +#GITHUB AUTHENTICATION END + end + + def edit + end + + def update + end + + def destroy + session[:user_id] = nil + redirect_to root_path, notice: 'Successfully logged out.' + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000000..5adb8ff95d --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,149 @@ +class UsersController < ApplicationController + before_action :authenticate_user!, only: [:user_account, :buyer_manage, :seller_manage, :pending_orders, :paid_orders, :cancelled_orders, :completed_orders] + # before_action :find_user only [:show, :edit, :update, :destroy] + +#AN IDEA FOR HOW TO LIMIT PRODUCT EDITING? + # app/controllers/users_controller + # before_action :require_login + # ... + # private + # def require_login + # # do stuff to check if user is logged in + # end + +#============User Account: Buyer Manage============= + def user_account + @user = User.find(session[:user_id]) + end + + def buyer_manage + @user = User.find(session[:user_id]) + @orders = @user.orders + end + + def show_revenue_count + @total_revenue = OrderItem.total_revenue(@user_id) + @total_count = OrderItem.total_count(@user_id) + + @paid_revenue = OrderItem.paid_revenue(@user_id) + @paid_count = OrderItem.paid_count(@user_id) + + @fulfilled_revenue = OrderItem.fulfilled_revenue(@user_id) + @fulfilled_count = OrderItem.fulfilled_count(@user_id) + + @cancelled_revenue = OrderItem.cancelled_revenue(@user_id) + @cancelled_count = OrderItem.cancelled_count(@user_id) + end +#===========User Account: seller Manage============= + def seller_manage + # status = params[:status] + @user_id = session[:user_id] + @user = User.find(@user_id) + + show_revenue_count + + # @order_items = OrderItem.by_status(@user_id, status) + @order_items = OrderItem.joins(:product).where('products.user_id' => @user_id) + end + + def show_orders_by_status + + @user = User.find(session[:user_id]) + @orders = @user.orders.where(:status => status) + redirect_to buyer_manage_path + end + + def get_order_by_status + status = params[:status] + @user_id = session[:user_id] + @user = User.find(@user_id) + @order_items = OrderItem.by_status(@user_id, status) + + show_revenue_count + + render 'seller_manage' + end + + def ship_order_item + + order_item = OrderItem.find(params[:order_item_id]) + order_item.status = "fulfilled" + + order_item.save! + + redirect_to action: 'seller_manage' + end + + def order_by_seller + order_item = OrderItem.find(params[:order_id]) + @order = order_item.order + end + +#==============User Authenticate============= + + def index + return User.all + end + + def show + # @my_user = User.find{ params[:id].to_i } + end + + def new + # @my_user = User.new params[:user] + end + + def create + # @my_user = User.new user_params + # if @my_user.save + # redirect_to root_path, notice: 'Successfully created user.' + # else render :new + # end + end + + + def edit + @my_user = User.find{ params[:id].to_i } + @path = 'update_path' + end + + def update + @my_user = User.find{ params[:id].to_i } + @params = params + @my_user.fname = params[:user][:name] + @my_user.email = params[:user][:email] + @my_user.street_address = params[:user][:street_address] + @my_user.city = params[:user][:city] + @my_user.state = params[:user][:state] + @my_user.zip = params[:user][:zip] + @my_user.phone = params[:user][:phone] + @my_user.merchant = params[:user][:merchant] + @my_user.provider = params[:user][:provider] + @my_user.status = params[:user][:status] + end + +#really is 'deactivate' + def destroy + @my_user = User.find{ params[:id] } + @my_user.status = false + @my_user.save + end + + +private + + def find_user + # @my_user = User.find{ params[:id] } + end + + def user_params + # params.require(:user).permit :email, :password, :password_confirmation + end + + def authenticate_user! + if !session[:user_id] + flash[:error] = "You must be signed in" + return redirect_to root_path + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de6be7945c..137a91e14e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,2 +1,5 @@ module ApplicationHelper + def get_product_categories + Product.uniq.pluck(:category) + end end diff --git a/app/helpers/homepages_helper.rb b/app/helpers/homepages_helper.rb new file mode 100644 index 0000000000..4bd8098f37 --- /dev/null +++ b/app/helpers/homepages_helper.rb @@ -0,0 +1,2 @@ +module HomepagesHelper +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000000..443227fd48 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,2 @@ +module OrdersHelper +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000000..ab5c42b325 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,2 @@ +module ProductsHelper +end diff --git a/app/helpers/reviews_helper.rb b/app/helpers/reviews_helper.rb new file mode 100644 index 0000000000..682b7b1abc --- /dev/null +++ b/app/helpers/reviews_helper.rb @@ -0,0 +1,2 @@ +module ReviewsHelper +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb new file mode 100644 index 0000000000..309f8b2eb3 --- /dev/null +++ b/app/helpers/sessions_helper.rb @@ -0,0 +1,2 @@ +module SessionsHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000000..2310a240d7 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..08c407cdae --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,14 @@ +class Order < ActiveRecord::Base + belongs_to :product + belongs_to :user + has_many :order_items + validates :price, presence: true, numericality: {:greater_than => 0} + + + def total_price + return self.order_items.inject(0) {|sum, order_item | sum + order_item.total_price } + end + + + +end diff --git a/app/models/order_item.rb b/app/models/order_item.rb new file mode 100644 index 0000000000..fd2898bc95 --- /dev/null +++ b/app/models/order_item.rb @@ -0,0 +1,58 @@ +class OrderItem < ActiveRecord::Base + belongs_to :product + belongs_to :order + + def total_price + return self.unit_price * self.quantity + end + + # Only OrderItem model is directly linked to seller. + # Order item has three status, pending, paid, fulfilled, cancelled. + # refactored the order item status logic, changes the order item status whenever he order status on payment changes. + def self.by_status(user_id, status) + return self.joins(:product) + .where( + 'products.user_id' => user_id, + :status => status + ) + end + + def self.revenue_by_status(user_id, status) + return self.by_status(user_id, status).inject(0) do |sum, paid_order| + sum + paid_order.total_price + end + end + + def self.paid_revenue(user_id) + return self.revenue_by_status(user_id, "paid") + end + + def self.paid_count(user_id) + return self.by_status(user_id, "paid").count + end + + def self.fulfilled_revenue(user_id) + return self.revenue_by_status(user_id, "fulfilled") + end + + def self.fulfilled_count(user_id) + return self.by_status(user_id, "fulfilled").count + end + + # total revenue = paid revenue + fulfilled revenue + def self.total_revenue(user_id) + return self.paid_revenue(user_id) + self.fulfilled_revenue(user_id) + end + + def self.total_count(user_id) + return self.paid_count(user_id) + self.fulfilled_count(user_id) + end + + def self.cancelled_revenue(user_id) + return self.revenue_by_status(user_id, "cancelled") + end + + def self.cancelled_count(user_id) + return self.by_status(user_id, "cancelled").count + end +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000000..049de1f138 --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,29 @@ +class Product < ActiveRecord::Base + belongs_to :user + has_many :orders + has_many :order_items, through: :orders + + validates :name, :description, :category, presence: true + + validates :price, presence: true, numericality: {:greater_than => 0} + + validates :inventory, presence: true, numericality: {:greater_than_or_equal_to => 0} + + + + + def average_rating + reviews = Review.where(:product_id => self.id) + return reviews.average(:rank) + end + + private + def self.random_photo(wanted_category) + Product.where(category: wanted_category).sample.photo_url + end + + def self.search(query) + where("name LIKE ? OR description LIKE ?", "%#{query}%", "%#{query}%") + end + +end diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..e061982d80 --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,5 @@ +class Review < ActiveRecord::Base + belongs_to :user + # validates :rank, presence: true, only_integer: true, :inclusion => 1..5, message: "only allows integers 1-5" + +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000000..d21471d854 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,18 @@ +class User < ActiveRecord::Base + has_many :reviews + has_many :products + has_many :orders + # has_secure_password + + validates :email, :uid, :provider, presence: true + + def self.build_from_github(auth_hash) + user = User.new + user.uid = auth_hash[:uid] + user.provider = 'github' + user.name = auth_hash['info']['name'] + user.email = auth_hash['info']['email'] + #raise to get info for auth hash + return user + end +end diff --git a/app/views/homepages/_navigation_links.html.erb b/app/views/homepages/_navigation_links.html.erb new file mode 100644 index 0000000000..e94dab7593 --- /dev/null +++ b/app/views/homepages/_navigation_links.html.erb @@ -0,0 +1,9 @@ + diff --git a/app/views/homepages/create.html.erb b/app/views/homepages/create.html.erb new file mode 100644 index 0000000000..12e275a63e --- /dev/null +++ b/app/views/homepages/create.html.erb @@ -0,0 +1,2 @@ +

Homepages#create

+

Find me in app/views/homepages/create.html.erb

diff --git a/app/views/homepages/destroy.html.erb b/app/views/homepages/destroy.html.erb new file mode 100644 index 0000000000..59e0285e7e --- /dev/null +++ b/app/views/homepages/destroy.html.erb @@ -0,0 +1,2 @@ +

Homepages#destroy

+

Find me in app/views/homepages/destroy.html.erb

diff --git a/app/views/homepages/edit.html.erb b/app/views/homepages/edit.html.erb new file mode 100644 index 0000000000..d05072e7e6 --- /dev/null +++ b/app/views/homepages/edit.html.erb @@ -0,0 +1,2 @@ +

Homepages#edit

+

Find me in app/views/homepages/edit.html.erb

diff --git a/app/views/homepages/index.html.erb b/app/views/homepages/index.html.erb new file mode 100644 index 0000000000..1189f14594 --- /dev/null +++ b/app/views/homepages/index.html.erb @@ -0,0 +1,42 @@ + +
+ +
+

Shop by Category

+ <% @product_categories.each do |product_category| %> +
+ +
    + +
  • + <%= link_to(image_tag(Product.random_photo(product_category), :class=>'product_photo'), image_path(show_category_path(product_category))) %> +
  • +
  • <%= link_to product_category, show_category_path(product_category) %>
  • + +
+
+ <% end %> + +
+ +
+

<%= link_to "Browse All Collections", index_products_path%>

+
+ +
+ <%= image_tag("Homepage/Vampire1.jpg", alt: "Awesome black vampire woman wearing gold jewelry", class: "frontpage") %> +
+ + + + +
+ <%= render partial: 'layouts/greeting' %> +

Find Your Product

+ <%= form_tag(search_products_path(), :method => "get") do %> + <%= search_field_tag("query", nil, :placeholder => "search")%> + <%= submit_tag "Submit", :name => nil %> + <% end %> +
+ +
diff --git a/app/views/homepages/new.html.erb b/app/views/homepages/new.html.erb new file mode 100644 index 0000000000..0ad26144e4 --- /dev/null +++ b/app/views/homepages/new.html.erb @@ -0,0 +1,2 @@ +

Homepages#new

+

Find me in app/views/homepages/new.html.erb

diff --git a/app/views/homepages/show_category.html.erb b/app/views/homepages/show_category.html.erb new file mode 100644 index 0000000000..8eef212234 --- /dev/null +++ b/app/views/homepages/show_category.html.erb @@ -0,0 +1,24 @@ +
+
+ +

<%= @product_category %>

+ + <% @products_in_category.each do |product| %> + +
+
    +
    + +
  • <%= link_to product.name, show_products_path(product.id) %>
  • + +
  • $<%= product.price %>
  • + +
  • <%= link_to image_tag(product.photo_url, :class => 'product_photo'), show_products_path(product.id) %>
  • + +
    +
+
+ + <% end %> +
+
diff --git a/app/views/homepages/update.html.erb b/app/views/homepages/update.html.erb new file mode 100644 index 0000000000..4cdb5ddd2f --- /dev/null +++ b/app/views/homepages/update.html.erb @@ -0,0 +1,2 @@ +

Homepages#update

+

Find me in app/views/homepages/update.html.erb

diff --git a/app/views/layouts/_greeting.html.erb b/app/views/layouts/_greeting.html.erb new file mode 100644 index 0000000000..454b77f426 --- /dev/null +++ b/app/views/layouts/_greeting.html.erb @@ -0,0 +1,7 @@ +
+ <% if current_user %> +

Welcome back, <%= current_user.name %>!

+ <% else %> +

Welcome to Vampazon!

+ <% end %> +
diff --git a/app/views/layouts/_messages.html.erb b/app/views/layouts/_messages.html.erb new file mode 100644 index 0000000000..82303abd01 --- /dev/null +++ b/app/views/layouts/_messages.html.erb @@ -0,0 +1,8 @@ +<%# Rails flash messages styled for Zurb Foundation %> +<% flash.each do |name, msg| %> + <% if msg.is_a?(String) %> +
+ <%= content_tag :div, msg %> +
+ <% end %> +<% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9b70e01c2e..7c514067dd 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,14 +1,32 @@ - - - - Betsy - <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> - <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> - <%= csrf_meta_tags %> - - - -<%= yield %> - - + + + + + + + + <%= favicon_link_tag 'vamp_favicon.ico' %> + Vampazon + <%= stylesheet_link_tag "application.css"%> + + + +
+ <%= image_tag("Homepage/Vampazon.png", alt: "Vampazon Home", class: "logo") %> + + +
+ + + <%= render 'layouts/messages' %> + + <%= yield %> + + + diff --git a/app/views/orders/_checkout_form.html.erb b/app/views/orders/_checkout_form.html.erb new file mode 100644 index 0000000000..432825e94c --- /dev/null +++ b/app/views/orders/_checkout_form.html.erb @@ -0,0 +1,67 @@ +<%= form_for @order, url: create_order_path do |f| %> +
+ +

Shipping Address:

+ +
+ <%= f.label "Name: " %> + <%= f.text_field :name, "Name" => nil, :required => true %> +
+ +
+ <%= f.label "Email: " %> + <%= f.text_field :email, "Email" => nil, :required => true %> +
+ +
+ <%= f.label "Street Address: " %> + <%= f.text_field :street_address, "Street Address" => nil, :required => true %> +
+ +
+ <%= f.label "City: " %> + <%= f.text_field :city, "City" => nil, :required => true %> +
+ +
+ <%= f.label "State: " %> + <%= f.text_field :state, "State" => nil, :required => true %> +
+ +
+ <%= f.label "Zip: " %> + <%= f.text_field :zip, "Zip" => nil, :required => true %> +
+ +
+ <%= f.label "Phone: " %> + <%= f.text_field :phone, "Phone" => nil, :required => false %> +
+ +

Payment Information:

+ +
+ <%= f.label "Credit Card: " %> + <%= f.text_field :cc_number, "Credit Card" => nil, :required => true %> +
+ +
+ <%= f.label "Expiration Month: " %> + <%= f.text_field :exp_month, "Expiration Month" => nil, :required => true %> +
+ +
+ <%= f.label "Expiration Year: " %> + <%= f.text_field :exp_year, "Expiration Year" => nil, :required => true %> +
+ +
+ <%= f.label "CVC: " %> + <%= f.text_field :cvc, "CVC" => nil, :required => true %> +
+ + <%= hidden_field_tag(:order_id, @order.id) %> + <%= f.submit "Confirm Payment", class: 'button '%> + +
+<% end %> diff --git a/app/views/orders/checkout.html.erb b/app/views/orders/checkout.html.erb new file mode 100644 index 0000000000..ae9f6dc3d4 --- /dev/null +++ b/app/views/orders/checkout.html.erb @@ -0,0 +1,18 @@ +
+ +

Checkout

+ + <% @order_items.each do |order_item| %> + +

<%= link_to "#{order_item.product.name}", show_products_path(order_item.product.id)%>

+

$<%= order_item.unit_price %>

+

Qty: <%= order_item.quantity %>

+ + <% end %> + +

Cart subtotal:$<%= @order.total_price %>

+ + <%= render partial: "checkout_form", locals: {action_name: "patch"} %> + + <%= link_to "Back to Cart", show_cart_path, :method => :get, :class => "button" %> +
diff --git a/app/views/orders/confirmation.html.erb b/app/views/orders/confirmation.html.erb new file mode 100644 index 0000000000..f7003db4bc --- /dev/null +++ b/app/views/orders/confirmation.html.erb @@ -0,0 +1,28 @@ +
+ +

Thank you for shopping with us!

+ +

Order Details:

+

Order#: <%= @order.id %>

+

Order Status: <%= @order.status %>

+

Purchased at: <%= @order.created_at %>

+ + <% @order.order_items.each do |order_item| %> + <%= order_item.product.name %> + unit price:<%= order_item.unit_price %> + Qty: <%= order_item.quantity %> + $<%= order_item.total_price %> + <% end %> +

Order Subtotal:$<%= @order.total_price %>

+ +

Shipping address:

+

Name:<%= @order.name %>

+

Email:<%= @order.email %>

+

Street Address:<%= @order.street_address %>

+

City:<%= @order.city %>

+

State:<%= @order.state %>

+

Zip:<%= @order.zip %>

+

Phone:<%= @order.phone %>

+ + <%= link_to "Continue Shopping", root_path, :method => :get, :class => "button" %> +
diff --git a/app/views/orders/create.html.erb b/app/views/orders/create.html.erb new file mode 100644 index 0000000000..295bd84094 --- /dev/null +++ b/app/views/orders/create.html.erb @@ -0,0 +1,2 @@ +

Orders#create

+

Find me in app/views/orders/create.html.erb

diff --git a/app/views/orders/create_order.html.erb b/app/views/orders/create_order.html.erb new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/app/views/orders/create_order.html.erb @@ -0,0 +1 @@ + diff --git a/app/views/orders/destroy.html.erb b/app/views/orders/destroy.html.erb new file mode 100644 index 0000000000..d14d0a3508 --- /dev/null +++ b/app/views/orders/destroy.html.erb @@ -0,0 +1,2 @@ +

Orders#destroy

+

Find me in app/views/orders/destroy.html.erb

diff --git a/app/views/orders/edit.html.erb b/app/views/orders/edit.html.erb new file mode 100644 index 0000000000..7de9049bee --- /dev/null +++ b/app/views/orders/edit.html.erb @@ -0,0 +1,2 @@ +

Orders#edit

+

Find me in app/views/orders/edit.html.erb

diff --git a/app/views/orders/index.html.erb b/app/views/orders/index.html.erb new file mode 100644 index 0000000000..731de654bc --- /dev/null +++ b/app/views/orders/index.html.erb @@ -0,0 +1,49 @@ +
+

ORDER PAGE

+ + +

CONTENTS OF ORDER

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ItemQuantityPrice
Coffin14.99
Cape420.99
Minion213.26
+
+ + diff --git a/app/views/orders/new.html.erb b/app/views/orders/new.html.erb new file mode 100644 index 0000000000..1bc27609ce --- /dev/null +++ b/app/views/orders/new.html.erb @@ -0,0 +1,2 @@ +

Orders#new

+

Find me in app/views/orders/new.html.erb

diff --git a/app/views/orders/show.html.erb b/app/views/orders/show.html.erb new file mode 100644 index 0000000000..22eb495f6f --- /dev/null +++ b/app/views/orders/show.html.erb @@ -0,0 +1,2 @@ +

Orders#show

+

Find me in app/views/orders/show.html.erb

diff --git a/app/views/orders/show_cart.html.erb b/app/views/orders/show_cart.html.erb new file mode 100644 index 0000000000..df98b7a51a --- /dev/null +++ b/app/views/orders/show_cart.html.erb @@ -0,0 +1,28 @@ +
+ +

Cart Details:

+ + <% @order_items.each do |order_item| %> + +

<%= link_to "#{order_item.product.name}", show_products_path(order_item.product.id)%>

+

$<%= order_item.unit_price %>

+ + <%= form_tag(change_quantity_path, method: :post) do %> + <%= label_tag :quantity %> + <%= select_tag :quantity, options_for_select((1..order_item.product.inventory), order_item.quantity) %> + <%= hidden_field_tag(:order_item_id, order_item.id) %> + <%= submit_tag "Update Quantity", class: 'button' %> + + <% end %> + + <%= form_tag(destroy_order_item_path, method: :delete) do %> + <%= hidden_field_tag(:order_item_id, order_item.id) %> + <%= submit_tag "Delete", :class => "button" %> + <% end %> + + <% end %> + +

Cart Subtotal: $<%= @order.total_price %>

+ <%= link_to "Continue Shopping", root_path, :method => :get, :class => "button" %> + <%= link_to "Checkout", checkout_path, :method => :get, :class => "button" %> +
diff --git a/app/views/orders/update.html.erb b/app/views/orders/update.html.erb new file mode 100644 index 0000000000..21caac1f70 --- /dev/null +++ b/app/views/orders/update.html.erb @@ -0,0 +1,2 @@ +

Orders#update

+

Find me in app/views/orders/update.html.erb

diff --git a/app/views/products/_form.html.erb b/app/views/products/_form.html.erb new file mode 100644 index 0000000000..ff47627bac --- /dev/null +++ b/app/views/products/_form.html.erb @@ -0,0 +1,36 @@ +
+
+ <%= form_for @product, method: @post_method, url: @post_path do |f| %> + +
+ <%= f.label "Product Name: " %> + <%= f.text_field :name, "Product Name" => nil, :required => true %> +
+ +
+ <%= f.label "Description: " %> + <%= f.text_field :description, "Description" => nil, :required => true %> +
+ +
+ <%= f.label "Price: " %> + <%= f.number_field :price, step: 0.01, "Price" => nil, :required => true %> +
+ +
+ <%= f.label "Inventory: " %> + <%= f.number_field :inventory, step: 1, "Inventory" => nil, :required => true %> +
+ +
+ <%= f.label "Category: " %> + <%= f.select :category, Product.uniq.pluck(:category), "Category" => nil, :required => true %> +
+ + <%= f.submit "Submit", class: 'button' %> + <% end %> + + <%=link_to "Cancel", root_path, class: "button alert" %> + +
+
diff --git a/app/views/products/create.html.erb b/app/views/products/create.html.erb new file mode 100644 index 0000000000..cb7dba3e46 --- /dev/null +++ b/app/views/products/create.html.erb @@ -0,0 +1 @@ +<%# params %> diff --git a/app/views/products/destroy.html.erb b/app/views/products/destroy.html.erb new file mode 100644 index 0000000000..d5c678b499 --- /dev/null +++ b/app/views/products/destroy.html.erb @@ -0,0 +1,2 @@ +

Products#destroy

+

Find me in app/views/products/destroy.html.erb

diff --git a/app/views/products/edit.html.erb b/app/views/products/edit.html.erb new file mode 100644 index 0000000000..eb3d0abe21 --- /dev/null +++ b/app/views/products/edit.html.erb @@ -0,0 +1 @@ +<%= render partial: 'form' %> \ No newline at end of file diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb new file mode 100644 index 0000000000..b950ce2e6b --- /dev/null +++ b/app/views/products/index.html.erb @@ -0,0 +1,30 @@ +
+
+ +

All Collections

+ + <% if @products.empty? %> + <%= image_tag "count_zero.jpg" %> + + <% else %> + <% @products.each do |product| %> + +
+
    +
    + +
  • <%= link_to product.name, show_products_path(product.id) %>
  • + +
  • <%= product.price %>
  • + +
  • <%= link_to image_tag(product.photo_url, class: 'product_photo'), show_products_path(product.id) %>
  • + +
    +
+
+ + <% end %> + <% end %> + +
+
diff --git a/app/views/products/new.html.erb b/app/views/products/new.html.erb new file mode 100644 index 0000000000..19a2cba60c --- /dev/null +++ b/app/views/products/new.html.erb @@ -0,0 +1,6 @@ +
+ <% if session[:user_id] != nil %> +

Post a New Product

+ <%= render partial: "form", locals: {action_name: "create"}%> + <% end %> +
diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb new file mode 100644 index 0000000000..2c32f48493 --- /dev/null +++ b/app/views/products/show.html.erb @@ -0,0 +1,54 @@ +
+
+ <%= image_tag(@product.photo_url) %> +
+ +
+
+

<%= @product.name %>

+ +

<%= @product.description %>

+

Price: $<%= @product.price %>

+

In-stock: <%= @product.inventory %>

+

Category: <%= @product.category %>

+ +

Seller: <%= link_to @seller.name, show_seller_products_path %>

+ <%= button_to("Other Items by this Seller", show_seller_products_path(@product.id), method: :get, class: 'button') %> + +

Average rating: <%= @product.average_rating %>

+

Review:

+ <% @reviews.each do |review| %> +

<%= review.description %>

+ <% end %> + +
+ <%= form_tag(add_to_cart_path, method: :post) do %> + <%= label_tag :quantity %> + <%= select_tag :quantity, options_for_select((1..@product.inventory), 1) %> + <%= hidden_field_tag(:product_id, @product.id) %> + <%= submit_tag "Add to Cart", class: 'button' %> + <% end %> +
+
+ + + + <%= button_to("Review Product",new_reviews_path(@product.id), action: :new, method: :get, class: 'button')%> + + <%if @product.user_id == session[:user_id]%> + + + + <%= button_to("Edit: #{@product.name}",edit_products_path(@product.id), action: :edit, method: :get, class: 'button')%> + + + + <%=button_to "delete", destroy_products_path(@product.id), action: :destroy, method: :delete, class: 'button alert' %> + + <% end %> + + +
+ + +
diff --git a/app/views/products/show_seller_products.html.erb b/app/views/products/show_seller_products.html.erb new file mode 100644 index 0000000000..e050fdf8dc --- /dev/null +++ b/app/views/products/show_seller_products.html.erb @@ -0,0 +1,24 @@ +
+
+ +

Collections by this Seller:

+ + <% @products.each do |product| %> + +
+
    +
    + +
  • <%= link_to product.name, show_products_path(product.id) %>
  • + +
  • <%= "$#{product.price}" %>
  • + +
  • <%= link_to image_tag(product.photo_url, :class => "product_photo"), show_products_path(product.id) %>
  • + +
    +
+
+ + <% end %> +
+
diff --git a/app/views/products/update.html.erb b/app/views/products/update.html.erb new file mode 100644 index 0000000000..039889ac02 --- /dev/null +++ b/app/views/products/update.html.erb @@ -0,0 +1,2 @@ +

Products#update

+

Find me in app/views/products/update.html.erb

diff --git a/app/views/reviews/create.html.erb b/app/views/reviews/create.html.erb new file mode 100644 index 0000000000..44bf11c2ed --- /dev/null +++ b/app/views/reviews/create.html.erb @@ -0,0 +1,2 @@ +

Reviews#create

+

Find me in app/views/reviews/create.html.erb

diff --git a/app/views/reviews/destroy.html.erb b/app/views/reviews/destroy.html.erb new file mode 100644 index 0000000000..df58c59d5c --- /dev/null +++ b/app/views/reviews/destroy.html.erb @@ -0,0 +1,2 @@ +

Reviews#destroy

+

Find me in app/views/reviews/destroy.html.erb

diff --git a/app/views/reviews/edit.html.erb b/app/views/reviews/edit.html.erb new file mode 100644 index 0000000000..28034f5e02 --- /dev/null +++ b/app/views/reviews/edit.html.erb @@ -0,0 +1,2 @@ +

Reviews#edit

+

Find me in app/views/reviews/edit.html.erb

diff --git a/app/views/reviews/index.html.erb b/app/views/reviews/index.html.erb new file mode 100644 index 0000000000..d19455779d --- /dev/null +++ b/app/views/reviews/index.html.erb @@ -0,0 +1,2 @@ +

Reviews#index

+

Find me in app/views/reviews/index.html.erb

diff --git a/app/views/reviews/new.html.erb b/app/views/reviews/new.html.erb new file mode 100644 index 0000000000..ce91637e5e --- /dev/null +++ b/app/views/reviews/new.html.erb @@ -0,0 +1,17 @@ +

Product Review for <%= "#{@product.name}"%>

+ +

Tell us what you think!

+ +<%=form_for @review, method: :post, url: 'create' do |f| %> + +<%= f.label :rank%> +<%= f.select :rank, [['5'],['4'],['3'], ['2'],['1']]%> + +<%= f.label :description%> +<%= f.text_field :description%> + +<%= f.submit %> + + + +<% end %> diff --git a/app/views/reviews/show.html.erb b/app/views/reviews/show.html.erb new file mode 100644 index 0000000000..68d8d94c3b --- /dev/null +++ b/app/views/reviews/show.html.erb @@ -0,0 +1,2 @@ +

Reviews#show

+

Find me in app/views/reviews/show.html.erb

diff --git a/app/views/reviews/update.html.erb b/app/views/reviews/update.html.erb new file mode 100644 index 0000000000..7d46cbed5c --- /dev/null +++ b/app/views/reviews/update.html.erb @@ -0,0 +1,2 @@ +

Reviews#update

+

Find me in app/views/reviews/update.html.erb

diff --git a/app/views/sessions/create.html.erb b/app/views/sessions/create.html.erb new file mode 100644 index 0000000000..c251174fea --- /dev/null +++ b/app/views/sessions/create.html.erb @@ -0,0 +1,2 @@ +

Sessions#create

+

Find me in app/views/sessions/create.html.erb

diff --git a/app/views/sessions/destroy.html.erb b/app/views/sessions/destroy.html.erb new file mode 100644 index 0000000000..d75237d982 --- /dev/null +++ b/app/views/sessions/destroy.html.erb @@ -0,0 +1,2 @@ +

Sessions#destroy

+

Find me in app/views/sessions/destroy.html.erb

diff --git a/app/views/sessions/edit.html.erb b/app/views/sessions/edit.html.erb new file mode 100644 index 0000000000..071265e062 --- /dev/null +++ b/app/views/sessions/edit.html.erb @@ -0,0 +1,2 @@ +

Sessions#edit

+

Find me in app/views/sessions/edit.html.erb

diff --git a/app/views/sessions/index.html.erb b/app/views/sessions/index.html.erb new file mode 100644 index 0000000000..62cbf379e3 --- /dev/null +++ b/app/views/sessions/index.html.erb @@ -0,0 +1,2 @@ +

Sessions#index

+

Find me in app/views/sessions/index.html.erb

diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000000..5b65f9f780 --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,7 @@ +

New Session

+ +<%= simple_form_for :login, {url: sessions_path } do |f| %> + <%= f.input :email %> + <%= f.input :password %> + <%= f.button :submit %> +<% end %> diff --git a/app/views/sessions/show.html.erb b/app/views/sessions/show.html.erb new file mode 100644 index 0000000000..1225c86bfd --- /dev/null +++ b/app/views/sessions/show.html.erb @@ -0,0 +1,2 @@ +

Sessions#show

+

Find me in app/views/sessions/show.html.erb

diff --git a/app/views/sessions/update.html.erb b/app/views/sessions/update.html.erb new file mode 100644 index 0000000000..057db622ad --- /dev/null +++ b/app/views/sessions/update.html.erb @@ -0,0 +1,2 @@ +

Sessions#update

+

Find me in app/views/sessions/update.html.erb

diff --git a/app/views/users/buyer_manage.html.erb b/app/views/users/buyer_manage.html.erb new file mode 100644 index 0000000000..a54143f4b5 --- /dev/null +++ b/app/views/users/buyer_manage.html.erb @@ -0,0 +1,27 @@ +
+ +

<%= @user.name %>'s Account

+

User id: <%= @user.id %>

+

User Name: <%= @user.name %>

+

Email: <%= @user.email %>

+ +

Buyer Management

+ +

My Orders:

+ <%= link_to "All", show_orders_by_status_path('all'), :class => "button" %> + <%= link_to "Pending", show_orders_by_status_path('pending'), :class => "button" %> + <%= link_to "Paid", show_orders_by_status_path('paid'), :class => "button" %> + <%= link_to "Completed", show_orders_by_status_path('completed'), :class => "button" %> + <%= link_to "Cancelled", show_orders_by_status_path('cancelled'), :class => "button alert" %> + + <% @orders.each do |order| %> + +

Order#: <%= link_to "#{order.id}", confirmation_path(order.id) %>

+

Creation: <%= order.created_at %>

+

$<%= order.total_price %>

+

<%= order.status %>

+

<%= link_to "Cancel", cancel_order_path(order.id), :method => :patch, :class => "button alert" %>

+ + <% end %> + +
diff --git a/app/views/users/create.html.erb b/app/views/users/create.html.erb new file mode 100644 index 0000000000..48ea02e600 --- /dev/null +++ b/app/views/users/create.html.erb @@ -0,0 +1,2 @@ +

Users#create

+

Find me in app/views/users/create.html.erb

diff --git a/app/views/users/destroy.html.erb b/app/views/users/destroy.html.erb new file mode 100644 index 0000000000..de4bd26343 --- /dev/null +++ b/app/views/users/destroy.html.erb @@ -0,0 +1,2 @@ +

Users#destroy

+

Find me in app/views/users/destroy.html.erb

diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 0000000000..1881fbdba0 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,2 @@ +

Users#edit

+

Find me in app/views/users/edit.html.erb

diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 0000000000..51968c88d2 --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,2 @@ +

Users#index

+

Find me in app/views/users/index.html.erb

diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000000..a69fd8c385 --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,8 @@ +

New User

+ +<%= simple_form_for @my_user do |f| %> + <%= f.input :email %> + <%= f.input :password %> + <%= f.input :password_confirmation %> + <%= f.button :submit %> +<% end %> \ No newline at end of file diff --git a/app/views/users/order_by_seller.html.erb b/app/views/users/order_by_seller.html.erb new file mode 100644 index 0000000000..d7a6d14a68 --- /dev/null +++ b/app/views/users/order_by_seller.html.erb @@ -0,0 +1,16 @@ +
+ +

Order Details

+

Buyer: <%= @order.user.name %>

+

Email: <%= @order.email %>

+

Shipping Address: <%= @order.street_address %>

+

<%= @order.city %>, <%= @order.state %> <%= @order.zip %>

+ <% if @order.phone %> +

Phone:<%= @order.phone %>

+ <% end %> +

Last 4 digits of credit card#: <%= @order.cc_number.to_s[-4..-1].to_i %>

+

Credit card expiration date: <%= @order.exp_month %>-<%= @order.exp_year %>

+ + <%= link_to "Return to Seller Management", seller_manage_path, :class => "button" %> + +
diff --git a/app/views/users/seller_manage.html.erb b/app/views/users/seller_manage.html.erb new file mode 100644 index 0000000000..b988de69d3 --- /dev/null +++ b/app/views/users/seller_manage.html.erb @@ -0,0 +1,46 @@ +
+ +

<%= @user.name %>'s Account

+

User ID: <%= @user.id %>

+

User Name: <%= @user.name %>

+

Email: <%= @user.email %>

+ +

Seller Management

+ +

Summary

+ +

Total Order Item Count (Paid and Fulfilled): <%= @total_count %>

+

Total Revenue: $<%= @total_revenue %>

+

Paid Order Item Count: <%= @paid_count %>

+

Paid Revenue: $<%= @paid_revenue %>

+

Fulfilled Order Item Count: <%= @fulfilled_count %>

+

Fulfilled Revenue: $<%= @fulfilled_revenue %>

+

Cancelled Order Item Count: <%= @cancelled_count %>

+

Cancelled Revenue: $<%= @cancelled_revenue %>

+ +

Order Item listings:

+ <%= link_to "All", seller_manage_path, :class => "button" %> + <%= link_to "Pending", get_order_by_status_path('pending'), :class => "button" %> + <%= link_to "Paid", get_order_by_status_path('paid'), :class => "button" %> + <%= link_to "Fulfilled", get_order_by_status_path('fulfilled'), :class => "button" %> + <%= link_to "Cancelled", get_order_by_status_path('cancelled'), :class => "button alert" %> + + <% @order_items.each do |order_item| %> +

Order Item#: <%= link_to "#{order_item.product.name}", show_products_path(order_item.product.id) %>

+

Creation: <%= order_item.created_at %>

+

$<%= order_item.total_price %>

+

<%= order_item.status %>

+ + + <% if order_item.status == "paid" %> + <%= form_tag(ship_order_item_path, method: :patch) do %> + <%= hidden_field_tag(:order_item_id, order_item.id) %> +

<%= submit_tag "Ship", :class => "button" %>

+ <% end %> + <% end %> + +

Order#: <%= link_to "#{order_item.order_id}", order_by_seller_path(order_item.order_id) %>

+ + <% end %> + +
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000000..e5fa3adf14 --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,2 @@ +

Users#show

+

Find me in app/views/users/show.html.erb

diff --git a/app/views/users/update.html.erb b/app/views/users/update.html.erb new file mode 100644 index 0000000000..cabbde176a --- /dev/null +++ b/app/views/users/update.html.erb @@ -0,0 +1,2 @@ +

Users#update

+

Find me in app/views/users/update.html.erb

diff --git a/app/views/users/user_account.html.erb b/app/views/users/user_account.html.erb new file mode 100644 index 0000000000..61066ba2e9 --- /dev/null +++ b/app/views/users/user_account.html.erb @@ -0,0 +1,14 @@ +
+ +

<%= @user.name %>'s Account

+

User id: <%= @user.id %>

+

User Name: <%= @user.name %>

+

Email: <%= @user.email %>

+ + <%= link_to "Buyer Management", buyer_manage_path, :class => "button" %> + <%= link_to "Seller Management", seller_manage_path, :class => "button" %> + + + <%= button_to "Create New Product", new_products_path, method: :get, :class => 'button' %> + +
diff --git a/config/application.rb b/config/application.rb index c5736a7c53..cdbabe01ee 100644 --- a/config/application.rb +++ b/config/application.rb @@ -6,6 +6,9 @@ # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) +# config/application.rb +# config.assets.initialize_on_precompile = false + module Betsy class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. @@ -22,5 +25,6 @@ class Application < Rails::Application # Do not swallow errors in after_commit/after_rollback callbacks. config.active_record.raise_in_transactional_callbacks = true + end end diff --git a/config/database.yml b/config/database.yml index 04f24be2ba..770465bc7e 100644 --- a/config/database.yml +++ b/config/database.yml @@ -15,7 +15,7 @@ # gem 'pg' # default: &default - adapter: postgresql + adapter: sqlite3 encoding: unicode # For details on connection pooling, see rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 0000000000..6aee15b9ef --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,3 @@ +# config.omniauth :github, "4fa0e3e1a1c088c7fba0", "0644062e493cedc8b257f39abdfd768c653b5983" +# +# config.omniauth :github, "4fa0e3e1a1c088c7fba0", "0644062e493cedc8b257f39abdfd768c653b5983", callback_url: "http://localhost:3000/auth/github/callback" diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 0000000000..36073da138 --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,4 @@ +Rails.application.config.middleware.use OmniAuth::Builder do + # binding.pry + provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email" +end \ No newline at end of file diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb new file mode 100644 index 0000000000..934487af6a --- /dev/null +++ b/config/initializers/simple_form.rb @@ -0,0 +1,165 @@ +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + # Wrappers are used by the form builder to generate a + # complete input. You can remove any component from the + # wrapper, change the order or even add your own to the + # stack. The options given below are used to wrap the + # whole input. + config.wrappers :default, class: :input, + hint_class: :field_with_hint, error_class: :field_with_errors do |b| + ## Extensions enabled by default + # Any of these extensions can be disabled for a + # given input by passing: `f.input EXTENSION_NAME => false`. + # You can make any of these extensions optional by + # renaming `b.use` to `b.optional`. + + # Determines whether to use HTML5 (:email, :url, ...) + # and required attributes + b.use :html5 + + # Calculates placeholders automatically from I18n + # You can also pass a string as f.input placeholder: "Placeholder" + b.use :placeholder + + ## Optional extensions + # They are disabled unless you pass `f.input EXTENSION_NAME => true` + # to the input. If so, they will retrieve the values from the model + # if any exists. If you want to enable any of those + # extensions by default, you can change `b.optional` to `b.use`. + + # Calculates maxlength from length validations for string inputs + b.optional :maxlength + + # Calculates pattern from format validations for string inputs + b.optional :pattern + + # Calculates min and max from length validations for numeric inputs + b.optional :min_max + + # Calculates readonly automatically from readonly attributes + b.optional :readonly + + ## Inputs + b.use :label_input + b.use :hint, wrap_with: { tag: :span, class: :hint } + b.use :error, wrap_with: { tag: :span, class: :error } + + ## full_messages_for + # If you want to display the full error message for the attribute, you can + # use the component :full_error, like: + # + # b.use :full_error, wrap_with: { tag: :span, class: :error } + end + + # The default wrapper to be used by the FormBuilder. + config.default_wrapper = :default + + # Define the way to render check boxes / radio buttons with labels. + # Defaults to :nested for bootstrap config. + # inline: input + label + # nested: label > input + config.boolean_style = :nested + + # Default class for buttons + config.button_class = 'btn' + + # Method used to tidy up errors. Specify any Rails Array method. + # :first lists the first message for each field. + # Use :to_sentence to list all errors for each field. + # config.error_method = :first + + # Default tag used for error notification helper. + config.error_notification_tag = :div + + # CSS class to add for error notification helper. + config.error_notification_class = 'error_notification' + + # ID to add for error notification helper. + # config.error_notification_id = nil + + # Series of attempts to detect a default label method for collection. + # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] + + # Series of attempts to detect a default value method for collection. + # config.collection_value_methods = [ :id, :to_s ] + + # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. + # config.collection_wrapper_tag = nil + + # You can define the class to use on all collection wrappers. Defaulting to none. + # config.collection_wrapper_class = nil + + # You can wrap each item in a collection of radio/check boxes with a tag, + # defaulting to :span. + # config.item_wrapper_tag = :span + + # You can define a class to use in all item wrappers. Defaulting to none. + # config.item_wrapper_class = nil + + # How the label text should be generated altogether with the required text. + # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } + + # You can define the class to use on all labels. Default is nil. + # config.label_class = nil + + # You can define the default class to be used on forms. Can be overriden + # with `html: { :class }`. Defaulting to none. + # config.default_form_class = nil + + # You can define which elements should obtain additional classes + # config.generate_additional_classes_for = [:wrapper, :label, :input] + + # Whether attributes are required by default (or not). Default is true. + # config.required_by_default = true + + # Tell browsers whether to use the native HTML5 validations (novalidate form option). + # These validations are enabled in SimpleForm's internal config but disabled by default + # in this configuration, which is recommended due to some quirks from different browsers. + # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, + # change this configuration to true. + config.browser_validations = false + + # Collection of methods to detect if a file type was given. + # config.file_methods = [ :mounted_as, :file?, :public_filename ] + + # Custom mappings for input types. This should be a hash containing a regexp + # to match as key, and the input type that will be used when the field name + # matches the regexp as value. + # config.input_mappings = { /count/ => :integer } + + # Custom wrappers for input types. This should be a hash containing an input + # type as key and the wrapper that will be used for all inputs with specified type. + # config.wrapper_mappings = { string: :prepend } + + # Namespaces where SimpleForm should look for custom input classes that + # override default inputs. + # config.custom_inputs_namespaces << "CustomInputs" + + # Default priority for time_zone inputs. + # config.time_zone_priority = nil + + # Default priority for country inputs. + # config.country_priority = nil + + # When false, do not use translations for labels. + # config.translate_labels = true + + # Automatically discover new inputs in Rails' autoload path. + # config.inputs_discovery = true + + # Cache SimpleForm inputs discovery + # config.cache_discovery = !Rails.env.development? + + # Default class for inputs + # config.input_class = nil + + # Define the default class of the input wrapper of the boolean input. + config.boolean_label_class = 'checkbox' + + # Defines if the default input wrapper class should be included in radio + # collection wrappers. + # config.include_default_input_wrapper_class = true + + # Defines which i18n scope will be used in Simple Form. + # config.i18n_scope = 'simple_form' +end diff --git a/config/initializers/simple_form_foundation.rb b/config/initializers/simple_form_foundation.rb new file mode 100644 index 0000000000..495ef35509 --- /dev/null +++ b/config/initializers/simple_form_foundation.rb @@ -0,0 +1,107 @@ +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| + # Don't forget to edit this file to adapt it to your needs (specially + # all the grid-related classes) + # + # Please note that hints are commented out by default since Foundation + # does't provide styles for hints. You will need to provide your own CSS styles for hints. + # Uncomment them to enable hints. + + config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error do |b| + b.use :html5 + b.use :placeholder + b.optional :maxlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + b.use :label_input + b.use :error, wrap_with: { tag: :small, class: :error } + + # b.use :hint, wrap_with: { tag: :span, class: :hint } + end + + config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error do |b| + b.use :html5 + b.use :placeholder + b.optional :maxlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + + b.wrapper :label_wrapper, tag: :div, class: 'small-3 columns' do |ba| + ba.use :label, class: 'right inline' + end + + b.wrapper :right_input_wrapper, tag: :div, class: 'small-9 columns' do |ba| + ba.use :input + ba.use :error, wrap_with: { tag: :small, class: :error } + # ba.use :hint, wrap_with: { tag: :span, class: :hint } + end + end + + config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'row' do |b| + b.use :html5 + b.optional :readonly + + b.wrapper :container_wrapper, tag: 'div', class: 'small-offset-3 small-9 columns' do |ba| + ba.wrapper :tag => 'label', :class => 'checkbox' do |bb| + bb.use :input + bb.use :label_text + end + + ba.use :error, wrap_with: { tag: :small, class: :error } + # ba.use :hint, wrap_with: { tag: :span, class: :hint } + end + end + + # Foundation does not provide a way to handle inline forms + # This wrapper can be used to create an inline form + # by hiding that labels on every screen sizes ('hidden-for-small-up'). + # + # Note that you need to adapt this wrapper to your needs. If you need a 4 + # columns form then change the wrapper class to 'small-3', if you need + # only two use 'small-6' and so on. + config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error do |b| + b.use :html5 + b.use :placeholder + b.optional :maxlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + + b.use :label, class: 'hidden-for-small-up' + b.use :input + + b.use :error, wrap_with: { tag: :small, class: :error } + # b.use :hint, wrap_with: { tag: :span, class: :hint } + end + + # Examples of use: + # - wrapper_html: {class: 'row'}, custom_wrapper_html: {class: 'column small-12'} + # - custom_wrapper_html: {class: 'column small-3 end'} + config.wrappers :customizable_wrapper, tag: 'div', error_class: :error do |b| + b.use :html5 + b.optional :readonly + + b.wrapper :custom_wrapper, tag: :div do |ba| + ba.use :label_input + end + + b.use :error, wrap_with: { tag: :small, class: :error } + # b.use :hint, wrap_with: { tag: :span, class: :hint } + end + + # CSS class for buttons + config.button_class = 'button' + + # Set this to div to make the checkbox and radio properly work + # otherwise simple_form adds a label tag instead of a div arround + # the nested label + config.item_wrapper_tag = :div + + # CSS class to add for error notification helper. + config.error_notification_class = 'alert-box alert' + + # The default wrapper to be used by the FormBuilder. + config.default_wrapper = :vertical_form +end diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml new file mode 100644 index 0000000000..2374383342 --- /dev/null +++ b/config/locales/simple_form.en.yml @@ -0,0 +1,31 @@ +en: + simple_form: + "yes": 'Yes' + "no": 'No' + required: + text: 'required' + mark: '*' + # You can uncomment the line below if you need to overwrite the whole required html. + # When using html, text and mark won't be used. + # html: '*' + error_notification: + default_message: "Please review the problems below:" + # Examples + # labels: + # defaults: + # password: 'Password' + # user: + # new: + # email: 'E-mail to sign in.' + # edit: + # email: 'E-mail.' + # hints: + # defaults: + # username: 'User name to sign in.' + # password: 'No special characters, please.' + # include_blanks: + # defaults: + # age: 'Rather not say' + # prompts: + # defaults: + # age: 'Select your age' diff --git a/config/routes.rb b/config/routes.rb index 3f66539d54..de6d373cc1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,56 +1,120 @@ Rails.application.routes.draw do - # The priority is based upon order of creation: first created -> highest priority. - # See how all your routes lay out with "rake routes". - # You can have the root of your site routed with "root" - # root 'welcome#index' + get 'reviews/index' => 'reviews#index', as: 'index_reviews' - # Example of regular route: - # get 'products/:id' => 'catalog#view' + get 'reviews/show/:id' => 'reviews#show', as: 'show_reviews' - # Example of named route that can be invoked with purchase_url(id: product.id) - # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase + get 'products/:id/reviews/new/' => 'reviews#new', as: 'new_reviews' - # Example resource route (maps HTTP verbs to controller actions automatically): - # resources :products + post 'products/:id/reviews/create' => 'reviews#create', as: 'create_reviews' - # Example resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end + get 'reviews/edit' + + get 'reviews/update' + + delete 'reviews/:id/destroy' => 'reviews#destroy', as: 'destroy_reviews' + +# we chose to make the convention of having the as: be action + plural. + + root to: 'homepages#index' + get 'homepages/index' => 'homepages#index', as: 'index' + + get 'homepages/:category/show_category' => 'homepages#show_category', as: 'show_category' + + # get 'homepages/new' => 'homepages#new', as: 'new_homepages' + # + # post 'homepages/create' => 'homepages#create', as: 'create_homepages' + # + # get 'homepages/edit' => 'homepages#edit', as: 'edit_homepages' # - # collection do - # get 'sold' - # end - # end - - # Example resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Example resource route with more complex sub-resources: - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', on: :collection - # end - # end - - # Example resource route with concerns: - # concern :toggleable do - # post 'toggle' - # end - # resources :posts, concerns: :toggleable - # resources :photos, concerns: :toggleable - - # Example resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end + # patch 'homepages/update' => 'homepages#update', as: 'update_homepages' + # + # delete 'homepages/destroy' => 'homepages#destroy', as: 'destroy_homepages' + + #============== Users ================== + + resources :users + + get 'user_account' => 'users#user_account', as: 'user_account' + + get 'buyer_manage' => 'users#buyer_manage', as: 'buyer_manage' + + get 'seller_manage' => 'users#seller_manage', as: 'seller_manage' + + get 'orders_by_status/:status/' => 'users#show_orders_by_status', as: 'show_orders_by_status' + + get 'get_order_by_status/:status/' => 'users#get_order_by_status', as: 'get_order_by_status' + + patch 'ship_order_item' => 'users#ship_order_item', as: 'ship_order_item' + + get 'order_by_seller/:order_id' => 'users#order_by_seller', as: 'order_by_seller' + + #============== Products ================== + + get 'products/index' => 'products#index', as: 'index_products' + + get 'products/:id/show_seller_products' => 'products#show_seller_products', as: 'show_seller_products' + + get 'products/show/:id' => 'products#show', as: 'show_products' + + get 'products/new' => 'products#new', as: 'new_products' + + post 'products/create' => 'products#create', as: 'create_products' + + get 'products/:id/edit' => 'products#edit', as: 'edit_products' + + patch 'products/:id/update' => 'products#update', as: 'update_products' + + delete 'products/:id/destroy' => 'products#destroy', as: 'destroy_products' + + get 'products/search' => 'products#search', as: 'search_products' + + + + + #============== Sessions ================== + + # get 'login' => 'sessions#new' + get 'logout' => 'sessions#destroy' + + get "/auth/:provider/callback" => "sessions#create" + + + # delete 'sessions/:id/destroy' => 'sessions#destroy', as: 'destroy_sessions' + + resources :sessions + + #============== Orders ================== + + + post 'cart/add_to_cart' => 'orders#add_to_cart', as: 'add_to_cart' + + get 'cart' => 'orders#show_cart', as: 'show_cart' + + post 'order_item/change_quantity' => 'orders#change_quantity', as: 'change_quantity' + + delete 'order_item/delete' => 'orders#destroy_order_item', as: 'destroy_order_item' + + get 'checkout' => 'orders#checkout', as: 'checkout' + + patch 'orders/create' => 'orders#create_order', as: 'create_order' + + get 'orders/:order_id/confirmation' => 'orders#confirmation', as: 'confirmation' + + patch 'orders/:order_id/cancel' => 'orders#cancel_order', as: 'cancel_order' + + + get 'orders/index' => 'orders#index', as: 'index_orders' + + get 'orders/show/:id' => 'orders#show', as: 'show_orders' + + get 'orders/new' => 'orders#new', as: 'new_orders' + + + get 'orders/:id/edit' => 'orders#edit', as: 'edit_orders' + + patch 'orders/:id/update' => 'orders#update', as: 'update_orders' + + + end diff --git a/db/migrate/20161018230557_create_users.rb b/db/migrate/20161018230557_create_users.rb new file mode 100644 index 0000000000..4162768c25 --- /dev/null +++ b/db/migrate/20161018230557_create_users.rb @@ -0,0 +1,17 @@ +class CreateUsers < ActiveRecord::Migration + def change + create_table :users do |t| + t.string :first_name + t.string :last_name + t.string :email + t.string :street_address + t.string :city + t.string :state + t.integer :zip + t.integer :phone + t.boolean :merchant + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20161018230623_create_products.rb b/db/migrate/20161018230623_create_products.rb new file mode 100644 index 0000000000..7ca39792a4 --- /dev/null +++ b/db/migrate/20161018230623_create_products.rb @@ -0,0 +1,15 @@ +class CreateProducts < ActiveRecord::Migration + def change + create_table :products do |t| + t.string :name + t.text :description + t.decimal :price + t.string :photo_url + t.integer :inventory + t.string :category + t.references :user_id, index: true, foreign_key: true + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20161018231057_create_orders.rb b/db/migrate/20161018231057_create_orders.rb new file mode 100644 index 0000000000..a97d256705 --- /dev/null +++ b/db/migrate/20161018231057_create_orders.rb @@ -0,0 +1,19 @@ +class CreateOrders < ActiveRecord::Migration + def change + create_table :orders do |t| + t.references :product_id, index: true, foreign_key: true + t.references :user_id, index: true, foreign_key: true + t.boolean :status + t.string :first_name + t.string :last_name + t.string :email + t.string :street_address + t.string :city + t.string :state + t.integer :zip + t.integer :phone + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20161018231137_create_order_items.rb b/db/migrate/20161018231137_create_order_items.rb new file mode 100644 index 0000000000..a765bb296f --- /dev/null +++ b/db/migrate/20161018231137_create_order_items.rb @@ -0,0 +1,12 @@ +class CreateOrderItems < ActiveRecord::Migration + def change + create_table :order_items do |t| + t.decimal :unit_price + t.integer :quantity + t.references :product_id, index: true, foreign_key: true + t.references :order_id, index: true, foreign_key: true + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20161018231156_create_reviews.rb b/db/migrate/20161018231156_create_reviews.rb new file mode 100644 index 0000000000..648fa54135 --- /dev/null +++ b/db/migrate/20161018231156_create_reviews.rb @@ -0,0 +1,11 @@ +class CreateReviews < ActiveRecord::Migration + def change + create_table :reviews do |t| + t.references :user_id, index: true, foreign_key: true + t.text :description + t.integer :rank + + t.timestamps null: false + end + end +end diff --git a/db/migrate/20161020031216_add_providerto_users.rb b/db/migrate/20161020031216_add_providerto_users.rb new file mode 100644 index 0000000000..7caa72c6db --- /dev/null +++ b/db/migrate/20161020031216_add_providerto_users.rb @@ -0,0 +1,5 @@ +class AddProvidertoUsers < ActiveRecord::Migration + def change + add_column :users, :provider, :string + end +end diff --git a/db/migrate/20161020033512_add_active_statusto_users.rb b/db/migrate/20161020033512_add_active_statusto_users.rb new file mode 100644 index 0000000000..790f10c559 --- /dev/null +++ b/db/migrate/20161020033512_add_active_statusto_users.rb @@ -0,0 +1,5 @@ +class AddActiveStatustoUsers < ActiveRecord::Migration + def change + add_column :users, :status, :boolean + end +end diff --git a/db/migrate/20161020052344_add_product_id_to_review.rb b/db/migrate/20161020052344_add_product_id_to_review.rb new file mode 100644 index 0000000000..12dd055a5c --- /dev/null +++ b/db/migrate/20161020052344_add_product_id_to_review.rb @@ -0,0 +1,5 @@ +class AddProductIdToReview < ActiveRecord::Migration + def change + add_reference :reviews, :product, index: true, foreign_key: true + end +end diff --git a/db/migrate/20161021020000_remove_foreign_keys_order_items.rb b/db/migrate/20161021020000_remove_foreign_keys_order_items.rb new file mode 100644 index 0000000000..de53192ece --- /dev/null +++ b/db/migrate/20161021020000_remove_foreign_keys_order_items.rb @@ -0,0 +1,6 @@ +class RemoveForeignKeysOrderItems < ActiveRecord::Migration + def change + remove_column :order_items, :order_id_id + remove_column :order_items, :product_id_id + end +end diff --git a/db/migrate/20161021020112_re_add_foreign_keys_order_items.rb b/db/migrate/20161021020112_re_add_foreign_keys_order_items.rb new file mode 100644 index 0000000000..ed30c0e131 --- /dev/null +++ b/db/migrate/20161021020112_re_add_foreign_keys_order_items.rb @@ -0,0 +1,6 @@ +class ReAddForeignKeysOrderItems < ActiveRecord::Migration + def change + add_column :order_items, :order_id, :integer + add_column :order_items, :product_id, :integer + end +end diff --git a/db/migrate/20161021020207_remove_foreign_keys_orders.rb b/db/migrate/20161021020207_remove_foreign_keys_orders.rb new file mode 100644 index 0000000000..9b3551054b --- /dev/null +++ b/db/migrate/20161021020207_remove_foreign_keys_orders.rb @@ -0,0 +1,6 @@ +class RemoveForeignKeysOrders < ActiveRecord::Migration + def change + remove_column :orders, :user_id_id + remove_column :orders, :product_id_id + end +end diff --git a/db/migrate/20161021020301_re_add_foreign_keys_orders.rb b/db/migrate/20161021020301_re_add_foreign_keys_orders.rb new file mode 100644 index 0000000000..6f79c1b2d9 --- /dev/null +++ b/db/migrate/20161021020301_re_add_foreign_keys_orders.rb @@ -0,0 +1,6 @@ +class ReAddForeignKeysOrders < ActiveRecord::Migration + def change + add_column :orders, :user_id, :integer + add_column :orders, :product_id, :integer + end +end diff --git a/db/migrate/20161021020359_remove_foreign_key_product.rb b/db/migrate/20161021020359_remove_foreign_key_product.rb new file mode 100644 index 0000000000..2f0bef857b --- /dev/null +++ b/db/migrate/20161021020359_remove_foreign_key_product.rb @@ -0,0 +1,5 @@ +class RemoveForeignKeyProduct < ActiveRecord::Migration + def change + remove_column :products, :user_id_id + end +end diff --git a/db/migrate/20161021020431_re_add_foreign_key_product.rb b/db/migrate/20161021020431_re_add_foreign_key_product.rb new file mode 100644 index 0000000000..7ed5e5d249 --- /dev/null +++ b/db/migrate/20161021020431_re_add_foreign_key_product.rb @@ -0,0 +1,5 @@ +class ReAddForeignKeyProduct < ActiveRecord::Migration + def change + add_column :products, :user_id, :integer + end +end diff --git a/db/migrate/20161021020520_remove_foreign_key_reviews.rb b/db/migrate/20161021020520_remove_foreign_key_reviews.rb new file mode 100644 index 0000000000..649535291e --- /dev/null +++ b/db/migrate/20161021020520_remove_foreign_key_reviews.rb @@ -0,0 +1,5 @@ +class RemoveForeignKeyReviews < ActiveRecord::Migration + def change + remove_column :reviews, :user_id_id + end +end diff --git a/db/migrate/20161021020547_re_add_foreign_key_reviews.rb b/db/migrate/20161021020547_re_add_foreign_key_reviews.rb new file mode 100644 index 0000000000..2c1f44ee19 --- /dev/null +++ b/db/migrate/20161021020547_re_add_foreign_key_reviews.rb @@ -0,0 +1,5 @@ +class ReAddForeignKeyReviews < ActiveRecord::Migration + def change + add_column :reviews, :user_id, :integer + end +end diff --git a/db/migrate/20161021020911_re_add_indices_order_items.rb b/db/migrate/20161021020911_re_add_indices_order_items.rb new file mode 100644 index 0000000000..550f2de8f2 --- /dev/null +++ b/db/migrate/20161021020911_re_add_indices_order_items.rb @@ -0,0 +1,6 @@ +class ReAddIndicesOrderItems < ActiveRecord::Migration + def change + add_index :order_items, :order_id + add_index :order_items, :product_id + end +end diff --git a/db/migrate/20161021021037_re_add_indices_orders.rb b/db/migrate/20161021021037_re_add_indices_orders.rb new file mode 100644 index 0000000000..3d9f28fca8 --- /dev/null +++ b/db/migrate/20161021021037_re_add_indices_orders.rb @@ -0,0 +1,6 @@ +class ReAddIndicesOrders < ActiveRecord::Migration + def change + add_index :orders, :user_id + add_index :orders, :product_id + end +end diff --git a/db/migrate/20161021021144_re_add_index_products.rb b/db/migrate/20161021021144_re_add_index_products.rb new file mode 100644 index 0000000000..d105ae03d5 --- /dev/null +++ b/db/migrate/20161021021144_re_add_index_products.rb @@ -0,0 +1,5 @@ +class ReAddIndexProducts < ActiveRecord::Migration + def change + add_index :products, :user_id + end +end diff --git a/db/migrate/20161021030828_add_password_digestto_users.rb b/db/migrate/20161021030828_add_password_digestto_users.rb new file mode 100644 index 0000000000..8eb52b354b --- /dev/null +++ b/db/migrate/20161021030828_add_password_digestto_users.rb @@ -0,0 +1,5 @@ +class AddPasswordDigesttoUsers < ActiveRecord::Migration + def change + add_column :users, :password_digest, :string + end +end diff --git a/db/migrate/20161021031349_add_password_confirmationto_users.rb b/db/migrate/20161021031349_add_password_confirmationto_users.rb new file mode 100644 index 0000000000..f767edf933 --- /dev/null +++ b/db/migrate/20161021031349_add_password_confirmationto_users.rb @@ -0,0 +1,5 @@ +class AddPasswordConfirmationtoUsers < ActiveRecord::Migration + def change + add_column :users, :password_confirmation, :string + end +end diff --git a/db/migrate/20161021063530_remove_password_confirmation_column_users.rb b/db/migrate/20161021063530_remove_password_confirmation_column_users.rb new file mode 100644 index 0000000000..a9e2b29bc0 --- /dev/null +++ b/db/migrate/20161021063530_remove_password_confirmation_column_users.rb @@ -0,0 +1,4 @@ +class RemovePasswordConfirmationColumnUsers < ActiveRecord::Migration + def change + end +end diff --git a/db/migrate/20161021181138_change_user_column_defaults_provider_status.rb b/db/migrate/20161021181138_change_user_column_defaults_provider_status.rb new file mode 100644 index 0000000000..7d2ad6991a --- /dev/null +++ b/db/migrate/20161021181138_change_user_column_defaults_provider_status.rb @@ -0,0 +1,5 @@ +class ChangeUserColumnDefaultsProviderStatus < ActiveRecord::Migration + def change + change_column_default(:users, :provider, :false) + end +end diff --git a/db/migrate/20161021181152_add_column_ui_dto_column_defaults.rb b/db/migrate/20161021181152_add_column_ui_dto_column_defaults.rb new file mode 100644 index 0000000000..f8b9c8ba53 --- /dev/null +++ b/db/migrate/20161021181152_add_column_ui_dto_column_defaults.rb @@ -0,0 +1,5 @@ +class AddColumnUiDtoColumnDefaults < ActiveRecord::Migration + def change + add_column :users, :uid, :integer, default: false + end +end diff --git a/db/migrate/20161022235549_change_integer_limit_in_users_table.rb b/db/migrate/20161022235549_change_integer_limit_in_users_table.rb new file mode 100644 index 0000000000..e0258fe075 --- /dev/null +++ b/db/migrate/20161022235549_change_integer_limit_in_users_table.rb @@ -0,0 +1,5 @@ +class ChangeIntegerLimitInUsersTable < ActiveRecord::Migration + def change + change_column :users, :phone, :integer, limit: 10 + end +end diff --git a/db/migrate/20161023232919_change_status_data_type_in_order.rb b/db/migrate/20161023232919_change_status_data_type_in_order.rb new file mode 100644 index 0000000000..ca7441f00a --- /dev/null +++ b/db/migrate/20161023232919_change_status_data_type_in_order.rb @@ -0,0 +1,5 @@ +class ChangeStatusDataTypeInOrder < ActiveRecord::Migration + def change + change_column(:orders, :status, :string, limit: 80) + end +end diff --git a/db/migrate/20161024074529_add_payment_info_to_order.rb b/db/migrate/20161024074529_add_payment_info_to_order.rb new file mode 100644 index 0000000000..3a39ab72c1 --- /dev/null +++ b/db/migrate/20161024074529_add_payment_info_to_order.rb @@ -0,0 +1,8 @@ +class AddPaymentInfoToOrder < ActiveRecord::Migration + def change + add_column :orders, :cc_number, :integer + add_column :orders, :exp_month, :integer + add_column :orders, :exp_year, :integer + add_column :orders, :cvc, :integer + end +end diff --git a/db/migrate/20161024090004_change_phone_limit_to_user.rb b/db/migrate/20161024090004_change_phone_limit_to_user.rb new file mode 100644 index 0000000000..81003e211a --- /dev/null +++ b/db/migrate/20161024090004_change_phone_limit_to_user.rb @@ -0,0 +1,5 @@ +class ChangePhoneLimitToUser < ActiveRecord::Migration + def change + change_column :users, :phone, :integer, limit: 10 + end +end diff --git a/db/migrate/20161024090318_change_phone_limit_to_order.rb b/db/migrate/20161024090318_change_phone_limit_to_order.rb new file mode 100644 index 0000000000..90f224c25a --- /dev/null +++ b/db/migrate/20161024090318_change_phone_limit_to_order.rb @@ -0,0 +1,5 @@ +class ChangePhoneLimitToOrder < ActiveRecord::Migration + def change + change_column :orders, :phone, :integer, limit: 10 + end +end diff --git a/db/migrate/20161024205357_remove_last_name_from_users.rb b/db/migrate/20161024205357_remove_last_name_from_users.rb new file mode 100644 index 0000000000..a7aae4852b --- /dev/null +++ b/db/migrate/20161024205357_remove_last_name_from_users.rb @@ -0,0 +1,5 @@ +class RemoveLastNameFromUsers < ActiveRecord::Migration + def change + remove_column :users, :last_name + end +end diff --git a/db/migrate/20161024205557_rename_first_name_column_users.rb b/db/migrate/20161024205557_rename_first_name_column_users.rb new file mode 100644 index 0000000000..7942f766f0 --- /dev/null +++ b/db/migrate/20161024205557_rename_first_name_column_users.rb @@ -0,0 +1,5 @@ +class RenameFirstNameColumnUsers < ActiveRecord::Migration + def change + rename_column :users, :first_name, :name + end +end diff --git a/db/migrate/20161024234517_remove_last_name_from_orders.rb b/db/migrate/20161024234517_remove_last_name_from_orders.rb new file mode 100644 index 0000000000..16dcd050a1 --- /dev/null +++ b/db/migrate/20161024234517_remove_last_name_from_orders.rb @@ -0,0 +1,5 @@ +class RemoveLastNameFromOrders < ActiveRecord::Migration + def change + remove_column :orders, :last_name + end +end diff --git a/db/migrate/20161024234656_rename_first_name_column_orders.rb b/db/migrate/20161024234656_rename_first_name_column_orders.rb new file mode 100644 index 0000000000..103b4cbce6 --- /dev/null +++ b/db/migrate/20161024234656_rename_first_name_column_orders.rb @@ -0,0 +1,5 @@ +class RenameFirstNameColumnOrders < ActiveRecord::Migration + def change + rename_column :orders, :first_name, :name + end +end diff --git a/db/migrate/20161026070303_add_status_to_order_item.rb b/db/migrate/20161026070303_add_status_to_order_item.rb new file mode 100644 index 0000000000..b1aac9f1e8 --- /dev/null +++ b/db/migrate/20161026070303_add_status_to_order_item.rb @@ -0,0 +1,5 @@ +class AddStatusToOrderItem < ActiveRecord::Migration + def change + add_column :order_items, :status, :string + end +end diff --git a/db/migrate/20161027212432_add_alt_text_to_products.rb b/db/migrate/20161027212432_add_alt_text_to_products.rb new file mode 100644 index 0000000000..ddaf60f684 --- /dev/null +++ b/db/migrate/20161027212432_add_alt_text_to_products.rb @@ -0,0 +1,5 @@ +class AddAltTextToProducts < ActiveRecord::Migration + def change + add_column :products, :alt_text, :string + end +end diff --git a/db/migrate/20161027223701_remove_integer_limits.rb b/db/migrate/20161027223701_remove_integer_limits.rb new file mode 100644 index 0000000000..9df91faa2a --- /dev/null +++ b/db/migrate/20161027223701_remove_integer_limits.rb @@ -0,0 +1,6 @@ +class RemoveIntegerLimits < ActiveRecord::Migration + def change + change_column :orders, :phone, :integer, limit: nil + change_column :users, :phone, :integer, limit: nil + end +end diff --git a/db/migrate/20161027231701_change_phone_columns_to_string.rb b/db/migrate/20161027231701_change_phone_columns_to_string.rb new file mode 100644 index 0000000000..1bbd55f109 --- /dev/null +++ b/db/migrate/20161027231701_change_phone_columns_to_string.rb @@ -0,0 +1,6 @@ +class ChangePhoneColumnsToString < ActiveRecord::Migration + def change + change_column :users, :phone, :string + change_column :orders, :phone, :string + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000000..d3d446c14b --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,96 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 20161027231701) do + + create_table "order_items", force: :cascade do |t| + t.decimal "unit_price" + t.integer "quantity" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "order_id" + t.integer "product_id" + t.string "status" + end + + add_index "order_items", ["order_id"], name: "index_order_items_on_order_id" + add_index "order_items", ["product_id"], name: "index_order_items_on_product_id" + + create_table "orders", force: :cascade do |t| + t.string "status", limit: 80 + t.string "name" + t.string "email" + t.string "street_address" + t.string "city" + t.string "state" + t.integer "zip" + t.string "phone" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "user_id" + t.integer "product_id" + t.integer "cc_number" + t.integer "exp_month" + t.integer "exp_year" + t.integer "cvc" + end + + add_index "orders", ["product_id"], name: "index_orders_on_product_id" + add_index "orders", ["user_id"], name: "index_orders_on_user_id" + + create_table "products", force: :cascade do |t| + t.string "name" + t.text "description" + t.decimal "price" + t.string "photo_url" + t.integer "inventory" + t.string "category" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "user_id" + t.string "alt_id" + t.string "alt_text" + end + + add_index "products", ["user_id"], name: "index_products_on_user_id" + + create_table "reviews", force: :cascade do |t| + t.text "description" + t.integer "rank" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "product_id" + t.integer "user_id" + end + + add_index "reviews", ["product_id"], name: "index_reviews_on_product_id" + + create_table "users", force: :cascade do |t| + t.string "name" + t.string "email" + t.string "street_address" + t.string "city" + t.string "state" + t.integer "zip" + t.string "phone" + t.boolean "merchant" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "provider", default: "false" + t.boolean "status" + t.string "password_digest" + t.string "password_confirmation" + t.integer "uid", default: 0 + end + +end diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e857e..da83bc6c43 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,3 +5,13 @@ # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) + +require 'csv' + + CSV.foreach ('seed_csvs/products.csv') do |csv_obj| + Product.create(name: csv_obj[1], description: csv_obj[2], price: csv_obj[3].to_f, photo_url: csv_obj[4], inventory: csv_obj[5].to_i, category: csv_obj[6], user_id: csv_obj[7].to_i, alt_text: csv_obj[8]) + end + + CSV.foreach ('seed_csvs/users.csv') do |csv_obj| + User.create(name: csv_obj[1], email: csv_obj[2], street_address: csv_obj[3], city: csv_obj[4], state: csv_obj[5], zip: csv_obj[6].to_i, phone: csv_obj[7], merchant: csv_obj[8], provider: csv_obj[9]) + end diff --git a/lib/templates/erb/scaffold/_form.html.erb b/lib/templates/erb/scaffold/_form.html.erb new file mode 100644 index 0000000000..201a069e2c --- /dev/null +++ b/lib/templates/erb/scaffold/_form.html.erb @@ -0,0 +1,13 @@ +<%%= simple_form_for(@<%= singular_table_name %>) do |f| %> + <%%= f.error_notification %> + +
+ <%- attributes.each do |attribute| -%> + <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> + <%- end -%> +
+ +
+ <%%= f.button :submit %> +
+<%% end %> diff --git a/notes_on_factory_girl_rails_use.md b/notes_on_factory_girl_rails_use.md new file mode 100644 index 0000000000..7be32e667a --- /dev/null +++ b/notes_on_factory_girl_rails_use.md @@ -0,0 +1,64 @@ +# Notes about Testing with 'factory_girl_rails' + +# factory_girl_rails +Documentation: https://github.com/thoughtbot/factory_girl_rails + ++ factory_girl is a fixtures replacement with a straightforward definition syntax ++ support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects) ++ support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance. + +Note_to_self: Currently using: Rails 4.2.6 + +##REASONS TO USE 'factory_girl': +1. https://www.hiringthing.com/2012/08/17/rails-testing-factory-girl.html ++ Good explanation of why its helpful: "The first (and possibly best) reason to use Factory Girl is because it solves the single worst problem of fixtures: maintenance. Tests become much easier to maintain when you can request a model instance that is always current." ++ Thorough examples! + +2. +https://thoughtbot.com/upcase/videos/factory-girl +better than fixtures. ++ "How Factory Girl helps avoid mystery guests: Let's look at a specific example. Fixtures often lead to Mystery Guests, an anti-pattern where we are performing some assertions in our tests but it's not at all obvious at a glance what the data we're asserting against. +3. http://culttt.com/2016/02/17/replacing-fixtures-with-factory-girl-in-ruby-on-rails/ ++ Gives great examples and discusses why "replacing fixtures with factories is helpful." ++ "Firstly, instead of defining each Fixture, you define a Factory that can be used to create models of that type. The Factory is basically just a blueprint for creating instances of that model object. Now whenever you need an instance of the model, or you need to pre-populate the database with data for a given scenario, you can use the Factory. is means that only the data required for the test will be in the database and it’s immediately clear where that data came from. +" + + +### HOW TO USE 'factory_girl': +1. +https://robots.thoughtbot.com/aint-no-calla-back-girl ++ Article goes over how to write and understand has_many associations. ++ Ex Factory: +``` +factory :article do + body 'password' + + factory :article_with_comment do + after(:create) do |article| + create(:comment, article: article) + end + end +end + +factory :comment do + body 'Great article!' +end +``` ++ Nice. Callbacks let us do this: +``` +article = create(:article_with_comment) +``` ++ Article also covers: Polymorphic relationships + +2. http://samuelmullen.com/categories/ruby-on-rails/ +Extremely comprehensive guide on how to use/test: Validating Presence of Associations and Foreign Keys in Rails. Among other things. It's crazy long and thorough. + +3. https://github.com/thoughtbot/factory_girl/wiki/How-factory_girl-interacts-with-ActiveRecord ++ Great example syntax + + + +## Notes on Minitest, found most examples of using 'factory_girl_rails' used Rspec. Found these helpful for using Minitest syntax. + +1. http://danwin.com/2013/03/ruby-minitest-cheat-sheet/ +2. https://ariejan.net/2015/04/07/testing-with-minitest/ diff --git a/public/vamp_favicon.ico b/public/vamp_favicon.ico new file mode 100644 index 0000000000..0d8ce7e7ec Binary files /dev/null and b/public/vamp_favicon.ico differ diff --git a/seed_csvs/products.csv b/seed_csvs/products.csv new file mode 100644 index 0000000000..67af13109f --- /dev/null +++ b/seed_csvs/products.csv @@ -0,0 +1,24 @@ +1,"Spooky ghosts","They moan, they groan, they slam doors and squeak floorboards! Earplugs sold separately.",124.99,"Minions/Ghosts.png",7,"Minions",5,"A picture of a very spooky clip art ghost" +2,"Igor","First-rate thrall with a pleasant attitude and half a century of experience. Contract involved - Igor is a MinUnion member.",95000.03,"Minions/Igor.jpg",1,"Minions",5,"An image of Igor as portrayed by Marty Feldman in the 1974 film Young Frankenstein" +3,"Chad","Chad is here for you with his winning smile! Chad is definitely not a plant sent by the Anti-Vampire Brigade. Chaaaaad.",350.04,"Minions/Chad.png",38,"Minions",4,"Faceless outline of a generic white businessman" +4,"Gargoyles","Like the kind from the popular children's television show",22.99,"Minions/Gargoyles.png",7,"Minions",6,"An image of Goliath from the hit animated show Gargoyles" +5,"Bats","A vicious swarm for protecting your home! Rabies shot sold separately.",500.35,"Minions/Bats.jpg",42,"Minions",8,"A claustrophobic dark tunnel shot with bats flying right at the brave and or terrified photographer" +6,"Wolves","They travel in packs and howl at the moon and eat watermelon sometimes! A must-have for any foreboding castle.",250.22,"Minions/Wolves.jpg",14,"Minions",4,"A wolf with half a watermelon in its derpy mouth" +7,"Coffins","Yass queen! Comes in marble, onyx, and artisanal oak, cherry, walnut, and maple.",799.41,"Home_Decor/Coffins.jpg",12,"Home Decor",5,"A marble sarcophagus with a woman lounging on top and a dead guy etched on the side" +8,"Blackout Curtains","Perfect for a restful slumber uninterrupted by a scorching fiery death from mid-morning sunbeams",40.25,"Home_Decor/Curtains.jpg",3,"Home Decor",5,"Blackout curtains with a silhouette of a most likely pining Victorian woman in relief against the light" +9,"Goblets","We could all use more for hurling across the room in a fit of vampire drama. Pitchers are currently unavailable - we hurled our stock across the room because reasons.",22.75,"Home_Decor/Goblets.jpg",6,"Home Decor",1,"Nice silver goblets with snazzy silver etchings on the sides" +10,"Candles","Nothing sets the mood quite like candlelight. Candelabra included!",39.99,"Home_Decor/Candles.jpg",17,"Home Decor",3,"Tall candles in a silver candelabra" +11,"Snackles","Keep your next meal from becoming to-go!",19.99,"Home_Decor/Snackles.jpg",1,"Home Decor",2,"These are the worst shackles I've ever seen - the person in the picture literally could fit both arms and a leg in these and still escape" +12,"Suspiciously Fresh Red Roses","Are they fake? Do you have a garden somewhere? Why don't they ever wilt??? Keep your guests guessing with these fabulous flowers!",12.99,"Home_Decor/Roses.jpg",317,"Home Decor",1,"Image of quintessential red roses that seemingly never wilt" +13,"Capes","Is it hard work, looking so good? Available in all colors.",49.99,"Fashion/Cape.jpg",5,"Fashion",6,"Freddy Mercury posing in a cape and being fabulous - thank you internet for this blessing" +14,"Tuxedoes","Be bold and mysterious at those evening soirees! Pairs well with our cape selection.",69.99,"Fashion/Tuxedo.jpg",14,"Fashion",8,"A picture of a white tuxedo shirt and a black bowtie" +15,"Anti-Stake Armor","Everyone has bad days. Plan in advance for the Anti-Vampire Brigade. Worn here by the brilliant Aishwarya Rai Bachchan.",129.99,"Fashion/Armor.jpg",3,"Fashion",8,"Awesome medieval leather armor worn by a really awesome lady on a movie set" +16,"Pajamas","Perfect for the undead in your life who enjoys a night in. Also available in Elmo, Oscar, and Big Bird.",31.99,"Fashion/Pajamas.png",15,"Fashion",6,"A chill cat in blue cookie monster footie pajamas with a plate of cookies in its lap" +17,"Spandex","Just like it says on the tin. Nothing else withstands the bat transformation, let's be real here.",15.99,"Fashion/Spandex.jpg",2,"Fashion",6,"People dancing in spandex at the 1988 Crystal Light National Aerobic Championships" +18,"Bat Goggles","Keep the wind out of your eyes while flying! Worn here by Colonel Sassacre.",11.99,"Fashion/Goggles.jpg",9,"Fashion",3,"A stoic cat wearing small black goggles" +19,"SPF 10,000 Sunscreen","Our own proprietary blend! * Note: Your results may vary.",7.99,"Personal_Care/Sunscreen.jpg",10,"Personal Care",1,"A photo of several sunscreen tubes and a spray bottle" +20,"Toothbrushes","Keep those fangs healthy! One tube of Tasty O- Toothpaste included.",3.99,"Personal_Care/Toothbrushes.jpg",5,"Personal Care",5,"A trio of toothbrushes" +21,"Hematophobia And You","A self-help book for those of us who have a more complicated relationships with blood.",16.99,"Personal_Care/Book.jpg",3,"Personal Care",2,"An open book with a large flower in it like this is etsy and they just happened to find their book like this and take a picture" +22,"Bronzer","Put a little color back in those pale cheeks! Available in all colors - we customize just for you! Mirror not included.",14.99,"Personal_Care/Bronzer.jpg",9,"Personal Care",3,"Bronzer with a brush and a small stand up mirror" +23,"Bite Guard","Keep those fangs sharp while you sleep with this new chocolate-flavored bite guard! Definitely not just a piece of chocolate.",5.99,"Personal_Care/Biteguard.jpg",4,"Personal Care",8,"An image of a mouth where the person is biting down on a piece of chocolate" +24,"Anti-Garlic Mask","You're never too old for a classic. Guaranteed to keep that garlic smell and also the ocean out!",159.99,"Personal_Care/Mask.png",1,"Personal Care",6,"Literally a shiny metallic diving bell helmet because if you're going to ride eternal shiny and chrome you might as well do it in one of these babies" diff --git a/seed_csvs/users.csv b/seed_csvs/users.csv new file mode 100644 index 0000000000..0e603386a9 --- /dev/null +++ b/seed_csvs/users.csv @@ -0,0 +1,8 @@ +1,"Rusty Rail","rusty@vampires.io","123 Madison Ave","Seattle","WA",98102,2062222,true,"github" +2,"Sally Beth Walcott","sally@vampires.io","1700 Undead Lane","Ruidoso","NM",88345,5055555,true,"github" +3,"Lestat Jones","lestat@aol.com","541 Old Hidden Country Route 5 North","Flushing","MI",48433,8108888,true,"github" +4,"Madeleine Kinoko","maddy@mushroom.com","700 Ocarina Way Apt 2","Phoenix","AZ",85345,6022222,true,"github" +5,"Juanita Torres","juanita@aol.com","814 East Archer Drive","Ruidoso","NM",88355,5054444,true,"github" +6,"Marcy Ogulo","marcy@vampires.io","10109 Eldritch Circle","Phoenix","AZ",85003,6233333,true,"github" +7,"Laila Satrapi","laila@gmail.com","222 Lugosi Lane #C","Seattle","WA",98104,2066666,true,"github" +8,"Ambrose Ardenmoor","ambrose@vampires.io","3 Unseen Court","Casper","WY",82002,8777777,true,"github" diff --git a/test/controllers/homepages_controller_test.rb b/test/controllers/homepages_controller_test.rb new file mode 100644 index 0000000000..b1f71cd90f --- /dev/null +++ b/test/controllers/homepages_controller_test.rb @@ -0,0 +1,21 @@ + +require 'test_helper' + +class HomepagesControllerTest < ActionController::TestCase + # test "should get index" do + # get :index + # assert_response :success + # end + + # test "assigns the @product_categories" do + # expect(assigns(:product_categories).not_to be_nil + # end + + # test "should get show product categories" do + # get :show, id: items(:album_sample).id + # assert_response :success + # end + + + +end diff --git a/test/controllers/orders_controller_test.rb b/test/controllers/orders_controller_test.rb new file mode 100644 index 0000000000..d689a0fccb --- /dev/null +++ b/test/controllers/orders_controller_test.rb @@ -0,0 +1,66 @@ +require 'test_helper' + +class OrdersControllerTest < ActionController::TestCase + # test "should get index" do + # get :index + # assert_response :success + # end + + # test "should get show" do + # get :show + # assert_response :success + # end + + # test "should get new" do + # get :new + # assert_response :success + # end + + # test "should get create" do + # get :create + # assert_response :success + # end + + # test "should get edit" do + # get :edit + # assert_response :success + # end + + # test "should get update" do + # get :update + # assert_response :success + # end + + # test "should get destroy" do + # get :destroy + # assert_response :success + # end + + # #example used was in TaskRails Task Controller, needs fleshing out with fixture info + + # test "If a user is not logged in they cannot see their task." do + # session[:user_id] = nil # ensure no one is logged in + + # get :show, id: orders(:SOMEORDER).id + # # if they are not logged in they cannot see the resource and are redirected to login. + # assert_redirected session_path + # assert_equal "You must be logged in first", flash[:notice] + # end + + # test "Make sure a user can see their orders" do + # session[:user_id] = users(:SOMENAME).id + # get :show, id: orders(:SOMENAME).id + + # assert_response :success + # end + + # test "Make Sure a User Cannot See Another User's Orders" do + # session[:user_id] = users(:SOMENAME).id + # get :show, id: orders(:SOMEORDER).id + # get :show, id: orders(:SOMEORDER).id + + # assert_response :redirect + # assert_equal flash[:notice], "You do not have access to that information." + # end + +end diff --git a/test/controllers/products_controller_test.rb b/test/controllers/products_controller_test.rb new file mode 100644 index 0000000000..adae9a1071 --- /dev/null +++ b/test/controllers/products_controller_test.rb @@ -0,0 +1,83 @@ +require 'test_helper' + +class ProductsControllerTest < ActionController::TestCase + test "should get index" do + get :index + assert_response :success + end + + test "should get show" do + get :show, {id: products(:product4).id } + assert_response :success + end + + test "should get new" do + get :new + assert_response :success + end + + test "should get create" do + post_params = {product: {name: 'Legos', description: 'small blocks', category: 'Home Decor', price: 1.0, inventory: 2 }} + post :create, post_params + assert_response :redirect + end + + test "should be able to edit a product" do + get :edit, {id: products(:product3).id } + assert_response :success + end + + test "should get update" do + patch :update, { id: products(:product4).id } + assert_response :success + end + + test "should get destroy" do + assert_difference( "Product.count", -1 ) do + delete :destroy, { id: products(:product2).id } + assert_response :redirect + end + end + + test 'a product must have a name' do + + end + + test 'a product must have a category' do + end + + test 'a product must have a price' do + end + + test 'a product must have a description' do + end + + #example used was in TaskRails Task Controller, needs fleshing out with fixture info + + # test "If a user is not logged in they cannot see their product." do + # session[:user_id] = nil # ensure no one is logged in + + # get :show, id: products(:product1).id + # # if they are not logged in they cannot see the resource and are redirected to login. + # assert_redirected_to session_path + # assert_equal "You must be logged in first", flash[:notice] + # end + + test "Make sure a user can see their products" do + session[:user_id] = users(:rbg).id + get :show, id: products(:product1).id + + assert_response :success + end + + # test "Make Sure a User Cannot See Another User's products" do + # session[:user_id] = users(:SOMENAME).id + # get :show, id: products(:SOMEPRODUCT).id + # get :show, id: products(:SOMEPRODUCT).id + + # assert_response :redirect + # assert_equal flash[:notice], "You do not have access to that information." + # end + + +end diff --git a/test/controllers/reviews_controller_test.rb b/test/controllers/reviews_controller_test.rb new file mode 100644 index 0000000000..7a6ab9f90d --- /dev/null +++ b/test/controllers/reviews_controller_test.rb @@ -0,0 +1,39 @@ +require 'test_helper' + +class ReviewsControllerTest < ActionController::TestCase + test "should get index" do + get :index + assert_response :success + end + + test "should get show" do + get :show + assert_response :success + end + + test "should get new" do + get :new + assert_response :success + end + + test "should get create" do + get :create + assert_response :success + end + + test "should get edit" do + get :edit + assert_response :success + end + + test "should get update" do + get :update + assert_response :success + end + + test "should get destroy" do + get :destroy + assert_response :success + end + +end diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb new file mode 100644 index 0000000000..904be93e76 --- /dev/null +++ b/test/controllers/sessions_controller_test.rb @@ -0,0 +1,65 @@ +require 'test_helper' + +class SessionsControllerTest < ActionController::TestCase + # test "should get index" do + # get :index + # assert_response :success + # end + + # test "should get show" do + # get :show + # assert_response :success + # end + + # test "should get new" do + # get :new + # assert_response :success + # end + + + + # test "should get edit" do + # get :edit + # assert_response :success + # end + + # test "should get update" do + # get :update + # assert_response :success + # end + + test "should get destroy" do + get :destroy + assert_response :redirect + end + + def login_a_user + request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:github] + get :create, {provider: "github"} + end + + test "Can Create a user" do + assert_difference("User.count", 1) do + login_a_user + assert_response :redirect + assert_redirected_to root_path + end + end + + test "If a user logs in twice it doesn't create a 2nd user" do + assert_difference("User.count", 1) do + login_a_user + end + assert_no_difference("User.count") do + login_a_user + assert_response :redirect + assert_redirected_to root_path + end + end + + # test "should get create" do + # get :create + # assert_response :success + # end + +end diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000000..e9b92773d0 --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,84 @@ +require 'test_helper' + +class UsersControllerTest < ActionController::TestCase + test 'should always succeed' do + assert true + end + + test "should get index" do + get :index + assert_response :success + end + + test "should get show" do + get :show, { id: users(:rbg).id } + assert_response :success + end + +#NOT FOR OUR SITUATION + # test "should get new" do + # get :new + # assert_response :success + # end + + +#NOT FOR OUR SITUATION + # test "should get create" do + # get :create + # assert_response :success + # end + + test "should get edit" do + get :edit, { id: users(:rbg).id } + assert_response :success + end + + test "should be able to update a user" do + patch :update, { id: users(:ss).id } + assert_response :success + end + + test "should be able to deactivate a user (i.e., destroy)" do + delete :destroy, { id: users(:rbg).id } + assert_response :success + end + + +#NOT REALLY NEEDED BECAUSE OF OAUTH. OAUTH WILL ENSURE OUR PERSON HAS ALL THESE + # test 'a user must have a name' do + # end + + # test 'a user must have a provider ' do + # end + + # test 'a user must have a uid' do + # end + +#FOR ALL OTHER CONTROLLERS + # test "If a user is not logged in they cannot see their task." do + # session[:user_id] = nil # ensure no one is logged in + + # get :show, id: tasks(:grace_task).id + # # if they are not logged in they cannot see the resource and are redirected to login. + # assert_redirected session_path + # assert_equal "You must be logged in first", flash[:notice] + # end + + # test "Make sure a user can see their tasks" do + # session[:user_id] = users(:grace_hopper).id + # get :show, id: tasks(:grace_task).id + + # assert_response :success + # end + + # test "Make Sure a User Cannot See Another User's Tasks" do + # session[:user_id] = users(:weili_dai).id + # get :show, id: tasks(:grace_task).id + # get :show, id: tasks(:grace_task).id + + # assert_response :redirect + # assert_equal flash[:notice], "You do not have access to that task." + # end + + +end diff --git a/test/fixtures/.keep b/test/fixtures/.keep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/fixtures/order_items.yml b/test/fixtures/order_items.yml new file mode 100644 index 0000000000..6bd5e513e0 --- /dev/null +++ b/test/fixtures/order_items.yml @@ -0,0 +1,13 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + unit_price: 1 + quantity: 1 + product_id: 1 + order_id: 1 + +two: + unit_price: 1 + quantity: 1 + product_id: 1 + order_id: 1 diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml new file mode 100644 index 0000000000..edf4719353 --- /dev/null +++ b/test/fixtures/orders.yml @@ -0,0 +1,25 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + product_id: + user_id: + status: false + name: MyString + email: MyString + street_address: MyString + city: MyString + state: MyString + zip: 1 + phone: 1 + +two: + product_id: + user_id: + status: false + name: MyString + email: MyString + street_address: MyString + city: MyString + state: MyString + zip: 1 + phone: 1 diff --git a/test/fixtures/products.yml b/test/fixtures/products.yml new file mode 100644 index 0000000000..3faa8892b2 --- /dev/null +++ b/test/fixtures/products.yml @@ -0,0 +1,37 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +product1: + name: sunscreen + description: SPF10000 + price: 99.99 + photo_url: https://unsplash.it/200 + inventory: 20 + category: personal_care + user_id: 1 + +product2: + name: coffin + description: softest conforty bed... + price: 9.99 + photo_url: https://unsplash.it/200 + inventory: 2 + category: Houseware + user_id: 2 + +product3: + name: cape + description: why I am so handsome. + price: 229.99 + photo_url: https://unsplash.it/200 + inventory: 1 + category: clothing + user_id: 3 + +product4: + name: + description: I treat them as my family. + price: 9.99 + photo_url: https://unsplash.it/200 + inventory: 1000 + category: minion + user_id: 4 diff --git a/test/fixtures/reviews.yml b/test/fixtures/reviews.yml new file mode 100644 index 0000000000..7e9b47b3d9 --- /dev/null +++ b/test/fixtures/reviews.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + user_id: + description: MyText + rank: 1 + +two: + user_id: + description: MyText + rank: 1 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000000..ddad4c36e5 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,25 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +rbg: + name: Ruth Ginsburg + email: notorious@thesupremes.io + street_address: 1 First Street NE + city: Washington + state: DC + zip: 20543 + phone: 2024793000 + merchant: false + provider: github + status: true + +ss: + name: Sonia Sotomayor + email: not-red-sonia@thesupremes.io + street_address: 1 First Street NE + city: Washington + state: MyString + zip: DC + phone: 2024793000 + merchant: true + provider: github + status: true diff --git a/test/models/order_item_test.rb b/test/models/order_item_test.rb new file mode 100644 index 0000000000..f8ddd49953 --- /dev/null +++ b/test/models/order_item_test.rb @@ -0,0 +1,79 @@ +require 'test_helper' + +class OrderItemTest < ActiveSupport::TestCase +#rake test TEST=test/models/order_item_test.rb + +# Testing Checklist: +# start with validations +# Check custom methods in the model (dont do private) +# relatonships + +# let's pass an easy test! + test "the truth" do + assert true + end + +# NEED TO BUILD FACTORY TRISH + # test "valid order_item" do + # assert create(:order_item).valid? + # end + + ##### testing product validations ##### + test "order_item must have a unit price, otherwise invalid." do + order_item = build(:order_item, unit_price: nil) + assert order_item.invalid? + end + + test "order_item must have a quantity, otherwise invalid." do + order_items = build(:order_item, name: nil) + assert order_item.invalid? + end + # test "order_items cannot be used when product_id - stock is below zero." do + # order_items = build(:order_items, ) + # assert order_items.invalid? + # end + + test "order_item prices should not be a negative number" do + order_item = build(:order_item, unit_price: -1 ) + assert order_item.invalid? + end + + test "An order_item price cannot be zero" do + order_item = build(:order_item, price: 0 ) + assert order_item.invalid? + end + + test "An order_item with all fields filled out will be vaild. " do + order_item = build(:order_item) + assert order_item.valid? + end + + test "order_item unit price must be in decimals. '2' will be invalid." do + order_item = build(:order_item, price: 2) + assert order_items.invalid? + end + + ##### testing product associations ##### + + test "order_items must belong to user & an order. If they have both they will be valid" do + order_item = build(:order_item) + assert order_item.valid? + end + + test "order_item must belong to user & an order. If they have neither association. They will be invalid. " do + order_item = build(:order_item, user_id: nil, product_id: nil) + assert order_item.invalid? + end + + test "order_item must belong to the correct user. Expect order_item to belong to ____" do + order_item = build(:order_item) + assert order_item.invalid? + end + + test "order_item must belong to a user" do + order_item = build(:order_item) + order_item2 = build(:order_item) + + assert_equal(order_item, order_item2) + end +end diff --git a/test/models/order_test.rb b/test/models/order_test.rb new file mode 100644 index 0000000000..a33d4be125 --- /dev/null +++ b/test/models/order_test.rb @@ -0,0 +1,142 @@ +require 'test_helper' + +class OrderTest < ActiveSupport::TestCase +# rake test TEST=test/models/order_ test.rb + +# Testing Checklist: + # start with validations + # Check custom methods in the model (dont do private) + # relatonships + +# let's pass an easy test! + test "the truth" do + assert true + end +##### test relationship with user ##### + + test "Valid order" do + order = create(:order) + assert order.valid? + end + + test "orders must belong to a user" do + order = build(:order, user: nil) + refute order.invalid? + assert_not_nil order.errors[:user], "orders must belong to a user!" + end + + + test "orders should have correct user" do + order = create(:order) + user = create(:user) + assert_equal(order.name, user.name) + end +# ATTEMPTING to test this METHOD from ORDERS MODEL: + # def total_price + # return self.order_items.inject(0) {|sum, order_item | sum + order_item.total_price } + # end + # not properly being created. + # test "To ensure that when 2 products ($10.00 each) will have a total_price = $20.00" do + # order1 = create(:order) + # order2 = create(:order) + # total = order1.find_by(product_id.price)+ order2(product_id.price) + # assert_equal (total, 20.00) + # a = create(:order_with_2_products) + # + # end + +#@ maya, you might need to look at these two: + # test "Order status will only be valid if they are any of the following: completed, canceled, ____,____ ." do + # order = create(:order, status: "something wonky") + # + # assert order.valid? + # end + + # test "Order status will not be valid if its not any of the following: ___, ___, ___" do + # order = create(:order, status: "something wonky") + # + # assert order.invalid? + # end + +# *email* will we make this necessary? +# also might be able to add this to a hash in factory so you can be certain to test all cases. +# additionally you can test the postive case of things. + test "If you're trying to submit an order, you must have: status, name, *email*, street_address, city, state, zip, phone" do + submit_order = (:order, status: nil, name:nil, *email: nil, city: nil, zip:nil, phone: nil) + assert submit_order.invalid? + end + + test "Payment parameters are valid as long as you have @ least 4 numbers in cc_number" do + order = create(:order, cc_number: 3333) + assert order.valid? + end + + test "Payment parameters are valid as long as you have @ least 4 numbers in cc_number. If you have less, it will be invalid" do + order = create(:order, cc_number: 333) + assert order.invalid? + end + + test "Make sure phone number user enters is the correct amount (8 nums long?)" do + + end + + test "CVC should be at least 3 numbers but not exceed 4 (as american express has 4).Thus, 1234 should be valid" do + order = create(:order, cvc: 1234) + assert order.valid? + end + + test "CVC should be at least 3 numbers but not exceed 4 (as american express has 4). Thus, 12345 will be invalid" do + order = create(:order, cvc: 12345) + assert order.invalid? + end + + + test "Order exp_month can only be 01 through 12, only valid if they represent the 12 month calendar year.So, 01 will be valid" do + order = create(:order, exp_month: 01) + assert order.valid? + end + + test "Order exp_month can only be 01 through 12, only valid if they represen the 12 month calendar year. 13 will be invalid" do + + end + + test "Orders that have a credit card that expires before the time of purchase. Will be invalid & possibly display a error message. Exp_Month: 12, Exp_Year:12, will be invalid " do + order = create(:order, exp_month:12, exp_year:12) + assert order.invalid? + end + + + test "Orders that have credit card number 12/20 expiration will be valid because its hasn't expired yet." do + order = create(:order, exp_month:12, exp_year:20) + assert order.valid? + + end + + + + # belongs_to :product + # belongs_to :user + # has_many :order_items + + + + # t.string "status", limit: 80 + # t.string "name" + # t.string "email" + # t.string "street_address" + # t.string "city" + # t.string "state" + # t.integer "zip" + # t.integer "phone", limit: 10 + # t.integer "user_id" + # t.integer "product_id" + # t.integer "cc_number" + # t.integer "exp_month" + # t.integer "exp_year" + # t.integer "cvc" + + + + + +end diff --git a/test/models/product_test.rb b/test/models/product_test.rb new file mode 100644 index 0000000000..4dfe45d64b --- /dev/null +++ b/test/models/product_test.rb @@ -0,0 +1,96 @@ +require 'test_helper' + +class ProductTest < ActiveSupport::TestCase +# rake test TEST=test/models/order_item_test.rb + +# Testing Checklist: + # start with validations + # Check custom methods in the model (dont do private) + # relatonships + +# let's pass an easy test! + test "the truth" do + assert true + end + + test "valid product" do + assert create(:product).valid? + end +##### testing product validations ##### + + # This test passes b/c of added validations. + test "Products must have a name, otherwise invalid." do + product = build(:product, name: nil) + assert product.invalid? + end + + # test "Adding a name to a product that wasn't valid because it lacked name. Will become valid, once assigned one" do + # product = create(:product, category: "fashion", name: nil) + # product.name = "Name Acquired" + # product.save + # assert(product.valid?) + # end + + # test "If a name is removed from product, product will then become invalid " do + # product = create(:product) + # assert(product.valid?) + # + # product.name = nil + # assert_not(product.valid?) + # end + + test "Products must have a price, otherwise invalid" do + product = build(:product, price: nil) + refute product.valid? + assert_not_nil product.errors[:price], "no validation error for the price present. " + end + +# # + test "product prices should not be a negative number" do + product = build(:product, price: -1 ) + assert product.invalid? + + end + + test "product prices should be greater than zero" do + product = build(:product, price: 0 ) + assert product.invalid? + end + + test "product prices should be a postive number. 1.00 is valid" do + product = build(:product, price: 1.00 ) + assert product.valid? + end + +# Commented out because to make validations for this one might caught merge conflicts. + # test "Product prices must be decimals. 2 will be invalid." do + # product = build(:product, price: 2) + # assert product.invalid? + # end + +##### testing product associations ##### + test "Products with a valid category will be valid. Valid only if category one of the following: minions, home decor, fashion, & personal care." do + product = create(:product, category: "fashion") + assert_not product.invalid? + end + +# not necessarily passing because we haven't written proper validations. We'd need to for it to pass. Partly this is logically taken care of because we only allow category to be determined via a drop down menu. + test "Products outside of valid category will be invalid." do + product = create(:product, category: "other") + assert product.invalid? + end + + test "A product must belong to a user. " do + product = build(:product, user: nil) + product.invalid? + end + + test "Products must have correct category, product is expected to be fashion." do + # default category: fashion /from factory. + product = build(:product) + fashion = build(:product) + + assert_equal(product.category, fashion.category) + end + +end diff --git a/test/models/review_test.rb b/test/models/review_test.rb new file mode 100644 index 0000000000..11aa5204f0 --- /dev/null +++ b/test/models/review_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class ReviewTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000000..82f61e0109 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/support/factory_girl.rb b/test/support/factory_girl.rb new file mode 100644 index 0000000000..83d27e86b2 --- /dev/null +++ b/test/support/factory_girl.rb @@ -0,0 +1,70 @@ +FactoryGirl.define do + + # product with a 'belongs_to' user + factory :product do + name "Magic Cape" + description "A cape like no other, for the undead" + price 10.00 + photo_url "Minions/Ghosts.png" + inventory 1 + category "fashion" || "minions" || "personal care" || "home decor" + user + + trait :no_inventory do + inventory 0 + end + trait :no_user do + user nil + end + end + + factory :user do + name "Michelle Obama" + # practicing with dependent attributes + email {"#{name.downcase}@example.com"} + street_address "2100 Bad Ass Drive" + city "Seattle" + state "WA" + zip 98122 + # limit 10 + phone 6023334455 + # create a trait where merchant is false or true. + # if true = they have something for sale. + merchant false + + trait :merchant_true do + merchant true + end + end + + factory :order do + # what does true mean again? and + # limit 80 + status true + name "Michelle Obama" + email {"#{name.downcase}@example.com"} + street_address "2100 Bad Ass Drive" + city "Seattle" + zip 98122 + # limit: 10 + phone 6023334455 + # eventually limited to 16 + cc_number 4444 + # should be not out of date + # limit 2 + exp_month 12 + # limit 2 + exp_year 17 + # limit 4 + cvc 444 + product + user + +# order without user + trait :order_without_user do + user nil + end + + + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 92e39b2d78..5f10ddf350 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,10 +1,45 @@ +require 'simplecov' +SimpleCov.start +# Rails.application.eager_load! + ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' +#add colors and make it more readable +require 'minitest/reporters' +# Things this goes here. should be in spec_helper_ we dont have +require 'support/factory_girl' + + class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all +#tell it to use the thing to make it more readable + MiniTest::Reporters.use! + # Add more helper methods to be used by all tests here... +# minitest-rails + include FactoryGirl::Syntax::Methods +#omniauth setup method + def setup + # Once you have enabled test mode, all requests + # to OmniAuth will be short circuited to use the mock authentication hash. + # A request to /auth/provider will redirect immediately to /auth/provider/callback. + + + OmniAuth.config.test_mode = true + + # The mock_auth configuration allows you to set per-provider (or default) authentication + # hashes to return during testing. + + + + OmniAuth.config.mock_auth[:github] = OmniAuth::AuthHash.new({ + provider: 'github', uid: '123545', info: { email: "a@b.com", name: "Ada" } + }) + + + end end