diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000..85ac0a6a5e Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 6db3c9a5bc..e422e0120d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,9 +7,13 @@ # Ignore bundler config. /.bundle +# Ignore the default SQLite database. +/db/*.sqlite3 +/db/*.sqlite3-journal + # Ignore all logfiles and tempfiles. /log/* !/log/.keep /tmp - .DS_Store +.env diff --git a/Gemfile b/Gemfile index c69f4ddde9..750cdec787 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,14 @@ source 'https://rubygems.org' -ruby '2.3.1' +gem 'has_scope' +# Foundation Rails Gem +gem 'foundation-rails' +# Required due to an incompatibility between TurboLinks and Foundation. +gem 'jquery-turbolinks' +gem 'awesome_print' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.2.6' -# Use postgresql as the database for Active Record -# gem 'pg', '~> 0.15' + # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets @@ -14,6 +18,8 @@ gem 'coffee-rails', '~> 4.1.0' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby +gem 'simplecov', :require => false, :group => :test + # Use jquery as the JavaScript library gem 'jquery-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks @@ -32,9 +38,19 @@ gem 'sdoc', '~> 0.4.0', group: :doc # Use Capistrano for deployment # gem 'capistrano-rails', group: :development +# OAuth gems +gem 'omniauth' +gem 'omniauth-github' + group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' + gem 'dotenv-rails' + gem 'better_errors' + gem 'binding_of_caller' + gem 'minitest-reporters' + # Use sqlite3 as the database for Active Record + gem 'sqlite3' end group :development do @@ -44,3 +60,7 @@ group :development do # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'spring' end +group :production do +gem 'pg' +gem 'rails_12factor' +end diff --git a/Gemfile.lock b/Gemfile.lock index 20975578b8..fe076ca487 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -36,11 +36,22 @@ 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) + babel-source (5.8.35) + babel-transpiler (0.7.0) + babel-source (>= 4.0, < 6) + execjs (~> 2.0) + 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 +59,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) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + foundation-rails (6.2.4.0) + railties (>= 3.1.0) + sass (>= 3.3.0, < 3.5) + sprockets-es6 (>= 0.9.0) + globalid (0.3.7) activesupport (>= 4.1.0) + has_scope (0.7.0) + actionpack (>= 4.1, < 5.1) + activesupport (>= 4.1, < 5.1) + 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) + jquery-turbolinks (2.1.0) + railties (>= 3.1.0) + turbolinks 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) + 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) rack (1.6.4) rack-test (0.6.3) rack (>= 1.0) @@ -97,40 +150,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) + simplecov (0.12.0) + docile (~> 1.1.0) + json (>= 1.8, < 3) + simplecov-html (~> 0.10.0) + simplecov-html (0.10.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-es6 (0.9.2) + babel-source (>= 5.8.11) + babel-transpiler + sprockets (>= 3.0.0) + 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,20 +213,31 @@ PLATFORMS ruby DEPENDENCIES + awesome_print + better_errors + binding_of_caller byebug coffee-rails (~> 4.1.0) + dotenv-rails + foundation-rails + has_scope jbuilder (~> 2.0) jquery-rails + jquery-turbolinks + minitest-reporters + omniauth + omniauth-github + pg rails (= 4.2.6) + rails_12factor sass-rails (~> 5.0) sdoc (~> 0.4.0) + simplecov spring + sqlite3 turbolinks uglifier (>= 1.3.0) web-console (~> 2.0) -RUBY VERSION - ruby 2.3.1p112 - BUNDLED WITH - 1.13.5 + 1.13.6 diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 0000000000..dd4e97e22e --- /dev/null +++ b/README.rdoc @@ -0,0 +1,28 @@ +== README + +This README would normally document whatever steps are necessary to get the +application up and running. + +Things you may want to cover: + +* Ruby version + +* System dependencies + +* Configuration + +* Database creation + +* Database initialization + +* How to run the test suite + +* Services (job queues, cache servers, search engines, etc.) + +* Deployment instructions + +* ... + + +Please feel free to use a different markup language if you do not plan to run +rake doc:app. diff --git a/app/assets/images/cart.png b/app/assets/images/cart.png new file mode 100644 index 0000000000..54859a5283 Binary files /dev/null and b/app/assets/images/cart.png differ diff --git a/app/assets/images/cute_uni.jpg b/app/assets/images/cute_uni.jpg new file mode 100644 index 0000000000..fb8e973c16 Binary files /dev/null and b/app/assets/images/cute_uni.jpg differ diff --git a/app/assets/images/default_uni.jpg b/app/assets/images/default_uni.jpg new file mode 100644 index 0000000000..d873f0c84a Binary files /dev/null and b/app/assets/images/default_uni.jpg differ diff --git a/app/assets/images/horn_magic_cookie.png b/app/assets/images/horn_magic_cookie.png new file mode 100644 index 0000000000..63d4f096ce Binary files /dev/null and b/app/assets/images/horn_magic_cookie.png differ diff --git a/app/assets/images/lucky_uni_shoe.jpg b/app/assets/images/lucky_uni_shoe.jpg new file mode 100644 index 0000000000..3f903e0e35 Binary files /dev/null and b/app/assets/images/lucky_uni_shoe.jpg differ diff --git a/app/assets/images/my_unicorn_necklace.png b/app/assets/images/my_unicorn_necklace.png new file mode 100644 index 0000000000..54e1173479 Binary files /dev/null and b/app/assets/images/my_unicorn_necklace.png differ diff --git a/app/assets/images/rating.png b/app/assets/images/rating.png new file mode 100644 index 0000000000..a341d0617b Binary files /dev/null and b/app/assets/images/rating.png differ diff --git a/app/assets/images/uni_ate_hm_tee.png b/app/assets/images/uni_ate_hm_tee.png new file mode 100644 index 0000000000..a8e25965d9 Binary files /dev/null and b/app/assets/images/uni_ate_hm_tee.png differ diff --git a/app/assets/images/uni_bed_spread.png b/app/assets/images/uni_bed_spread.png new file mode 100644 index 0000000000..3f9628034e Binary files /dev/null and b/app/assets/images/uni_bed_spread.png differ diff --git a/app/assets/images/uni_cake_tee.png b/app/assets/images/uni_cake_tee.png new file mode 100644 index 0000000000..e382bea2ab Binary files /dev/null and b/app/assets/images/uni_cake_tee.png differ diff --git a/app/assets/images/uni_chair.png b/app/assets/images/uni_chair.png new file mode 100644 index 0000000000..50177e3fb4 Binary files /dev/null and b/app/assets/images/uni_chair.png differ diff --git a/app/assets/images/uni_flats.png b/app/assets/images/uni_flats.png new file mode 100644 index 0000000000..0473e14105 Binary files /dev/null and b/app/assets/images/uni_flats.png differ diff --git a/app/assets/images/uni_horn_necklace.png b/app/assets/images/uni_horn_necklace.png new file mode 100644 index 0000000000..6b71547a2f Binary files /dev/null and b/app/assets/images/uni_horn_necklace.png differ diff --git a/app/assets/images/uni_light_up_slippers.png b/app/assets/images/uni_light_up_slippers.png new file mode 100644 index 0000000000..923a1ffe4e Binary files /dev/null and b/app/assets/images/uni_light_up_slippers.png differ diff --git a/app/assets/images/uni_old_book_art.png b/app/assets/images/uni_old_book_art.png new file mode 100644 index 0000000000..68095ff124 Binary files /dev/null and b/app/assets/images/uni_old_book_art.png differ diff --git a/app/assets/images/uni_pillow.png b/app/assets/images/uni_pillow.png new file mode 100644 index 0000000000..8325616a23 Binary files /dev/null and b/app/assets/images/uni_pillow.png differ diff --git a/app/assets/images/uni_platforms.png b/app/assets/images/uni_platforms.png new file mode 100644 index 0000000000..2a222ec13e Binary files /dev/null and b/app/assets/images/uni_platforms.png differ diff --git a/app/assets/images/uni_pllw.png b/app/assets/images/uni_pllw.png new file mode 100644 index 0000000000..4cf41be47e Binary files /dev/null and b/app/assets/images/uni_pllw.png differ diff --git a/app/assets/images/uni_poo.png b/app/assets/images/uni_poo.png new file mode 100644 index 0000000000..9f2c12609c Binary files /dev/null and b/app/assets/images/uni_poo.png differ diff --git a/app/assets/images/uni_puke_mug.png b/app/assets/images/uni_puke_mug.png new file mode 100644 index 0000000000..1c7aef4d02 Binary files /dev/null and b/app/assets/images/uni_puke_mug.png differ diff --git a/app/assets/images/uni_ring.png b/app/assets/images/uni_ring.png new file mode 100644 index 0000000000..eaa7bd1f22 Binary files /dev/null and b/app/assets/images/uni_ring.png differ diff --git a/app/assets/images/uni_steampunk_necklace.png b/app/assets/images/uni_steampunk_necklace.png new file mode 100644 index 0000000000..77f6ed8608 Binary files /dev/null and b/app/assets/images/uni_steampunk_necklace.png differ diff --git a/app/assets/images/uni_wall_art.png b/app/assets/images/uni_wall_art.png new file mode 100644 index 0000000000..4b8bc530b4 Binary files /dev/null and b/app/assets/images/uni_wall_art.png differ diff --git a/app/assets/images/uni_wall_mount.png b/app/assets/images/uni_wall_mount.png new file mode 100644 index 0000000000..7f22813392 Binary files /dev/null and b/app/assets/images/uni_wall_mount.png differ diff --git a/app/assets/images/unicorn_cake_topper.png b/app/assets/images/unicorn_cake_topper.png new file mode 100644 index 0000000000..7f4fbb69de Binary files /dev/null and b/app/assets/images/unicorn_cake_topper.png differ diff --git a/app/assets/images/unicorn_farts.png b/app/assets/images/unicorn_farts.png new file mode 100644 index 0000000000..c9f61774ba Binary files /dev/null and b/app/assets/images/unicorn_farts.png differ diff --git a/app/assets/images/unicorn_liqueur.png b/app/assets/images/unicorn_liqueur.png new file mode 100644 index 0000000000..a6c5d111ba Binary files /dev/null and b/app/assets/images/unicorn_liqueur.png differ diff --git a/app/assets/images/unicorn_merchant.jpg b/app/assets/images/unicorn_merchant.jpg new file mode 100644 index 0000000000..9c2481daad Binary files /dev/null and b/app/assets/images/unicorn_merchant.jpg differ diff --git a/app/assets/images/unilogo.png b/app/assets/images/unilogo.png new file mode 100644 index 0000000000..668861880d Binary files /dev/null and b/app/assets/images/unilogo.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e07c5a830f..038d8d7ecc 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -12,5 +12,15 @@ // //= require jquery //= require jquery_ujs +//= require foundation //= require turbolinks //= require_tree . + +$(function(){ $(document).foundation(); }); + +//= require foundation +$(document).foundation(); + +$(document).on('turbolinks:load', function() { + $(function(){ $(document).foundation(); }); +}); diff --git a/app/assets/javascripts/carts.coffee b/app/assets/javascripts/carts.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/carts.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/categories.coffee b/app/assets/javascripts/categories.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/categories.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/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/merchants.coffee b/app/assets/javascripts/merchants.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/merchants.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/orderitems.coffee b/app/assets/javascripts/orderitems.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/orderitems.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/stores.coffee b/app/assets/javascripts/stores.coffee new file mode 100644 index 0000000000..24f83d18bb --- /dev/null +++ b/app/assets/javascripts/stores.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/_settings.scss b/app/assets/stylesheets/_settings.scss new file mode 100644 index 0000000000..703053eb9d --- /dev/null +++ b/app/assets/stylesheets/_settings.scss @@ -0,0 +1,574 @@ +// Foundation for Sites Settings +// ----------------------------- +// +// Table of Contents: +// +// 1. Global +// 2. Breakpoints +// 3. The Grid +// 4. Base Typography +// 5. Typography Helpers +// 6. Abide +// 7. Accordion +// 8. Accordion Menu +// 9. Badge +// 10. Breadcrumbs +// 11. Button +// 12. Button Group +// 13. Callout +// 14. Close Button +// 15. Drilldown +// 16. Dropdown +// 17. Dropdown Menu +// 18. Flex Video +// 19. Forms +// 20. Label +// 21. Media Object +// 22. Menu +// 23. Meter +// 24. Off-canvas +// 25. Orbit +// 26. Pagination +// 27. Progress Bar +// 28. Reveal +// 29. Slider +// 30. Switch +// 31. Table +// 32. Tabs +// 33. Thumbnail +// 34. Title Bar +// 35. Tooltip +// 36. Top Bar + +@import 'util/util'; + +// 1. Global +// --------- + +$global-font-size: 100%; +$global-width: rem-calc(1200); +$global-lineheight: 1.5; +$foundation-palette: ( + primary: #2199e8, + secondary: #777, + success: #3adb76, + warning: #ffae00, + alert: #ec5840, +); +$light-gray: #e6e6e6; +$medium-gray: #cacaca; +$dark-gray: #8a8a8a; +$black: #0a0a0a; +$white: #fefefe; +$body-background: $white; +$body-font-color: $black; +$body-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-antialiased: true; +$global-margin: 1rem; +$global-padding: 1rem; +$global-weight-normal: normal; +$global-weight-bold: bold; +$global-radius: 0; +$global-text-direction: ltr; +$global-flexbox: false; +$print-transparent-backgrounds: true; + +@include add-foundation-colors; + +// 2. Breakpoints +// -------------- + +$breakpoints: ( + small: 0, + medium: 640px, + large: 1024px, + xlarge: 1200px, + xxlarge: 1440px, +); +$breakpoint-classes: (small medium large); + +// 3. The Grid +// ----------- + +$grid-row-width: $global-width; +$grid-column-count: 12; +$grid-column-gutter: ( + small: 20px, + medium: 30px, +); +$grid-column-align-edge: true; +$block-grid-max: 8; + +// 4. Base Typography +// ------------------ + +$header-font-family: $body-font-family; +$header-font-weight: $global-weight-normal; +$header-font-style: normal; +$font-family-monospace: Consolas, 'Liberation Mono', Courier, monospace; +$header-sizes: ( + small: ( + 'h1': 24, + 'h2': 20, + 'h3': 19, + 'h4': 18, + 'h5': 17, + 'h6': 16, + ), + medium: ( + 'h1': 48, + 'h2': 40, + 'h3': 31, + 'h4': 25, + 'h5': 20, + 'h6': 16, + ), +); +$header-color: inherit; +$header-lineheight: 1.4; +$header-margin-bottom: 0.5rem; +$header-text-rendering: optimizeLegibility; +$small-font-size: 80%; +$header-small-font-color: $medium-gray; +$paragraph-lineheight: 1.6; +$paragraph-margin-bottom: 1rem; +$paragraph-text-rendering: optimizeLegibility; +$code-color: $black; +$code-font-family: $font-family-monospace; +$code-font-weight: $global-weight-normal; +$code-background: $light-gray; +$code-border: 1px solid $medium-gray; +$code-padding: rem-calc(2 5 1); +$anchor-color: $primary-color; +$anchor-color-hover: scale-color($anchor-color, $lightness: -14%); +$anchor-text-decoration: none; +$anchor-text-decoration-hover: none; +$hr-width: $global-width; +$hr-border: 1px solid $medium-gray; +$hr-margin: rem-calc(20) auto; +$list-lineheight: $paragraph-lineheight; +$list-margin-bottom: $paragraph-margin-bottom; +$list-style-type: disc; +$list-style-position: outside; +$list-side-margin: 1.25rem; +$list-nested-side-margin: 1.25rem; +$defnlist-margin-bottom: 1rem; +$defnlist-term-weight: $global-weight-bold; +$defnlist-term-margin-bottom: 0.3rem; +$blockquote-color: $dark-gray; +$blockquote-padding: rem-calc(9 20 0 19); +$blockquote-border: 1px solid $medium-gray; +$cite-font-size: rem-calc(13); +$cite-color: $dark-gray; +$keystroke-font: $font-family-monospace; +$keystroke-color: $black; +$keystroke-background: $light-gray; +$keystroke-padding: rem-calc(2 4 0); +$keystroke-radius: $global-radius; +$abbr-underline: 1px dotted $black; + +// 5. Typography Helpers +// --------------------- + +$lead-font-size: $global-font-size * 1.25; +$lead-lineheight: 1.6; +$subheader-lineheight: 1.4; +$subheader-color: $dark-gray; +$subheader-font-weight: $global-weight-normal; +$subheader-margin-top: 0.2rem; +$subheader-margin-bottom: 0.5rem; +$stat-font-size: 2.5rem; + +// 6. Abide +// -------- + +$abide-inputs: true; +$abide-labels: true; +$input-background-invalid: map-get($foundation-palette, alert); +$form-label-color-invalid: map-get($foundation-palette, alert); +$input-error-color: map-get($foundation-palette, alert); +$input-error-font-size: rem-calc(12); +$input-error-font-weight: $global-weight-bold; + +// 7. Accordion +// ------------ + +$accordion-background: $white; +$accordion-plusminus: true; +$accordion-item-color: foreground($accordion-background, $primary-color); +$accordion-item-background-hover: $light-gray; +$accordion-item-padding: 1.25rem 1rem; +$accordion-content-background: $white; +$accordion-content-border: 1px solid $light-gray; +$accordion-content-color: foreground($accordion-content-background, $body-font-color); +$accordion-content-padding: 1rem; + +// 8. Accordion Menu +// ----------------- + +$accordionmenu-arrows: true; +$accordionmenu-arrow-color: $primary-color; + +// 9. Badge +// -------- + +$badge-background: $primary-color; +$badge-color: foreground($badge-background); +$badge-padding: 0.3em; +$badge-minwidth: 2.1em; +$badge-font-size: 0.6rem; + +// 10. Breadcrumbs +// --------------- + +$breadcrumbs-margin: 0 0 $global-margin 0; +$breadcrumbs-item-font-size: rem-calc(11); +$breadcrumbs-item-color: $primary-color; +$breadcrumbs-item-color-current: $black; +$breadcrumbs-item-color-disabled: $medium-gray; +$breadcrumbs-item-margin: 0.75rem; +$breadcrumbs-item-uppercase: true; +$breadcrumbs-item-slash: true; + +// 11. Button +// ---------- + +$button-padding: 0.85em 1em; +$button-margin: 0 0 $global-margin 0; +$button-fill: solid; +$button-background: $primary-color; +$button-background-hover: scale-color($button-background, $lightness: -15%); +$button-color: $white; +$button-color-alt: $black; +$button-radius: $global-radius; +$button-sizes: ( + tiny: 0.6rem, + small: 0.75rem, + default: 0.9rem, + large: 1.25rem, +); +$button-opacity-disabled: 0.25; +$button-background-hover-lightness: -20%; +$button-hollow-hover-lightness: -50%; + +// 12. Button Group +// ---------------- + +$buttongroup-margin: 1rem; +$buttongroup-spacing: 1px; +$buttongroup-child-selector: '.button'; +$buttongroup-expand-max: 6; + +// 13. Callout +// ----------- + +$callout-background: $white; +$callout-background-fade: 85%; +$callout-border: 1px solid rgba($black, 0.25); +$callout-margin: 0 0 1rem 0; +$callout-padding: 1rem; +$callout-font-color: $body-font-color; +$callout-font-color-alt: $body-background; +$callout-radius: $global-radius; +$callout-link-tint: 30%; + +// 14. Close Button +// ---------------- + +$closebutton-position: right top; +$closebutton-offset-horizontal: 1rem; +$closebutton-offset-vertical: 0.5rem; +$closebutton-size: 2em; +$closebutton-lineheight: 1; +$closebutton-color: $dark-gray; +$closebutton-color-hover: $black; + +// 15. Drilldown +// ------------- + +$drilldown-transition: transform 0.15s linear; +$drilldown-arrows: true; +$drilldown-arrow-color: $primary-color; +$drilldown-background: $white; + +// 16. Dropdown +// ------------ + +$dropdown-padding: 1rem; +$dropdown-border: 1px solid $medium-gray; +$dropdown-font-size: 1rem; +$dropdown-width: 300px; +$dropdown-radius: $global-radius; +$dropdown-sizes: ( + tiny: 100px, + small: 200px, + large: 400px, +); + +// 17. Dropdown Menu +// ----------------- + +$dropdownmenu-arrows: true; +$dropdownmenu-arrow-color: $anchor-color; +$dropdownmenu-min-width: 200px; +$dropdownmenu-background: $white; +$dropdownmenu-border: 1px solid $medium-gray; + +// 18. Flex Video +// -------------- + +$flexvideo-margin-bottom: rem-calc(16); +$flexvideo-ratio: 4 by 3; +$flexvideo-ratio-widescreen: 16 by 9; + +// 19. Forms +// --------- + +$fieldset-border: 1px solid $medium-gray; +$fieldset-padding: rem-calc(20); +$fieldset-margin: rem-calc(18 0); +$legend-padding: rem-calc(0 3); +$form-spacing: rem-calc(16); +$helptext-color: $black; +$helptext-font-size: rem-calc(13); +$helptext-font-style: italic; +$input-prefix-color: $black; +$input-prefix-background: $light-gray; +$input-prefix-border: 1px solid $medium-gray; +$input-prefix-padding: 1rem; +$form-label-color: $black; +$form-label-font-size: rem-calc(14); +$form-label-font-weight: $global-weight-normal; +$form-label-line-height: 1.8; +$select-background: $white; +$select-triangle-color: $dark-gray; +$select-radius: $global-radius; +$input-color: $black; +$input-placeholder-color: $medium-gray; +$input-font-family: inherit; +$input-font-size: rem-calc(16); +$input-background: $white; +$input-background-focus: $white; +$input-background-disabled: $light-gray; +$input-border: 1px solid $medium-gray; +$input-border-focus: 1px solid $dark-gray; +$input-shadow: inset 0 1px 2px rgba($black, 0.1); +$input-shadow-focus: 0 0 5px $medium-gray; +$input-cursor-disabled: not-allowed; +$input-transition: box-shadow 0.5s, border-color 0.25s ease-in-out; +$input-number-spinners: true; +$input-radius: $global-radius; +$button-radius: $global-radius; + +// 20. Label +// --------- + +$label-background: $primary-color; +$label-color: foreground($label-background); +$label-font-size: 0.8rem; +$label-padding: 0.33333rem 0.5rem; +$label-radius: $global-radius; + +// 21. Media Object +// ---------------- + +$mediaobject-margin-bottom: $global-margin; +$mediaobject-section-padding: $global-padding; +$mediaobject-image-width-stacked: 100%; + +// 22. Menu +// -------- + +$menu-margin: 0; +$menu-margin-nested: 1rem; +$menu-item-padding: 0.7rem 1rem; +$menu-item-color-active: $white; +$menu-item-background-active: map-get($foundation-palette, primary); +$menu-icon-spacing: 0.25rem; + +// 23. Meter +// --------- + +$meter-height: 1rem; +$meter-radius: $global-radius; +$meter-background: $medium-gray; +$meter-fill-good: $success-color; +$meter-fill-medium: $warning-color; +$meter-fill-bad: $alert-color; + +// 24. Off-canvas +// -------------- + +$offcanvas-size: 250px; +$offcanvas-background: $light-gray; +$offcanvas-zindex: -1; +$offcanvas-transition-length: 0.5s; +$offcanvas-transition-timing: ease; +$offcanvas-fixed-reveal: true; +$offcanvas-exit-background: rgba($white, 0.25); +$maincontent-class: 'off-canvas-content'; +$maincontent-shadow: 0 0 10px rgba($black, 0.5); + +// 25. Orbit +// --------- + +$orbit-bullet-background: $medium-gray; +$orbit-bullet-background-active: $dark-gray; +$orbit-bullet-diameter: 1.2rem; +$orbit-bullet-margin: 0.1rem; +$orbit-bullet-margin-top: 0.8rem; +$orbit-bullet-margin-bottom: 0.8rem; +$orbit-caption-background: rgba($black, 0.5); +$orbit-caption-padding: 1rem; +$orbit-control-background-hover: rgba($black, 0.5); +$orbit-control-padding: 1rem; +$orbit-control-zindex: 10; + +// 26. Pagination +// -------------- + +$pagination-font-size: rem-calc(14); +$pagination-margin-bottom: $global-margin; +$pagination-item-color: $black; +$pagination-item-padding: rem-calc(3 10); +$pagination-item-spacing: rem-calc(1); +$pagination-radius: $global-radius; +$pagination-item-background-hover: $light-gray; +$pagination-item-background-current: $primary-color; +$pagination-item-color-current: foreground($pagination-item-background-current); +$pagination-item-color-disabled: $medium-gray; +$pagination-ellipsis-color: $black; +$pagination-mobile-items: false; +$pagination-mobile-current-item: false; +$pagination-arrows: true; + +// 27. Progress Bar +// ---------------- + +$progress-height: 1rem; +$progress-background: $medium-gray; +$progress-margin-bottom: $global-margin; +$progress-meter-background: $primary-color; +$progress-radius: $global-radius; + +// 28. Reveal +// ---------- + +$reveal-background: $white; +$reveal-width: 600px; +$reveal-max-width: $global-width; +$reveal-padding: $global-padding; +$reveal-border: 1px solid $medium-gray; +$reveal-radius: $global-radius; +$reveal-zindex: 1005; +$reveal-overlay-background: rgba($black, 0.45); + +// 29. Slider +// ---------- + +$slider-width-vertical: 0.5rem; +$slider-transition: all 0.2s ease-in-out; +$slider-height: 0.5rem; +$slider-background: $light-gray; +$slider-fill-background: $medium-gray; +$slider-handle-height: 1.4rem; +$slider-handle-width: 1.4rem; +$slider-handle-background: $primary-color; +$slider-opacity-disabled: 0.25; +$slider-radius: $global-radius; + +// 30. Switch +// ---------- + +$switch-background: $medium-gray; +$switch-background-active: $primary-color; +$switch-height: 2rem; +$switch-height-tiny: 1.5rem; +$switch-height-small: 1.75rem; +$switch-height-large: 2.5rem; +$switch-radius: $global-radius; +$switch-margin: $global-margin; +$switch-paddle-background: $white; +$switch-paddle-offset: 0.25rem; +$switch-paddle-radius: $global-radius; +$switch-paddle-transition: all 0.25s ease-out; + +// 31. Table +// --------- + +$table-background: $white; +$table-color-scale: 5%; +$table-border: 1px solid smart-scale($table-background, $table-color-scale); +$table-padding: rem-calc(8 10 10); +$table-hover-scale: 2%; +$table-row-hover: darken($table-background, $table-hover-scale); +$table-row-stripe-hover: darken($table-background, $table-color-scale + $table-hover-scale); +$table-striped-background: smart-scale($table-background, $table-color-scale); +$table-stripe: even; +$table-head-background: smart-scale($table-background, $table-color-scale / 2); +$table-head-row-hover: darken($table-head-background, $table-hover-scale); +$table-foot-background: smart-scale($table-background, $table-color-scale); +$table-foot-row-hover: darken($table-foot-background, $table-hover-scale); +$table-head-font-color: $body-font-color; +$table-foot-font-color: $body-font-color; +$show-header-for-stacked: false; + +// 32. Tabs +// -------- + +$tab-margin: 0; +$tab-background: $white; +$tab-background-active: $light-gray; +$tab-item-font-size: rem-calc(12); +$tab-item-background-hover: $white; +$tab-item-padding: 1.25rem 1.5rem; +$tab-expand-max: 6; +$tab-content-background: $white; +$tab-content-border: $light-gray; +$tab-content-color: foreground($tab-background, $primary-color); +$tab-content-padding: 1rem; + +// 33. Thumbnail +// ------------- + +$thumbnail-border: solid 4px $white; +$thumbnail-margin-bottom: $global-margin; +$thumbnail-shadow: 0 0 0 1px rgba($black, 0.2); +$thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5); +$thumbnail-transition: box-shadow 200ms ease-out; +$thumbnail-radius: $global-radius; + +// 34. Title Bar +// ------------- + +$titlebar-background: $black; +$titlebar-color: $white; +$titlebar-padding: 0.5rem; +$titlebar-text-font-weight: bold; +$titlebar-icon-color: $white; +$titlebar-icon-color-hover: $medium-gray; +$titlebar-icon-spacing: 0.25rem; + +// 35. Tooltip +// ----------- + +$has-tip-font-weight: $global-weight-bold; +$has-tip-border-bottom: dotted 1px $dark-gray; +$tooltip-background-color: $black; +$tooltip-color: $white; +$tooltip-padding: 0.75rem; +$tooltip-font-size: $small-font-size; +$tooltip-pip-width: 0.75rem; +$tooltip-pip-height: $tooltip-pip-width * 0.866; +$tooltip-radius: $global-radius; + +// 36. Top Bar +// ----------- + +$topbar-padding: 0.5rem; +$topbar-background: $light-gray; +$topbar-submenu-background: $topbar-background; +$topbar-title-spacing: 1rem; +$topbar-input-width: 200px; +$topbar-unstack-breakpoint: medium; + diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css deleted file mode 100644 index f9cd5b3483..0000000000 --- a/app/assets/stylesheets/application.css +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This is a manifest file that'll be compiled into application.css, which will include all the files - * listed below. - * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, - * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. - * - * You're free to add application-wide styles to this file and they'll appear at the bottom of the - * compiled file so the styles you add here take precedence over styles defined in any styles - * defined in the other CSS/SCSS files in this directory. It is generally better to create a new - * file per style scope. - * - *= require_tree . - *= require_self - */ diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss new file mode 100644 index 0000000000..9ee2bc8ef9 --- /dev/null +++ b/app/assets/stylesheets/application.scss @@ -0,0 +1,115 @@ + + // * This is a manifest file that'll be compiled into application.css, which will include all the files + // * listed below. + // * + // * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + // * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + // * + // * You're free to add application-wide styles to this file and they'll appear at the bottom of the + // * compiled file so the styles you add here take precedence over styles defined in any styles + // * defined in the other CSS/SCSS files in this directory. It is generally better to create a new + // * file per style scope. + // * + // *= require_tree . + // *= require_self + // *= require foundation_and_overrides + + +// import google fonts +@import url('https://fonts.googleapis.com/css?family=Mystery+Quest|Numans'); + +// Font variables to use in css +$display-font: 'Mystery Quest', cursive; +$body-font: 'Numans', sans-serif; + +body { + font-family: $body-font; +} + +header * { + font-family: $display-font; +} + +h1, h2, h3, h4 { + font-family: $body-font; +} + +.links { + margin: 5%; +} + +h1 { + text-align: center; +} + +.pg-title { + margin: 5%; + text-align: center; +} + +.product-row { + margin: 2%; +} + + +.logo { + width: 70%; +} + +header h1 { + font-size: 4rem; +} + +.pg-title { + margin: 5% 0 5% 0; +} + + +.product-tile { + display: inline-block; + text-align: center; + margin: 2.5%; + border: 1px solid lightgray; + height: 300px; + width: 300px; + padding-top: 3%; +} + +.product-tile img { + padding-top: 30px; + max-height: 180px; +} + + +.gallery { + text-align: center; +} + +.quantity { + text-align: center; +} + +.quantity-box { + width: 30%; +} + +.see-cart { + display: block; + padding-top: 2%; +} + + +footer { + border-top: 1px solid grey; + margin-top: 10%; + text-align: center; + background-color: mintcream; +} + +footer p { + margin-top: 1%; +} + +tr { + text-align: center; +} diff --git a/app/assets/stylesheets/carts.scss b/app/assets/stylesheets/carts.scss new file mode 100644 index 0000000000..62647c9dde --- /dev/null +++ b/app/assets/stylesheets/carts.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the carts 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/categories.scss b/app/assets/stylesheets/categories.scss new file mode 100644 index 0000000000..ef1657f8c9 --- /dev/null +++ b/app/assets/stylesheets/categories.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the categories 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/foundation_and_overrides.scss b/app/assets/stylesheets/foundation_and_overrides.scss new file mode 100644 index 0000000000..458eb4fafb --- /dev/null +++ b/app/assets/stylesheets/foundation_and_overrides.scss @@ -0,0 +1,52 @@ +@charset 'utf-8'; + +@import 'settings'; +@import 'foundation'; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +@import 'motion-ui/motion-ui'; + +// We include everything by default. To slim your CSS, remove components you don't use. + +@include foundation-global-styles; +@include foundation-grid; +@include foundation-typography; +@include foundation-button; +@include foundation-forms; +@include foundation-visibility-classes; +@include foundation-float-classes; +@include foundation-accordion; +@include foundation-accordion-menu; +@include foundation-badge; +@include foundation-breadcrumbs; +@include foundation-button-group; +@include foundation-callout; +@include foundation-close-button; +@include foundation-drilldown-menu; +@include foundation-dropdown; +@include foundation-dropdown-menu; +@include foundation-flex-video; +@include foundation-label; +@include foundation-media-object; +@include foundation-menu; +@include foundation-menu-icon; +@include foundation-off-canvas; +@include foundation-orbit; +@include foundation-pagination; +@include foundation-progress-bar; +@include foundation-slider; +@include foundation-sticky; +@include foundation-reveal; +@include foundation-switch; +@include foundation-table; +@include foundation-tabs; +@include foundation-thumbnail; +@include foundation-title-bar; +@include foundation-tooltip; +@include foundation-top-bar; + +// If you'd like to include motion-ui the foundation-rails gem comes prepackaged with it, uncomment the 3 @imports, if you are not using the gem you need to install the motion-ui sass package. +// +@include motion-ui-transitions; +@include motion-ui-animations; diff --git a/app/assets/stylesheets/homepages.scss b/app/assets/stylesheets/homepages.scss new file mode 100644 index 0000000000..8a2a8eaabe --- /dev/null +++ b/app/assets/stylesheets/homepages.scss @@ -0,0 +1,18 @@ +// 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/ + +img.orbit_img { + display:block; + margin: 0 auto; +} + +.orbit-previous, .orbit-next { + color: black; +} + +.orbit-caption { + background-color: white; + color: black; + text-align: center; +} diff --git a/app/assets/stylesheets/merchants.scss b/app/assets/stylesheets/merchants.scss new file mode 100644 index 0000000000..2327c00afe --- /dev/null +++ b/app/assets/stylesheets/merchants.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the merchants 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/orderitems.scss b/app/assets/stylesheets/orderitems.scss new file mode 100644 index 0000000000..3ae284dd37 --- /dev/null +++ b/app/assets/stylesheets/orderitems.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the orderitems 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..0d38760272 --- /dev/null +++ b/app/assets/stylesheets/orders.scss @@ -0,0 +1,17 @@ +// 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/ + + +.order { + display: inline-block; +} + +#order_sum { + margin: 1% auto; + border: 1px solid black; +} + +.center { + text-align: center; +} diff --git a/app/assets/stylesheets/products.scss b/app/assets/stylesheets/products.scss new file mode 100644 index 0000000000..bb4a918289 --- /dev/null +++ b/app/assets/stylesheets/products.scss @@ -0,0 +1,12 @@ +// 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/ + +#description, img { + display: inline-block; +} + +#review { + border-bottom: 1px solid black; + margin-top: 1%; +} 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/stores.scss b/app/assets/stylesheets/stores.scss new file mode 100644 index 0000000000..02d6cc9224 --- /dev/null +++ b/app/assets/stylesheets/stores.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Stores 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..4975de10ab 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,4 +2,32 @@ 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 + + # this allow us to block guests from certain pages: + helper_method :current_user + helper_method :active_products + + def active_products + @products = [] + Product.all.each do |p| + if p.retired == false + @products << p + end + end + return @products + end + + + # if @current_user is not set then Merchant.find_by(id) will set the current_user + def current_user + @current_user ||= Merchant.find_by(id: session[:user_id]) if session[:user_id] + end + private + def require_merchant + unless current_user + flash[:notice] = "You must be logged in to access merchant section" + redirect_to homepages_index_path + end + end + end diff --git a/app/controllers/carts_controller.rb b/app/controllers/carts_controller.rb new file mode 100644 index 0000000000..375a5f65f4 --- /dev/null +++ b/app/controllers/carts_controller.rb @@ -0,0 +1,79 @@ +class CartsController < ApplicationController + def index + begin + if session[:order] + @order = Order.find(session[:order]) + if @order.update_prices? + flash[:notice] = "Some of your order items have changed in price and have been updated. Please review your order and press 'Check out' or continue shopping." + redirect_to carts_index_path + end + end + rescue ActiveRecord::RecordNotFound + session[:order] = nil + flash[:notice] = "An error occurred and your cart could not be found. Your cart has been reset so you can continue shopping." + redirect_to carts_index_path + end + end + + def edit + begin + if session[:order] + @order = Order.find(session[:order]) + if @order.remove_backordered? + if !Order.find_by(id: session[:order]) + session[:order] = nil + end + flash[:notice] = "Some of your order items are no longer in stock. The backordered items were removed from your order. Please review your order and press 'Check out' or continue shopping." + redirect_to carts_index_path + elsif @order.update_prices? + flash[:notice] = "Some of your order items have changed in price and have been updated. Please review your order and press 'Check out' or continue shopping." + redirect_to carts_index_path + end + else + flash[:notice] = "Your cart is empty! Please add something to your cart before you check out." + redirect_to carts_index_path + end + rescue ActiveRecord::RecordNotFound + session[:order] = nil + flash[:notice] = "An error occurred and your cart could not be found. Your cart has been reset so you can continue shopping." + redirect_to carts_index_path + end + end + + def update + begin + if session[:order] + @order = Order.find(session[:order]) + @order.assign_attributes(order_params) + @order.assign_attributes(status: "paid", placed_at: DateTime.now) + if @order.save + @order.update_stock + session[:order] = nil + else + render :edit, :status => :error + end + else + flash[:notice] = "Sorry, your cart could not be found. Please try again." + redirect_to carts_index_path + end + rescue ActiveRecord::RecordNotFound + session[:order] = nil + flash[:notice] = "An error occurred and your cart could not be found. Your cart has been reset so you can continue shopping." + redirect_to carts_index_path + end + end + + private + + def order_params + + filtered = params.require(:order).permit(:name, :address, :email, :city, :state, :zip, :card_name, :card_num, :cvv, :billing_zip, :expiry) + base_date = DateTime.new(filtered['expiry(1i)'].to_i, filtered['expiry(2i)'].to_i) + filtered.delete('expiry(3i)') + filtered.delete('expiry(2i)') + filtered.delete('expiry(1i)') + filtered[:expiry] = base_date.end_of_month + return filtered + end + +end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb new file mode 100644 index 0000000000..daffb17427 --- /dev/null +++ b/app/controllers/categories_controller.rb @@ -0,0 +1,45 @@ +class CategoriesController < ApplicationController + before_action :require_merchant, only: [:new, :create] + before_action :find_merchant, only: [:new, :edit] + + + + def index + @categories = Category.all + end + + def new + @category = Category.new + end + + def create + @category.name = params[:category][:name] + @category.save + redirect_to product_edit_path + end + + def edit + + end + + def update + + end + + def show + begin + @category = Category.find(params[:id].to_i) + @products = active_products.select {|product| product.category_ids.include? (@category.id)} + rescue ActiveRecord::RecordNotFound + render :file => 'public/404.html', :status => :not_found + end + end + + def destroy + end + private + def find_merchant + @merchant = Merchant.find_by(id: session[:user_id].to_i) + end + +end diff --git a/app/controllers/homepages_controller.rb b/app/controllers/homepages_controller.rb new file mode 100644 index 0000000000..1896e54d3b --- /dev/null +++ b/app/controllers/homepages_controller.rb @@ -0,0 +1,9 @@ +class HomepagesController < ApplicationController + def index + @categories = Category.all + end + + def show + @products = Product.all + end +end diff --git a/app/controllers/merchants_controller.rb b/app/controllers/merchants_controller.rb new file mode 100644 index 0000000000..ccbd52802b --- /dev/null +++ b/app/controllers/merchants_controller.rb @@ -0,0 +1,36 @@ +class MerchantsController < ApplicationController + before_action :find_merchant, except: [:new, :create] + before_action :require_merchant + + def index + + end + + def new + + end + + def create + + end + + def edit + + end + + def update + + @merchant.displayname = params[:merchant][:displayname] + @merchant.location = params[:merchant][:location] + @merchant.phone = params[:merchant][:phone] + @merchant.photo = params[:merchant][:photo] + @merchant.save + redirect_to merchants_index_path(@merchant.id) + end + + private + + def find_merchant + @merchant = Merchant.find_by(id: session[:user_id].to_i) # Bug fix: added the id: to the inside of this statement + end +end diff --git a/app/controllers/orderitems_controller.rb b/app/controllers/orderitems_controller.rb new file mode 100644 index 0000000000..2b68ecb575 --- /dev/null +++ b/app/controllers/orderitems_controller.rb @@ -0,0 +1,97 @@ +class OrderitemsController < ApplicationController + def create + begin + if session[:order] + order = Order.find_by(id: session[:order]) + else + order = Order.new(status: 'pending') + end + + if order + if params[:add_to_cart][:quantity].to_i <= Product.find(params[:product_id]).stock + orderitem = Orderitem.new(quantity: params[:add_to_cart][:quantity], product_id: params[:product_id], price: Product.find(params[:product_id]).price, status: 'pending') + order.orderitems << orderitem + if !order.save || !orderitem.save + flash[:notice] = "There was an error adding the item to your cart. Please try again." + else + session[:order] = order.id + flash[:notice] = "Item added to cart! Quantity: #{params[:add_to_cart][:quantity]}" + end + else + flash[:notice] = "Sorry, you cannot add that many items to your cart because your cart would exceed available stock." + end + else + session[:order] = nil + flash[:notice] = "The item was not added because your cart could not be found. Your cart has now been reset; please try adding the item again." + end + redirect_to products_show_path(params[:product_id]) + rescue ActiveRecord::RecordNotFound + flash[:notice] = "Sorry, that item could not be found. Please shop our other unicorn products." + redirect_to categories_index_path + end + end + + # This is getting to be a fat controller. Should move to model if time permits. + def update + begin + orderitem = Orderitem.find(params[:id]) + if params[:add_to_cart] # From item page - increase # of items in cart + if params[:add_to_cart][:quantity].to_i <= orderitem.product.stock - orderitem.quantity + orderitem.update(quantity: orderitem.quantity += params[:add_to_cart][:quantity].to_i) + flash[:notice] = "Item added to cart! Total quantity: #{orderitem.quantity}" + redirect_to products_show_path(orderitem.product) + else + flash[:notice] = "Sorry, you cannot add that many items to your cart because your cart would exceed available stock. Your cart already contains #{orderitem.quantity} of this item." + redirect_to products_show_path(orderitem.product) + end + elsif params[:change_quantity] # From cart page - reset # of items to newly input value + if params[:change_quantity][:quantity].to_i <= orderitem.product.stock + orderitem.update(quantity: params[:change_quantity][:quantity].to_i) + flash[:notice] = "Quantity updated! Quantity: #{orderitem.quantity}" + redirect_to carts_index_path + else + flash[:notice] = "Sorry, you cannot put that many items in your cart because the quantity would exceed available stock." + redirect_to carts_index_path + end + end + rescue ActiveRecord::RecordNotFound + flash[:notice] = "Sorry, that item in your order was not updated because it could not be found. Please try again." + if params[:add_to_cart] + redirect_to categories_index_path + else + redirect_to carts_index_path + end + end + end + + def destroy + begin + order = Order.find(session[:order]) + orderitem = Orderitem.find(params[:id]) + + if order.id != orderitem.order.id + raise RuntimeError + end + + orderitem.destroy + flash[:notice] = "Item removed from cart!" + + # Destroy the order if cart is now empty + if order.orderitems == [] + order.destroy + session[:order] = nil + end + rescue ActiveRecord::RecordNotFound, RuntimeError + flash[:notice] = "Sorry, there was a problem with your cart and the item could not be removed. Please try again." + end + redirect_to carts_index_path + end + + def ship + @orderitem = Orderitem.find(params[:id]) + @orderitem.status = "Shipped" + @orderitem.save + + redirect_to orders_index_path + end +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 0000000000..f9bd4070bc --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,50 @@ +class OrdersController < ApplicationController + + before_action :require_merchant, only: [:index, :show] + has_scope :status + + def index + @status_orders = apply_scopes(Order).all + merchant = Merchant.find_by(id: session[:user_id].to_i) + @orders = merchant.orders(@status_orders) + @paid = merchant.order_by_status("paid") + @complete = merchant.order_by_status("complete") + @pending = merchant.order_by_status("pending") + @cancelled = merchant.order_by_status("cancelled") + end + + def show + @order = Order.find(params[:id]) + @orderitems = @order.find_merchant_order_items(session[:user_id]) + end + + def destroy + begin + @order = Order.find(session[:order]) + @order.destroy_items + @order.destroy + session[:order] = nil + redirect_to carts_index_path + rescue ActiveRecord::RecordNotFound + render :file => 'public/404.html', :status => :not_found + end + end + + def complete + @order = Order.find(params[:id]) + @order.status = "complete" + @order.save + + redirect_to orders_index_path + end + + def cancel + @order = Order.find(params[:id]) + @order.status = "cancelled" + @order.save + @order.update_cancel_stock + + redirect_to orders_show_path + end + +end diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb new file mode 100644 index 0000000000..1d4902abd5 --- /dev/null +++ b/app/controllers/products_controller.rb @@ -0,0 +1,95 @@ +class ProductsController < ApplicationController + before_action :find_product, except: [:new, :create, :index] + before_action :require_merchant, only: [:new, :create, :edit, :retire, :update, :index] + + def index + @merchant = Merchant.find_by(id: session[:user_id].to_i) + end + + def show + + @reviews = Review.where(product_id: params[:id]) + + begin + @already_in_cart = session[:order] && Order.find(session[:order]).has_product(@product.id) + rescue ActiveRecord::RecordNotFound + session[:order] = nil + flash[:notice] = "Whoops! We had to reset your cart. Please feel free to continue shopping." + redirect_to products_show_path(params[:id]) + end + + # Review Average method is in Product model + @average = @product.review_average(@reviews) + + if @already_in_cart + @orderitem = Orderitem.new(quantity: 1) # To display the 1 in the form + @existing_orderitem = Orderitem.find_by(product: @product) + @url = orderitems_update_path(@existing_orderitem) + @method = :patch + else + @orderitem = Orderitem.new(quantity: 1) + @url = orderitems_create_path(params[:id]) # Passing in the product id so we can make a new orderitem + @method = :post + end + end + + def new + @action = "create" + @product = Product.new + end + + def edit + @action = "update" + end + + def create + @product = Product.create + @product.name = params[:product][:name] + @product.price = params[:product][:price] + @product.merchant_id = session[:user_id].to_i + @product.description = params[:product][:description] + @product.photo = params[:product][:photo].to_s + @product.stock = params[:product][:stock] + @product.category_ids = params[:product][:category_ids] + @product.retired = false + @product.save + redirect_to products_index_path + end + + def update + + @product.name = params[:product][:name] + @product.price = params[:product][:price] + @product.merchant_id = session[:user_id].to_i + @product.description = params[:product][:description] + @product.photo = params[:product][:photo].to_s + @product.stock = params[:product][:stock] + @product.category_ids = params[:product][:category_ids] + @product.save + redirect_to products_index_path + end + + # We might consider storing this method on the Product model + + def retire + if @product.retired == true + @product.retired = false + else + @product.retired = true + end + @product.save + + redirect_to products_index_path + end + + private + def find_product + @product = Product.find_by(id: params[:id].to_i) + if !@product || (@product.retired && (!session[:user_id] || session[:user_id].to_i != @product.merchant.id)) + flash[:notice] = "Sorry, that product could not be found. Please continue shopping our other awesome products." + redirect_to homepages_show_path + end + end + + +end diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb new file mode 100644 index 0000000000..543a1f6832 --- /dev/null +++ b/app/controllers/reviews_controller.rb @@ -0,0 +1,30 @@ +class ReviewsController < ApplicationController + before_action :check_if_selling_merchant + + def new + @review = Review.new + end + + def create + @review = Review.new + @review.rating = params[:review][:rating] + @review.feedback = params[:review][:feedback] + @review.product_id = params[:id] + + if @review.save + redirect_to products_show_path(@review.product_id) + else + render :new, :status => :error + end + end + + private + + def check_if_selling_merchant + if session[:user_id] && session[:user_id].to_i == Product.find_by(id: params[:id]).merchant.id + flash[:notice] = "Sorry, you cannot leave a review on your own product." + redirect_to products_show_path(params[:id]) + end + end + +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb new file mode 100644 index 0000000000..6bb8ae1ac9 --- /dev/null +++ b/app/controllers/sessions_controller.rb @@ -0,0 +1,50 @@ +class SessionsController < ApplicationController + def create + # Build the auth_hash from the Github hash object + auth_hash = request.env['omniauth.auth'] + + # Check to see if we received the auth_hash from Github. + if auth_hash == nil + flash[:notice] = "Login Failed" + return redirect_to root_path + end + + @merchant = Merchant.find_by(uid: auth_hash[:uid], provider: 'github') + + if @merchant == nil + # If merchant doesn't match any record in the DB, attempt to create a new merchant. + # The method to create the new Merchant (build_from_github) is defined in the + # Merchant model. + @merchant = Merchant.build_from_github(auth_hash) + + # Save the Merchant ID in the session (**not the :uid from GitHub**) + session[:user_id] = @merchant.id + flash[:notice] = "Successfully Logged In" + + return redirect_to merchants_edit_path(@merchant.id) + + end + + session[:user_id] = @merchant.id + + flash[:notice] = "Successfully Logged In" + redirect_to merchants_index_path + + end + + def index + @merchant = Merchant.find(session[:user_id]) + end + + def destroy + # Note: the does not log the merchant out of their Github account, which is why + # when a merchant logs out and then logs back in, they do not have to re-enter + # their credentials; the application has been authorized to use those credentials + # and will be able to until the merchant logs out of Github (then they'd have to + # reenter in their credentials to our app). + session[:user_id] = nil + + flash[:notice] = "Successfully Logged Out" + redirect_to root_path + end +end diff --git a/app/controllers/stores_controller.rb b/app/controllers/stores_controller.rb new file mode 100644 index 0000000000..d6f434834c --- /dev/null +++ b/app/controllers/stores_controller.rb @@ -0,0 +1,15 @@ +class StoresController < ApplicationController + def index + @stores = Merchant.all + end + + def show + begin + @store = Merchant.find(params[:id]) + @products = active_products.select {|product| product.merchant_id == @store.id} + rescue ActiveRecord::RecordNotFound + render :file => 'public/404.html', :status => :not_found + end + end + +end diff --git a/app/helpers/carts_helper.rb b/app/helpers/carts_helper.rb new file mode 100644 index 0000000000..d99c380cb5 --- /dev/null +++ b/app/helpers/carts_helper.rb @@ -0,0 +1,2 @@ +module CartsHelper +end diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb new file mode 100644 index 0000000000..bb812853d9 --- /dev/null +++ b/app/helpers/categories_helper.rb @@ -0,0 +1,4 @@ +module CategoriesHelper + + +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/merchants_helper.rb b/app/helpers/merchants_helper.rb new file mode 100644 index 0000000000..53c309112d --- /dev/null +++ b/app/helpers/merchants_helper.rb @@ -0,0 +1,3 @@ +module MerchantsHelper + +end diff --git a/app/helpers/orderitems_helper.rb b/app/helpers/orderitems_helper.rb new file mode 100644 index 0000000000..c74e407d1c --- /dev/null +++ b/app/helpers/orderitems_helper.rb @@ -0,0 +1,2 @@ +module OrderitemsHelper +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 0000000000..7a285b61ac --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,44 @@ +module OrdersHelper + + def final_total(array) + total = 0 + + array.each do |item| + total += item.total + end + + return total + end + + def total(orders_array) + total = 0 + orders_array.each do |order| + total += final_total(order.find_merchant_order_items(session[:user_id])) + end + return total + end + + def total_revenue(orders_array) + total_rev = 0 + + orders_array.each do |order| + order.orderitems.each do |orderitem| + shippedorderitems = [] + if orderitem.product.merchant_id == session[:user_id].to_i && orderitem.status == "Shipped" + shippedorderitems << orderitem + end + total_rev += final_total(shippedorderitems) + end + end + return total_rev + end + + def complete_check(array) + array.each do |item| + if item.status == "pending" + return false + end + end + return true + end +end diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb new file mode 100644 index 0000000000..d14b612015 --- /dev/null +++ b/app/helpers/products_helper.rb @@ -0,0 +1,9 @@ +module ProductsHelper + def category_options + @category_options = [] + Category.all.each do |category| + @category_options << [category.name, category.id] + end + return @category_options + end +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/stores_helper.rb b/app/helpers/stores_helper.rb new file mode 100644 index 0000000000..1ed55e92c1 --- /dev/null +++ b/app/helpers/stores_helper.rb @@ -0,0 +1,2 @@ +module StoresHelper +end diff --git a/app/models/category.rb b/app/models/category.rb new file mode 100644 index 0000000000..3eaa5efd8d --- /dev/null +++ b/app/models/category.rb @@ -0,0 +1,5 @@ +# Info on join tables: http://shilpi2189.blogspot.com/2013/01/implementing-hasandbelongstomany.html + +class Category < ActiveRecord::Base + has_and_belongs_to_many :products +end diff --git a/app/models/merchant.rb b/app/models/merchant.rb new file mode 100644 index 0000000000..28dc397cc4 --- /dev/null +++ b/app/models/merchant.rb @@ -0,0 +1,54 @@ +class Merchant < ActiveRecord::Base + has_many :products + + def self.build_from_github(auth_hash) + merchant = Merchant.new + merchant.uid = auth_hash[:uid].to_i + merchant.provider = 'github' + merchant.username = auth_hash['info']['nickname'] + merchant.email = auth_hash['info']['email'] + merchant.displayname = 'My Merchant' + merchant.save + + return merchant + end + + validates :username, + presence: true, + uniqueness: true + + # validates :displayname, + # presence: true, + # uniqueness: true + + validates :email, + presence: true, + uniqueness: true + + def orders (list) + products = self.products + orders = [] + products.each do |product| + product.orderitems.each do |orderitem| + if !orders.include?(orderitem.order) && orderitem.order != nil && list.include?(orderitem.order) + orders << orderitem.order + end + end + end + return orders + end + + def order_by_status (status) + products = self.products + orders = [] + products.each do |product| + product.orderitems.each do |orderitem| + if !orders.include?(orderitem.order) && orderitem.order != nil && orderitem.order.status == status + orders << orderitem.order + end + end + end + return orders + end + +end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 0000000000..ba6e519902 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,124 @@ +class Order < ActiveRecord::Base + has_many :orderitems + + validates :orderitems, + presence: true + + scope :status, lambda{|status| where('status = ?', status )} + + # Email validation from: http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html + validates :name, presence: true, if: :buyer_info_needed? + validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i }, if: :buyer_info_needed? + validates :address, presence: true, if: :buyer_info_needed? + validates :city, presence: true, if: :buyer_info_needed? + validates :state, presence: true, if: :buyer_info_needed? + validates :zip, presence: true, numericality: true, length: {minimum: 5, maximum: 5}, if: :buyer_info_needed? + validates :card_name, presence: true, if: :buyer_info_needed? + validates :card_num, presence: true, numericality: true, length: {minimum: 13, maximum: 19}, if: :buyer_info_needed? + validates :expiry, presence: true, if: :buyer_info_needed? + validates :cvv, presence: true, numericality: true, length: {minimum: 3, maximum: 4}, if: :buyer_info_needed? + validates :billing_zip, presence: true, numericality: true, length: {minimum: 5, maximum: 5}, if: :buyer_info_needed? + validates :placed_at, presence: true, if: :buyer_info_needed? + + + def total + total = 0 + + self.orderitems.each do |orderitem| + total += orderitem.total + end + + return total + end + + def has_product (product_id) + + self.orderitems.each do |orderitem| + if orderitem.product.id == product_id + return true + end + end + + return false + + end + + # Reduce the stock of each item when it is sold + + def update_stock + + self.orderitems.each do |orderitem| + product = orderitem.product + product.stock -= orderitem.quantity + product.save + end + + end + + #update stock when order is canceled, ONLY for items specified merchant was responsible for. + def update_cancel_stock + + self.orderitems.each do |orderitem| + if orderitem.status != "Shipped" + product = orderitem.product + product.stock += orderitem.quantity + product.save + end + end + + end + + + def find_merchant_order_items(user_id) + orderitems = [] + self.orderitems.each do |orderitem| + if orderitem.product.merchant_id == user_id.to_i + orderitems << orderitem + end + end + return orderitems + end + + def remove_backordered? + there_are_backordered_items = false + self.orderitems.each do |orderitem| + product = orderitem.product + if product.stock <= 0 # If an item is fully out of stock, remove it from the cart + if self.orderitems.length == 1 + self.destroy + end + orderitem.destroy + there_are_backordered_items = true + elsif product.stock < orderitem.quantity # If an item has too little stock to fill the order fully, reduce the quantity + orderitem.quantity = product.stock + orderitem.save + there_are_backordered_items = true + end + end + return there_are_backordered_items + end + + def destroy_items + self.orderitems.each do |orderitem| + orderitem.destroy + end + end + + def update_prices? + there_are_updated_prices = false + self.orderitems.each do |orderitem| + product = orderitem.product + if orderitem.price != product.price # If an item's price has changed + orderitem.update(price: product.price) + there_are_updated_prices = true + end + end + return there_are_updated_prices + end + + private + + def buyer_info_needed? + return status == 'paid' + end +end diff --git a/app/models/orderitem.rb b/app/models/orderitem.rb new file mode 100644 index 0000000000..2155beca3d --- /dev/null +++ b/app/models/orderitem.rb @@ -0,0 +1,21 @@ +class Orderitem < ActiveRecord::Base + belongs_to :product + belongs_to :order + + validates :quantity, + numericality: { only_integer: true, greater_than: 0 } + + validates :product, + presence: true + + validates :order, + presence: true + + validates :price, + presence: true + + def total + return self.quantity * self.price + end + +end diff --git a/app/models/product.rb b/app/models/product.rb new file mode 100644 index 0000000000..0fc25ed38c --- /dev/null +++ b/app/models/product.rb @@ -0,0 +1,34 @@ +class Product < ActiveRecord::Base + belongs_to :merchant + has_many :orderitems + has_many :reviews + has_and_belongs_to_many :categories + + validates :name, + presence: true, + uniqueness: true + + validates :price, + presence: true, + numericality: { greater_than: 0 } + + validates :merchant_id, + presence: true + + + def review_average(reviews) + # Review.where(product_id: params[:id]) + average = 0 + reviews.each do |review| + average += review.rating.to_i + end + if average > 0 + average = sprintf('%.2f', (average / reviews.length.to_f)) + else + average = "No ratings yet" + end + return average + end + + +end diff --git a/app/models/review.rb b/app/models/review.rb new file mode 100644 index 0000000000..c3faaeaf9d --- /dev/null +++ b/app/models/review.rb @@ -0,0 +1,13 @@ +class Review < ActiveRecord::Base + belongs_to :product + + validates :rating, + presence: true, + numericality: { only_integer: true, + greater_than_or_equal_to: 1, + less_than_or_equal_to: 5 } + + validates :product, + presence: true + +end diff --git a/app/views/carts/edit.html.erb b/app/views/carts/edit.html.erb new file mode 100644 index 0000000000..c0dec01230 --- /dev/null +++ b/app/views/carts/edit.html.erb @@ -0,0 +1,64 @@ +<% # http://stackoverflow.com/questions/8386287/how-to-display-month-and-year-selection-for-credit-card %> + +
+
+ <% if @order.errors.any? %> +

Whoops! We couldn't save your information because:

+ +

Please edit your information and try again.

+ <% end %> + +

Check out

+ +

Please enter your shipping and payment information below. This will help us send you your magically delightful products as quickly as possible.

+ <%= form_for @order, url: carts_update_path, method: :put do |f| %> + +

Shipping information

+ + <%= f.label :name %> + <%= f.text_field :name %> + + <%= f.label :email %> + <%= f.text_field :email %> + + <%= f.label :address %> + <%= f.text_field :address %> + + <%= f.label :city %> + <%= f.text_field :city %> + + <%= f.label :state %> + <%= f.text_field :state %> + + <%= f.label :zip %> + <%= f.text_field :zip %> + +

Billing information

+ + <%= f.label "Name on credit card" %> + <%= f.text_field :card_name %> + + <%= f.label "Credit card number" %> + <%= f.text_field :card_num %> + + <%= f.label :expiry, "Expiration date" %> + <%= f.date_select :expiry, discard_day: true, order: [:month, :year], use_short_month: true, add_month_numbers: true, start_year: Date.today.year, end_year: Date.today.year+20 %> + + <%= f.label "CVV (code on back of card)" %> + <%= f.text_field :cvv %> + + <%= f.label :billing_zip %> + <%= f.text_field :billing_zip %> + +

When you push the "Complete transaction" button, your credit card will be charged <%= number_to_currency(@order.total/100.00) %>

+ + <%= f.submit "Complete transaction" %> + <% end %> +
+
diff --git a/app/views/carts/index.html.erb b/app/views/carts/index.html.erb new file mode 100644 index 0000000000..8db657a6f3 --- /dev/null +++ b/app/views/carts/index.html.erb @@ -0,0 +1,63 @@ +

What's in my cart?

+ +

<%= flash[:notice] %> + +<% if session[:order] %> + +

Your cart contains:

+ + + + + + + + + + + + <% @order.orderitems.each do |orderitem| %> + + + + + + + + <% end %> + + + + + + + + +
ProductUnit priceQuantityTotal
<%= link_to orderitem.product.name, products_show_path(orderitem.product.id) %><%= number_to_currency(orderitem.price/100.00) %> + <%= form_for orderitem, as: 'change_quantity', url: orderitems_update_path(orderitem), method: :patch do |f| %> + <%= f.number_field :quantity, min: 1 %> + <%= f.submit "Update" %> + <% end %> + <%= number_to_currency(orderitem.total/100.00) %><%= button_to "Delete", orderitems_destroy_path(orderitem), method: :delete %>
+ <%= number_to_currency(@order.total/100.00)%>
+
+

<%= link_to "Empty cart", orders_destroy_path %>

+
+ + +<% else %> +
+

Your cart is empty! That makes the unicorns sad :(

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

<%= link_to "Keep shopping", categories_index_path, class: "links" %>

+
+
+

<%= link_to "Check out", carts_edit_path, class: "links" %>

+
+
diff --git a/app/views/carts/update.html.erb b/app/views/carts/update.html.erb new file mode 100644 index 0000000000..5ba80c61fe --- /dev/null +++ b/app/views/carts/update.html.erb @@ -0,0 +1,40 @@ + + +
+
+

Thank you for shopping with Unicorns "R" Us!

+ + + + + + + + + + + <% @order.orderitems.each do |orderitem| %> + + + + + + + <% end %> + + + + + + + +
ProductUnit priceQuantityTotal
<%= link_to orderitem.product.name, products_show_path(orderitem.product.id) %><%= number_to_currency(orderitem.price/100.00) %><%= orderitem.quantity %><%= number_to_currency(orderitem.total/100.00) %>
+ <%= number_to_currency(@order.total/100.00)%>
+ + +

The status of your order is: <%= @order.status %>.

+

Your order was placed at: <%= @order.placed_at %>.

+ +

Questions? Problems? Want to cancel something? Don't hesitate to contact us at <%= mail_to 'customerservice@unicornsrus.com' %>. Be sure to reference your order number, order ID: <%= @order.id %>.

+
+
diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb new file mode 100644 index 0000000000..08b90663ac --- /dev/null +++ b/app/views/categories/index.html.erb @@ -0,0 +1,21 @@ + + +
+ +
diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb new file mode 100644 index 0000000000..8c7a528ad9 --- /dev/null +++ b/app/views/categories/new.html.erb @@ -0,0 +1,22 @@ + + + +
+
+ <% if current_user %> + <%= "#{@merchant.displayname}" %> + + + + <%= form_for Category do |f| %> + <%= f.label "Category Name" %> + <%= f.text_field :name %> + <% f.submit %> + <% end %> + + <% else %> +

You are not authorized to visit this page. Please login as a merchant.

+ + <% end %> +
+
diff --git a/app/views/categories/show.html.erb b/app/views/categories/show.html.erb new file mode 100644 index 0000000000..d34bde4416 --- /dev/null +++ b/app/views/categories/show.html.erb @@ -0,0 +1,20 @@ + +
+ +
diff --git a/app/views/homepages/index.html.erb b/app/views/homepages/index.html.erb new file mode 100644 index 0000000000..30e52ecd1c --- /dev/null +++ b/app/views/homepages/index.html.erb @@ -0,0 +1,40 @@ +<% if flash[:notice] %> +

<%= flash[:notice] %>

+<% end %> + + +

Top Picks

+ + +
+ + + + + + + + +
diff --git a/app/views/homepages/show.html.erb b/app/views/homepages/show.html.erb new file mode 100644 index 0000000000..945f2e7b7c --- /dev/null +++ b/app/views/homepages/show.html.erb @@ -0,0 +1,24 @@ + +
+ +
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 9b70e01c2e..7daa77fa30 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -1,14 +1,64 @@ - Betsy + Unicorns <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> + <%= favicon_link_tag '/favicon.ico' %> +
+
+
+ +
+
+

<%= link_to "Unicorns 'R' Us", root_path %>

+
+
+
Meeting all your unicorn needs since 2016.
+
+ +
+ +
+
+
+ + <%= yield %> +
+ +
+ + diff --git a/app/views/merchants/edit.html.erb b/app/views/merchants/edit.html.erb new file mode 100644 index 0000000000..f5da4163e7 --- /dev/null +++ b/app/views/merchants/edit.html.erb @@ -0,0 +1,40 @@ +<% if @merchant.displayname == nil %> +

<%= "Please Provide the following information to create a new merchant store"%>

+<% else %> +

<%= "#{@merchant.displayname}, edit your profile"%>

+<% end %> + + +<%= flash[:notice] %> + +
+ + +<%= form_for @merchant, url: merchants_update_path do |f| %> + +
+
+ <%= f.label "Profile Image URL" %> + <%= f.text_field :photo %> + + <%= f.label "Store Name" %> + <%= f.text_field :displayname %> + + <%= f.label "Store Location" %> + <%= f.text_field :location %> + + <%= f.label "Store Contact Number" %> + <%= f.telephone_field :phone %> + + <%= f.label "Email" %> + <%= f.email_field :email %> + + <%= f.label "User Name" %> + <%= f.text_field :username %> + + <%= f.submit "Save", class: "button" %> +
+
+<% end %> + +
diff --git a/app/views/merchants/index.html.erb b/app/views/merchants/index.html.erb new file mode 100644 index 0000000000..d57f97b52f --- /dev/null +++ b/app/views/merchants/index.html.erb @@ -0,0 +1,36 @@ +
+