Itsy Categories
+ <% @categories.each do |category| %> +-
+
- + <%=link_to category.name, category_path(category.id) %> + +
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..e3c78a862f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,29 @@
+# See https://help.github.com/articles/ignoring-files for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+# git config --global core.excludesfile '~/.gitignore_global'
+
+# Ignore bundler config.
+/.bundle
+
+# Ignore all logfiles and tempfiles.
+/log/*
+/tmp/*
+!/log/.keep
+!/tmp/.keep
+
+# Ignore uploaded files in development
+/storage/*
+!/storage/.keep
+
+/node_modules
+/yarn-error.log
+
+/public/assets
+.byebug_history
+
+# Ignore master key for decrypting credentials and more.
+/config/master.key
+coverage/
+.env
\ No newline at end of file
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000000..25c81fe399
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+ruby-2.5.1
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..953e32145c
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "workbench.colorCustomizations": {
+ "tab.unfocusedActiveBorder": "#fff0"
+ }
+}
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000000..6e63f902df
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,87 @@
+source 'https://rubygems.org'
+git_source(:github) { |repo| "https://github.com/#{repo}.git" }
+
+ruby '2.5.1'
+
+# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
+gem 'rails', '~> 5.2.3'
+# Use postgresql as the database for Active Record
+gem 'pg', '>= 0.18', '< 2.0'
+# Use Puma as the app server
+gem 'puma', '~> 3.11'
+# Use SCSS for stylesheets
+gem 'sass-rails', '~> 5.0'
+# Use Uglifier as compressor for JavaScript assets
+gem 'uglifier', '>= 1.3.0'
+# See https://github.com/rails/execjs#readme for more supported runtimes
+# gem 'mini_racer', platforms: :ruby
+
+# Use CoffeeScript for .coffee assets and views
+# gem 'coffee-rails', '~> 4.2'
+# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
+gem 'turbolinks', '~> 5'
+# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
+gem 'jbuilder', '~> 2.5'
+# Use Redis adapter to run Action Cable in production
+# gem 'redis', '~> 4.0'
+# Use ActiveModel has_secure_password
+# gem 'bcrypt', '~> 3.1.7'
+
+# Use ActiveStorage variant
+# gem 'mini_magick', '~> 4.8'
+
+# Use Capistrano for deployment
+# gem 'capistrano-rails', group: :development
+
+# Reduces boot times through caching; required in config/boot.rb
+gem 'bootsnap', '>= 1.1.0', require: false
+
+group :development, :test do
+ # Call 'byebug' anywhere in the code to stop execution and get a debugger console
+ gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
+end
+
+group :development do
+ # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
+ gem 'web-console', '>= 3.3.0'
+ gem 'listen', '>= 3.0.5', '< 3.2'
+ # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
+ gem 'spring'
+ gem 'spring-watcher-listen', '~> 2.0.0'
+end
+
+group :test do
+ # Adds support for Capybara system testing and selenium driver
+ gem 'capybara', '>= 2.15'
+ gem 'selenium-webdriver'
+ # Easy installation and use of chromedriver to run system tests with Chrome
+ gem 'chromedriver-helper'
+end
+
+# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
+gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+
+gem 'jquery-rails'
+gem 'jquery-turbolinks'
+gem 'bootstrap', '~> 4.1.3'
+group :development, :test do
+ gem 'pry-rails'
+end
+
+group :development do
+ gem 'better_errors'
+ gem 'binding_of_caller'
+ gem 'guard'
+ gem 'guard-minitest'
+ gem 'dotenv-rails'
+end
+
+group :test do
+ gem 'minitest-rails'
+ gem 'minitest-reporters'
+ gem 'simplecov'
+ gem 'simplecov-console'
+end
+
+gem "omniauth"
+gem "omniauth-github"
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000000..5b27d3a074
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,321 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ actioncable (5.2.3)
+ actionpack (= 5.2.3)
+ nio4r (~> 2.0)
+ websocket-driver (>= 0.6.1)
+ actionmailer (5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
+ mail (~> 2.5, >= 2.5.4)
+ rails-dom-testing (~> 2.0)
+ actionpack (5.2.3)
+ actionview (= 5.2.3)
+ activesupport (= 5.2.3)
+ rack (~> 2.0)
+ rack-test (>= 0.6.3)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
+ actionview (5.2.3)
+ activesupport (= 5.2.3)
+ builder (~> 3.1)
+ erubi (~> 1.4)
+ rails-dom-testing (~> 2.0)
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
+ activejob (5.2.3)
+ activesupport (= 5.2.3)
+ globalid (>= 0.3.6)
+ activemodel (5.2.3)
+ activesupport (= 5.2.3)
+ activerecord (5.2.3)
+ activemodel (= 5.2.3)
+ activesupport (= 5.2.3)
+ arel (>= 9.0)
+ activestorage (5.2.3)
+ actionpack (= 5.2.3)
+ activerecord (= 5.2.3)
+ marcel (~> 0.3.1)
+ activesupport (5.2.3)
+ concurrent-ruby (~> 1.0, >= 1.0.2)
+ i18n (>= 0.7, < 2)
+ minitest (~> 5.1)
+ tzinfo (~> 1.1)
+ addressable (2.6.0)
+ public_suffix (>= 2.0.2, < 4.0)
+ ansi (1.5.0)
+ archive-zip (0.12.0)
+ io-like (~> 0.3.0)
+ arel (9.0.0)
+ autoprefixer-rails (9.5.1)
+ execjs
+ better_errors (2.5.1)
+ coderay (>= 1.0.0)
+ erubi (>= 1.0.0)
+ rack (>= 0.9.0)
+ bindex (0.7.0)
+ binding_of_caller (0.8.0)
+ debug_inspector (>= 0.0.1)
+ bootsnap (1.4.4)
+ msgpack (~> 1.0)
+ bootstrap (4.1.3)
+ autoprefixer-rails (>= 6.0.3)
+ popper_js (>= 1.12.9, < 2)
+ sass (>= 3.5.2)
+ builder (3.2.3)
+ byebug (11.0.1)
+ capybara (3.18.0)
+ addressable
+ mini_mime (>= 0.1.3)
+ nokogiri (~> 1.8)
+ rack (>= 1.6.0)
+ rack-test (>= 0.6.3)
+ regexp_parser (~> 1.2)
+ xpath (~> 3.2)
+ childprocess (1.0.1)
+ rake (< 13.0)
+ chromedriver-helper (2.1.1)
+ archive-zip (~> 0.10)
+ nokogiri (~> 1.8)
+ coderay (1.1.2)
+ concurrent-ruby (1.1.5)
+ crass (1.0.4)
+ debug_inspector (0.0.3)
+ docile (1.3.1)
+ dotenv (2.7.2)
+ dotenv-rails (2.7.2)
+ dotenv (= 2.7.2)
+ railties (>= 3.2, < 6.1)
+ erubi (1.8.0)
+ execjs (2.7.0)
+ faraday (0.15.4)
+ multipart-post (>= 1.2, < 3)
+ ffi (1.10.0)
+ formatador (0.2.5)
+ globalid (0.4.2)
+ activesupport (>= 4.2.0)
+ guard (2.15.0)
+ formatador (>= 0.2.4)
+ listen (>= 2.7, < 4.0)
+ lumberjack (>= 1.0.12, < 2.0)
+ nenv (~> 0.1)
+ notiffany (~> 0.0)
+ pry (>= 0.9.12)
+ shellany (~> 0.0)
+ thor (>= 0.18.1)
+ guard-compat (1.2.1)
+ guard-minitest (2.4.6)
+ guard-compat (~> 1.2)
+ minitest (>= 3.0)
+ hashie (3.6.0)
+ hirb (0.7.3)
+ i18n (1.6.0)
+ concurrent-ruby (~> 1.0)
+ io-like (0.3.0)
+ jbuilder (2.8.0)
+ activesupport (>= 4.2.0)
+ multi_json (>= 1.2)
+ jquery-rails (4.3.3)
+ 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 (2.2.0)
+ jwt (2.1.0)
+ listen (3.1.5)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ ruby_dep (~> 1.2)
+ loofah (2.2.3)
+ crass (~> 1.0.2)
+ nokogiri (>= 1.5.9)
+ lumberjack (1.0.13)
+ mail (2.7.1)
+ mini_mime (>= 0.1.1)
+ marcel (0.3.3)
+ mimemagic (~> 0.3.2)
+ method_source (0.9.2)
+ mimemagic (0.3.3)
+ mini_mime (1.0.1)
+ mini_portile2 (2.4.0)
+ minitest (5.11.3)
+ minitest-rails (3.0.0)
+ minitest (~> 5.8)
+ railties (~> 5.0)
+ minitest-reporters (1.3.6)
+ ansi
+ builder
+ minitest (>= 5.0)
+ ruby-progressbar
+ msgpack (1.2.10)
+ multi_json (1.13.1)
+ multi_xml (0.6.0)
+ multipart-post (2.0.0)
+ nenv (0.3.0)
+ nio4r (2.3.1)
+ nokogiri (1.10.3)
+ mini_portile2 (~> 2.4.0)
+ notiffany (0.1.1)
+ nenv (~> 0.1)
+ shellany (~> 0.0)
+ oauth2 (1.4.1)
+ faraday (>= 0.8, < 0.16.0)
+ jwt (>= 1.0, < 3.0)
+ multi_json (~> 1.3)
+ multi_xml (~> 0.5)
+ rack (>= 1.2, < 3)
+ omniauth (1.9.0)
+ hashie (>= 3.4.6, < 3.7.0)
+ rack (>= 1.6.2, < 3)
+ omniauth-github (1.3.0)
+ omniauth (~> 1.5)
+ omniauth-oauth2 (>= 1.4.0, < 2.0)
+ omniauth-oauth2 (1.6.0)
+ oauth2 (~> 1.1)
+ omniauth (~> 1.9)
+ pg (1.1.4)
+ popper_js (1.14.5)
+ pry (0.12.2)
+ coderay (~> 1.1.0)
+ method_source (~> 0.9.0)
+ pry-rails (0.3.9)
+ pry (>= 0.10.4)
+ public_suffix (3.0.3)
+ puma (3.12.1)
+ rack (2.0.7)
+ rack-test (1.1.0)
+ rack (>= 1.0, < 3)
+ rails (5.2.3)
+ actioncable (= 5.2.3)
+ actionmailer (= 5.2.3)
+ actionpack (= 5.2.3)
+ actionview (= 5.2.3)
+ activejob (= 5.2.3)
+ activemodel (= 5.2.3)
+ activerecord (= 5.2.3)
+ activestorage (= 5.2.3)
+ activesupport (= 5.2.3)
+ bundler (>= 1.3.0)
+ railties (= 5.2.3)
+ sprockets-rails (>= 2.0.0)
+ rails-dom-testing (2.0.3)
+ activesupport (>= 4.2.0)
+ nokogiri (>= 1.6)
+ rails-html-sanitizer (1.0.4)
+ loofah (~> 2.2, >= 2.2.2)
+ railties (5.2.3)
+ actionpack (= 5.2.3)
+ activesupport (= 5.2.3)
+ method_source
+ rake (>= 0.8.7)
+ thor (>= 0.19.0, < 2.0)
+ rake (12.3.2)
+ rb-fsevent (0.10.3)
+ rb-inotify (0.10.0)
+ ffi (~> 1.0)
+ regexp_parser (1.4.0)
+ ruby-progressbar (1.10.0)
+ ruby_dep (1.5.0)
+ rubyzip (1.2.2)
+ sass (3.7.4)
+ sass-listen (~> 4.0.0)
+ sass-listen (4.0.0)
+ rb-fsevent (~> 0.9, >= 0.9.4)
+ rb-inotify (~> 0.9, >= 0.9.7)
+ sass-rails (5.0.7)
+ railties (>= 4.0.0, < 6)
+ sass (~> 3.1)
+ sprockets (>= 2.8, < 4.0)
+ sprockets-rails (>= 2.0, < 4.0)
+ tilt (>= 1.1, < 3)
+ selenium-webdriver (3.142.0)
+ childprocess (>= 0.5, < 2.0)
+ rubyzip (~> 1.2, >= 1.2.2)
+ shellany (0.0.1)
+ simplecov (0.16.1)
+ docile (~> 1.1)
+ json (>= 1.8, < 3)
+ simplecov-html (~> 0.10.0)
+ simplecov-console (0.4.2)
+ ansi
+ hirb
+ simplecov
+ simplecov-html (0.10.2)
+ spring (2.0.2)
+ activesupport (>= 4.2)
+ spring-watcher-listen (2.0.1)
+ listen (>= 2.7, < 4.0)
+ spring (>= 1.2, < 3.0)
+ sprockets (3.7.2)
+ concurrent-ruby (~> 1.0)
+ rack (> 1, < 3)
+ sprockets-rails (3.2.1)
+ actionpack (>= 4.0)
+ activesupport (>= 4.0)
+ sprockets (>= 3.0.0)
+ thor (0.20.3)
+ thread_safe (0.3.6)
+ tilt (2.0.9)
+ turbolinks (5.2.0)
+ turbolinks-source (~> 5.2)
+ turbolinks-source (5.2.0)
+ tzinfo (1.2.5)
+ thread_safe (~> 0.1)
+ uglifier (4.1.20)
+ execjs (>= 0.3.0, < 3)
+ web-console (3.7.0)
+ actionview (>= 5.0)
+ activemodel (>= 5.0)
+ bindex (>= 0.4.0)
+ railties (>= 5.0)
+ websocket-driver (0.7.0)
+ websocket-extensions (>= 0.1.0)
+ websocket-extensions (0.1.3)
+ xpath (3.2.0)
+ nokogiri (~> 1.8)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ better_errors
+ binding_of_caller
+ bootsnap (>= 1.1.0)
+ bootstrap (~> 4.1.3)
+ byebug
+ capybara (>= 2.15)
+ chromedriver-helper
+ dotenv-rails
+ guard
+ guard-minitest
+ jbuilder (~> 2.5)
+ jquery-rails
+ jquery-turbolinks
+ listen (>= 3.0.5, < 3.2)
+ minitest-rails
+ minitest-reporters
+ omniauth
+ omniauth-github
+ pg (>= 0.18, < 2.0)
+ pry-rails
+ puma (~> 3.11)
+ rails (~> 5.2.3)
+ sass-rails (~> 5.0)
+ selenium-webdriver
+ simplecov
+ simplecov-console
+ spring
+ spring-watcher-listen (~> 2.0.0)
+ turbolinks (~> 5)
+ tzinfo-data
+ uglifier (>= 1.3.0)
+ web-console (>= 3.3.0)
+
+RUBY VERSION
+ ruby 2.5.1p57
+
+BUNDLED WITH
+ 2.0.1
diff --git a/Guardfile b/Guardfile
new file mode 100644
index 0000000000..e34f706f4a
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,9 @@
+guard :minitest, autorun: false, spring: true do
+ watch(%r{^app/(.+).rb$}) { |m| "test/#{m[1]}_test.rb" }
+ watch(%r{^app/controllers/application_controller.rb$}) { 'test/controllers' }
+ watch(%r{^app/controllers/(.+)_controller.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
+ watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
+ watch(%r{^lib/(.+).rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
+ watch(%r{^test/.+_test.rb$})
+ watch(%r{^test/test_helper.rb$}) { 'test' }
+end
diff --git a/README.md b/README.md
index 6db044f03d..062cd09a49 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# bEtsy
+Dee is doing a weird test right now :)
+
## At a Glance
- Group, [stage 3](https://github.com/Ada-Developers-Academy/pedagogy/blob/master/rule-of-three.md) project
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000000..e85f913914
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,6 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require_relative 'config/application'
+
+Rails.application.load_tasks
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
new file mode 100644
index 0000000000..b16e53d6d5
--- /dev/null
+++ b/app/assets/config/manifest.js
@@ -0,0 +1,3 @@
+//= link_tree ../images
+//= link_directory ../javascripts .js
+//= link_directory ../stylesheets .css
diff --git a/app/assets/images/.keep b/app/assets/images/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/assets/images/colors.png b/app/assets/images/colors.png
new file mode 100644
index 0000000000..310e8868d9
Binary files /dev/null and b/app/assets/images/colors.png differ
diff --git a/app/assets/images/doodles.png b/app/assets/images/doodles.png
new file mode 100644
index 0000000000..855a89e9e6
Binary files /dev/null and b/app/assets/images/doodles.png differ
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
new file mode 100644
index 0000000000..27c269c46f
--- /dev/null
+++ b/app/assets/javascripts/application.js
@@ -0,0 +1,19 @@
+// This is a manifest file that'll be compiled into application.js, which will include all the files
+// listed below.
+//
+// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
+// vendor/assets/javascripts directory can be referenced here using a relative path.
+//
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// compiled file. JavaScript code in this file should be added after the last require_* statement.
+//
+// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
+// about supported directives.
+ //= require jquery3
+ //= require popper
+ //= require bootstrap-sprockets
+//
+//= require rails-ujs
+//= require activestorage
+//= require turbolinks
+//= require_tree .
diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js
new file mode 100644
index 0000000000..739aa5f022
--- /dev/null
+++ b/app/assets/javascripts/cable.js
@@ -0,0 +1,13 @@
+// Action Cable provides the framework to deal with WebSockets in Rails.
+// You can generate new channels where WebSocket features live using the `rails generate channel` command.
+//
+//= require action_cable
+//= require_self
+//= require_tree ./channels
+
+(function() {
+ this.App || (this.App = {});
+
+ App.cable = ActionCable.createConsumer();
+
+}).call(this);
diff --git a/app/assets/javascripts/categories.js b/app/assets/javascripts/categories.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/categories.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/channels/.keep b/app/assets/javascripts/channels/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/assets/javascripts/homepages.js b/app/assets/javascripts/homepages.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/homepages.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/merchants.js b/app/assets/javascripts/merchants.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/merchants.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/order.js b/app/assets/javascripts/order.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/order.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/orderitems.js b/app/assets/javascripts/orderitems.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/orderitems.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/orders.js b/app/assets/javascripts/orders.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/orders.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/products.js b/app/assets/javascripts/products.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/products.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/reviews.js b/app/assets/javascripts/reviews.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/reviews.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/javascripts/sessions.js b/app/assets/javascripts/sessions.js
new file mode 100644
index 0000000000..dee720facd
--- /dev/null
+++ b/app/assets/javascripts/sessions.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/stylesheets/about.scss b/app/assets/stylesheets/about.scss
new file mode 100644
index 0000000000..181769510c
--- /dev/null
+++ b/app/assets/stylesheets/about.scss
@@ -0,0 +1,10 @@
+.main-content {
+ margin: 100px 0px 50px 0px;
+ z-index: 100;
+}
+
+ #left-text, #left-about {
+ text-align: left;
+}
+
+
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
new file mode 100644
index 0000000000..e63c5728f2
--- /dev/null
+++ b/app/assets/stylesheets/application.scss
@@ -0,0 +1,224 @@
+
+@import "bootstrap";
+/* Import scss content */
+@import "**/*";
+@import url('https://fonts.googleapis.com/css?family=Nunito');
+
+html{
+ height:100%;
+}
+
+:root {
+ --blue: #cceedd;
+ --indigo: #8855ff;
+ --purple: #cc66ee;
+ --pink: #ffaaaa;
+ --red: #dc3545;
+ --orange: #ff8754;
+ --yellow: #ffc107;
+ --green: #aacc44;
+ --teal: #88ccaa;
+ --cyan: #cceedd;
+ --white: #fff;
+ --gray: #99aabb;
+ --gray-dark: #343a40;
+ --primary: #88ccaa;
+ --secondary: #8855ff;
+ --success: #aacc44;
+ --info: #88ccaa;
+ --warning: #ffc107;
+ --danger: #ff8754;
+ --light: #cceedd;
+ --dark: #343a40;
+}
+
+body {
+ // background-image: url("doodles.png");
+ font-family: 'Nunito', sans-serif;
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ // max-width: 1088px;
+}
+
+strong {
+ color: #15cba6;
+ font-weight: bold;
+}
+
+footer {
+ color: #099a97;
+ text-align: center;
+}
+
+main{
+ min-height: 1500px;
+ border-radius: 0px 0px 10px 10px;
+ padding-left: 5%;
+ padding-right: 5%;
+ padding-top: 2px;
+}
+
+li {
+ list-style: none;
+}
+
+.header {
+ width: 100%;
+ position: fixed;
+ padding-bottom: 10px;
+ left: 1px;
+ right: 2px;
+ background-color: white;
+ border-bottom: solid;
+ border-bottom-color: #c9c9c9;
+ border-width: thin;
+ z-index: 400;
+}
+
+.logo {
+ display: inline-block;
+ padding-left: 20px;
+}
+
+.logo a:visited {
+ color: #099a97;
+}
+
+.logo a:hover {
+ color: #7a0abb;
+}
+
+
+.motto {
+ text-align: center;
+ font-size: .8rem;
+ color: rgb(117, 6, 90);
+ letter-spacing: .2em;
+ font-family: 'Itim', sans-serif;
+}
+
+.navigation ul {
+ padding-inline-start: 5px;
+ margin-bottom: 0;
+ align-items: center;
+}
+
+.nav-app-header {
+ display: flex;
+ flex-direction: row;
+ font-family: 'Itim', sans-serif;
+ margin-left: 110px;
+ margin-right: 110px;
+ padding-bottom: 20px;
+ position: fixed;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+ padding: 0.5rem 1rem;
+}
+
+.app-header__nav_item {
+ display: inline-block;
+ padding-left: 10px;
+
+}
+
+.main-container {
+ display: flex;
+ flex-direction: column;
+}
+
+a:visited {
+ color: #292F36;
+
+}
+a:link {
+ color: #292F36;
+}
+
+a:hover {
+ color: #15cba6;
+ text-decoration: none;
+}
+
+#session {
+ background-color: #FFFFFF;
+}
+
+#session:hover {
+ color: #099a97;
+ border: #099a97 solid 1px;
+}
+
+.btn-primary {
+ background-color: white;
+ color: var(--primary);
+ border: 1px #292F36 solid;
+}
+
+.btn-primary:hover {
+ color: var(--primary);
+ background-color: #099a97;
+ border: 1px #099a97 solid;
+}
+
+.btn-primary:visited {
+ color: var(--primary);
+ border: 1px #292F36 solid;
+}
+
+.dropdown {
+ position: relative;
+ display: inline-block;
+}
+
+.dropdown-content {
+ display: none;
+ position: absolute;
+ background-color: #fff;
+ text-align: center;
+ min-width: 10em;
+ box-shadow: 0px 5px 5px 0px rgba(0,0,0,0.2);
+ z-index: 1;
+ font-weight: bolder;
+ white-space: nowrap;
+}
+
+.dropdown:hover .dropdown-content,
+.dropdown:hover .dropdown-content li {
+ display: block;
+ width: 100%;
+}
+
+.dropdown .dropdown-content:hover li:hover {
+ background-color: #ddd;
+ width: 100%;
+}
+
+.pull-right {
+ position: relative;
+ margin-left: auto;
+ padding-bottom: 10px;
+}
+
+/* Footer */
+
+#itsy-foot {
+ background-color: #95d9b3 ;
+ margin-top: 103px;
+ height: 220px;
+ font-size: 15px;
+}
+
+
+.text-uppercase, .copyright {
+ color: white;
+}
+
+#itsy-foot p {
+ color: #ffffff;
+ font-size: 17px;
+}
+
diff --git a/app/assets/stylesheets/categories.scss b/app/assets/stylesheets/categories.scss
new file mode 100644
index 0000000000..181c95946f
--- /dev/null
+++ b/app/assets/stylesheets/categories.scss
@@ -0,0 +1,68 @@
+// 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/
+
+// main {
+// min-height: 500px;
+// padding: 10%;
+// margin-top: -5px;
+// border-radius: 0px 0px 10px 10px;
+// }
+
+.list{
+ display: inline;
+
+}
+
+.category-heading{
+ padding-top: 6%;
+ padding-bottom: 3%;
+}
+.category-container {
+ display: block;
+ flex-direction: column;
+ text-align: center;
+ padding-top: 10%
+}
+
+.category-img {
+ width: 60%;
+ height: auto;
+ vertical-align: middle;;
+}
+
+.category-link {
+ font-size: 20pt;
+}
+
+.list-type4{
+ width:410px;
+ margin:0 auto;
+}
+
+.list-type4 ul{
+ counter-reset: li;
+ list-style: none;
+ *list-style: decimal;
+ font-size: 15px;
+ padding: 0;
+ margin-bottom: 4em;
+}
+
+.list-type4 a{
+ position: relative;
+ display: block;
+ // padding: .4em .4em .4em 2em;
+ *padding: .4em;
+ margin: .5em 0;
+ background: #de99f5;
+ color: white;
+ text-decoration: none;
+ box-shadow:inset 0.5em 0 black;
+ -webkit-transition: box-shadow 1s; /* For Safari 3.1 to 6.0 */
+ transition: box-shadow 1s;
+}
+
+.list-type4 a:hover{
+ box-shadow:inset 2em 0 black;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/homepages.scss b/app/assets/stylesheets/homepages.scss
new file mode 100644
index 0000000000..2305c36d10
--- /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/merchants.scss b/app/assets/stylesheets/merchants.scss
new file mode 100644
index 0000000000..98792274fe
--- /dev/null
+++ b/app/assets/stylesheets/merchants.scss
@@ -0,0 +1,104 @@
+// 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/
+section {
+ padding: 60px 0;
+}
+
+div h1.section-title {
+ text-align: center;
+ color: #007b5e;
+ margin-bottom: 50px;
+ text-transform: uppercase;
+}
+
+#tabs {
+background-color:transparent;
+ color: #333;
+}
+
+#tabs h6.section-title {
+ color: #eee;
+}
+
+#tabs .nav-tabs .nav-item.show .nav-link, .nav-tabs .nav-link.active {
+ color: #333;
+ background-color: transparent;
+border-color: transparent transparent #f3f3f3;
+ border-bottom: 4px solid !important;
+ font-size: 1.5em;
+ font-weight: bold;
+}
+
+#tabs .nav-tabs .nav-link {
+ border: 1px solid transparent;
+ border-top-left-radius: .25rem;
+ border-top-right-radius: .25rem;
+ color: #333;
+ font-size: 1.5em;
+}
+
+
+/* Merchant Index */
+
+.all-merchants-head {
+ padding-top: 5%;
+ padding-bottom: 3%;
+ text-align: center;
+}
+
+.merch-list-container {
+ padding-bottom: 3%;
+// text-decoration: underline;
+ text-align: center;
+}
+
+/* Merchant Show */
+
+.img-responsive {
+ width:100%;
+}
+
+.table img {
+ max-width: 30%;
+}
+
+.table {
+ padding-left: 5%;
+ width: 100%;
+}
+
+.merch-container {
+ padding: 5%;
+ /* width: 500px; */
+ height: 700px;
+ align-items: center;
+}
+
+.username-heading {
+ text-align: center;
+}
+
+.merch-header {
+ padding-top: 5%;
+ background:#c3e9d6;
+}
+
+.merch-header {
+ padding-left: 5%;
+ padding-top: 3%;
+ padding-bottom: 3%;
+ margin-bottom: 3%;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
+ color: white;
+ text-shadow: 2px 2px #77be9b;
+}
+
+.dashboard-title {
+ padding-top: 5%;
+ text-align: center;
+}
+
+.merchant-content {
+ padding: 5%;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/order.scss b/app/assets/stylesheets/order.scss
new file mode 100644
index 0000000000..3d54d9a374
--- /dev/null
+++ b/app/assets/stylesheets/order.scss
@@ -0,0 +1,48 @@
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
+/* Filled cart */
+
+.cart-heading {
+ padding-top: 10%;
+ text-align: center;
+ }
+
+ .cart-cost {
+ padding-right: 10%;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ background: #dfeee6;
+ text-align: right;
+ }
+
+ .cart-cost-divider {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #88ccaa;;
+ margin: 1em 0; padding: 0;
+ }
+
+ .total-cost {
+ font-weight: bold;
+ }
+
+ .checkout-btn {
+ padding-left: 75%;
+ }
+ /* Empty Cart */
+ .empty-head {
+ padding-top: 5%;
+
+ .button-container {
+ text-align: center;
+ }
+ }
+
+ /* Checkout page */
+
+ .checkout-heading {
+ padding-top: 10%;
+ text-align: center;
+ }
+
\ No newline at end of file
diff --git a/app/assets/stylesheets/orderitems.scss b/app/assets/stylesheets/orderitems.scss
new file mode 100644
index 0000000000..651ea3f922
--- /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..36a5020be4
--- /dev/null
+++ b/app/assets/stylesheets/orders.scss
@@ -0,0 +1,57 @@
+// 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/
+
+/* Filled cart */
+
+.cart-heading {
+ padding-top: 10%;
+ text-align: center;
+}
+
+.cart-cost {
+ padding-right: 10%;
+ padding-top: 10px;
+ padding-bottom: 5px;
+ background: #dfeee6;
+ text-align: right;
+}
+
+.cart-cost-divider {
+ display: block;
+ height: 1px;
+ border: 0;
+ border-top: 1px solid #88ccaa;;
+ margin: 1em 0; padding: 0;
+}
+
+.total-cost {
+ font-weight: bold;
+}
+
+.checkout-btn {
+ padding-left: 75%;
+}
+/* Empty Cart */
+.empty-head {
+ padding-top: 5%;
+ text-align: center;
+}
+
+.banner {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+}
+
+.button-container {
+ text-align: center;
+}
+
+/* Checkout page */
+
+.checkout-heading {
+ padding-top: 10%;
+ text-align: center;
+}
+
diff --git a/app/assets/stylesheets/products.scss b/app/assets/stylesheets/products.scss
new file mode 100644
index 0000000000..27e8131aa3
--- /dev/null
+++ b/app/assets/stylesheets/products.scss
@@ -0,0 +1,18 @@
+// 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/
+
+.card-columns {
+ padding-top: 10%;
+ z-index: -1;
+ position: relative;
+}
+
+.product-show-img {
+ max-width: 70%;
+}
+
+.product-main-article {
+ padding: 3%;
+ padding-top: 12%;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/reviews.scss b/app/assets/stylesheets/reviews.scss
new file mode 100644
index 0000000000..41285ad069
--- /dev/null
+++ b/app/assets/stylesheets/reviews.scss
@@ -0,0 +1,8 @@
+// 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/
+
+
+.review-main {
+ padding-top: 10%;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/root.scss b/app/assets/stylesheets/root.scss
new file mode 100644
index 0000000000..9e9a6ff992
--- /dev/null
+++ b/app/assets/stylesheets/root.scss
@@ -0,0 +1,145 @@
+section {
+ padding-bottom: 0px;
+}
+
+hr {
+ border: 0;
+ clear:both;
+ display:block;
+ width: 96%;
+ background-color: gainsboro;
+ height: 1px;
+}
+
+/* Carousel */
+
+#carousel {
+ display: block !important;
+ z-index: -1;
+ max-width: 100%;
+}
+
+.w-100 {
+ width: 100% !important;
+}
+
+.container {
+ /* width: 500px; */
+ /* height: 700px; */
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+ align-items: center;
+}
+
+/* Featured Section */
+
+#featured-section {
+ display: flex;
+ flex-direction: row;
+}
+
+.product-name {
+ font-size: 20px;
+ font-weight: bold;
+ color: #099a97;
+}
+
+.featured-products {
+ display: flex;
+ justify-content: space-evenly;
+ padding-right: 7rem;
+ padding-left: 7rem;
+ padding-bottom: 4rem;
+}
+
+.featured-img {
+ margin-right: 10px;
+ margin-left: 10px;
+ padding-right: 10px;
+ padding-left: 10px;
+ border: solid;
+ border-color: #95d9b3;
+ border-width: 1px;
+ border-radius: 6px;
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+
+.container p {
+ padding-top: 10px;
+ text-align: center;
+}
+
+.featured-merchant {
+ margin: -20px;
+ font-size: 10pt;
+}
+
+/* Slogan Box */
+
+.slogan-box {
+ background-color: #e2f5ea ;
+ display: flex;
+ justify-content: space-evenly;
+ padding-right: 7rem;
+ padding-left: 7rem;
+ padding-top: 4rem;
+ padding-bottom: 4rem;
+}
+
+.slogan-box img {
+ object-fit: cover;
+ max-width: 500px;
+ max-height: 500px;
+}
+
+h2.whats-itsy {
+ border-bottom: 2px solid #000;
+ padding-bottom: 3px;
+}
+
+div.about-itsy {
+ display: flex;
+ flex-direction: column;
+ padding-left: 3rem;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+}
+
+/* Featured Categories */
+
+.featured-cat-title {
+ padding-bottom: 8px;
+ text-align: center;
+}
+.featured-categories {
+ display: inline-flex;
+ flex-direction: row;
+ justify-content: space-evenly;
+ padding-right: 7rem;
+ padding-left: 7rem;
+ padding-top: 4rem;
+ padding-bottom: 4rem;
+}
+
+.feat-cat {
+ width: 100%;
+ height: 80%;
+ // margin-right: 10px;
+ // margin-left: 10px;
+ padding-right: 20px;
+ padding-left: 20px;
+}
+
+.btn-primary {
+ color: white;
+ border: 1px #292F36 solid;
+}
+
+div.card-deck {
+ z-index: -1;
+}
+
diff --git a/app/assets/stylesheets/sessions.scss b/app/assets/stylesheets/sessions.scss
new file mode 100644
index 0000000000..ccb1ed25b2
--- /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/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb
new file mode 100644
index 0000000000..d672697283
--- /dev/null
+++ b/app/channels/application_cable/channel.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Channel < ActionCable::Channel::Base
+ end
+end
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
new file mode 100644
index 0000000000..0ff5442f47
--- /dev/null
+++ b/app/channels/application_cable/connection.rb
@@ -0,0 +1,4 @@
+module ApplicationCable
+ class Connection < ActionCable::Connection::Base
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
new file mode 100644
index 0000000000..322ee1d4c3
--- /dev/null
+++ b/app/controllers/application_controller.rb
@@ -0,0 +1,16 @@
+class ApplicationController < ActionController::Base
+ before_action :find_merchant
+
+ def find_merchant
+ @current_merchant = Merchant.find_by(id: session[:user_id])
+ end
+
+ def require_login
+ current_merchant = find_merchant
+ if current_merchant.nil?
+ flash[:status] = :error
+ flash[:result_text] = "You must be logged in to perform this action."
+ redirect_to root_path
+ end
+ end
+end
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb
new file mode 100644
index 0000000000..3dd650e939
--- /dev/null
+++ b/app/controllers/categories_controller.rb
@@ -0,0 +1,55 @@
+class CategoriesController < ApplicationController
+ before_action :require_login, only: [:new, :create]
+
+ def index
+ @categories = Category.all
+ end
+
+ def show
+ @category = Category.find_by(id: params[:id])
+
+ if !@category
+ flash[:status] = :warning
+ flash[:result_text] = "A problem occurred: Media not found"
+ redirect_to root_path
+ end
+ end
+
+ def new
+ @category = Category.new
+ end
+
+ def create
+ @category = Category.new(category_params)
+ if @category.save
+ flash[:status] = :success
+ flash[:result_text] = "Successfully created #{@category.name} category"
+ redirect_to merchant_path(session[:user_id])
+ else
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not add category"
+ @category.errors.messages.each do |field, messages|
+ flash.now[field] = messages
+ end
+ render :new, status: :bad_request
+ end
+ end
+
+ private
+
+ def current_user
+ @current_user ||= Merchant.find(session[:user_id]) if session[:user_id]
+ end
+
+ def require_login
+ if current_user.nil?
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: You must login to view this page"
+ redirect_to root_path
+ end
+ end
+
+ def category_params
+ return params.require(:category).permit(:name)
+ end
+end
diff --git a/app/controllers/concerns/.keep b/app/controllers/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/controllers/homepages_controller.rb b/app/controllers/homepages_controller.rb
new file mode 100644
index 0000000000..647748af42
--- /dev/null
+++ b/app/controllers/homepages_controller.rb
@@ -0,0 +1,7 @@
+class HomepagesController < ApplicationController
+ def root
+ end
+
+ def about
+ end
+end
diff --git a/app/controllers/merchants_controller.rb b/app/controllers/merchants_controller.rb
new file mode 100644
index 0000000000..a9b9c42465
--- /dev/null
+++ b/app/controllers/merchants_controller.rb
@@ -0,0 +1,30 @@
+class MerchantsController < ApplicationController
+ before_action :find_merchant, only: [:show, :dashboard]
+
+ def index
+ @merchants = Merchant.all
+ end
+
+ def show
+ end
+
+ def dashboard
+ @merchant = Merchant.find_by(id: session[:user_id])
+ @orderitems = @merchant.items_by_status("all")
+ @pendingitems = Merchant.items_by_orderid(@orderitems["pending"])
+ @paiditems = Merchant.items_by_orderid(@orderitems["paid"])
+ @completeitems = Merchant.items_by_orderid(@orderitems["complete"])
+ @cancelleditems = Merchant.items_by_orderid(@orderitems["cancelled"])
+ @products = @merchant.products
+ @activeproducts = @products.order(:name).where(active: true).where("stock > ?", 0)
+ @soldout = @products.order(:name).where(active: true).where(stock: 0)
+ @inactive = @products.order(:name).where(active: false)
+ end
+
+ private
+
+ def find_merchant
+ @merchant = Merchant.find_by(id: params[:id])
+ head :not_found unless @merchant
+ end
+end
diff --git a/app/controllers/orderitems_controller.rb b/app/controllers/orderitems_controller.rb
new file mode 100644
index 0000000000..7da68f9f75
--- /dev/null
+++ b/app/controllers/orderitems_controller.rb
@@ -0,0 +1,101 @@
+class OrderitemsController < ApplicationController
+ def create
+ # raise
+ @product = Product.find_by(id: params[:product_id])
+
+ if @product
+ @orderitem = Orderitem.new(orderitem_params)
+ # not actually changing stock, just using this as a device to generate errors
+ @product.stock -= params[:orderitem][:quantity].to_i
+
+ if !@product.valid?
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: not enough available stock"
+ redirect_to product_path(@product.id)
+ return
+ end
+
+ if !session[:order_id]
+ @order = Order.create
+ session[:order_id] = @order.id
+ end
+ @orderitem.product_id = @product.id
+ @orderitem.order_id = session[:order_id]
+ is_successful = @orderitem.save
+
+ if is_successful
+ flash[:status] = :success
+ flash[:result_text] = "Succesfully added an itsy item to your cart"
+ redirect_to product_path(@product.id)
+ else
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not add item to cart"
+ @orderitem.errors.messages.each do |field, messages|
+ flash.now[field] = messages
+ end
+ redirect_to product_path(@product.id)
+ end
+ else
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Can't find product"
+ redirect_to products_path
+ end
+ end
+
+ def update
+ @orderitem = Orderitem.find_by(id: params[:id])
+ if !@orderitem
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not find item"
+ redirect_to root_path
+ else
+ @product = @orderitem.product
+ # not actually changing stock, just using this as a device to generate errors
+ @product.stock -= params[:quantity].to_i
+
+ if !@product.valid?
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: not enough available stock"
+ redirect_to order_path(@orderitem.order.id)
+ return
+ end
+
+ @orderitem.quantity = params[:quantity].to_i
+ if @orderitem.save
+ flash[:status] = :success
+ flash[:result_text] = "Successfully updated item: #{@orderitem.product.name}"
+ redirect_to order_path(@orderitem.order.id)
+ else
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not update item"
+ @orderitem.errors.messages.each do |field, messages|
+ flash.now[field] = messages
+ end
+ redirect_to order_path(@orderitem.order.id)
+ end
+ end
+ end
+
+ def destroy
+ orderitem = Orderitem.find_by(id: params[:id])
+ if orderitem.nil?
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not find item"
+ if !session[:order_id]
+ redirect_to products_path
+ return
+ end
+ else
+ orderitem.destroy
+ flash[:status] = :success
+ flash[:result_text] = "Succesfully deleted item!"
+ end
+ redirect_to order_path(session[:order_id])
+ end
+
+ private
+
+ def orderitem_params
+ return params.require(:orderitem).permit(:quantity)
+ end
+end
diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb
new file mode 100644
index 0000000000..a08047cdc6
--- /dev/null
+++ b/app/controllers/orders_controller.rb
@@ -0,0 +1,114 @@
+class OrdersController < ApplicationController
+ before_action :find_order, only: [:edit, :update, :show, :review, :confirmation]
+
+ def index
+ @orders = Order.all
+ end
+
+ def update
+ if @order.nil?
+ redirect_to products_path
+ else
+ @order.update(status: Order::PENDING)
+ is_successful = @order.update(order_params)
+ if is_successful
+ redirect_to review_order_path(@order.id)
+ else
+ @order.errors.messages.each do |field, message|
+ flash.now[field] = message
+ end
+
+ render :edit, status: :bad_request
+ end
+ end
+ end
+
+ def show
+ if @order.nil?
+ flash[:status] = :error
+ flash[:result_text] = "Order not found!"
+ redirect_to orders_path
+ elsif @order.orderitems
+ @order.orderitems.each do |item|
+ orig_quantity = item.quantity
+ new_quantity = item.adjust_quantity
+ no_stock = true if new_quantity == 0
+ if orig_quantity != new_quantity
+ # had to write this in a weird way so that the test would pass
+ if flash.now[:status] != :warning
+ flash.now[:status] = :warning
+ flash.now[:result_text] = "Some item quantities in your cart have changed due to availability: #{item.product.name}"
+ else
+ flash.now[:result_text] << ", #{item.product.name}"
+ end
+ item.destroy if no_stock
+ end
+ end
+ end
+ end
+
+ def review
+ end
+
+ def confirmation
+ if @order.nil?
+ redirect_to root_path
+ else
+ @order.update(status: Order::PAID)
+ session[:order_id] = nil
+ # @temp_orderitems = []
+ # @order.orderitems.each do |item|
+ # hash = {
+ # orderitem_id: item.id,
+ # product_name: item.product.name,
+ # product_price: item.product.price,
+ # quantity: item.quantity,
+ # item_total: item.quantity * item.product.price,
+ # }
+
+ # @temp_orderitems << hash
+ # end
+ end
+ end
+
+ def cancel
+ @order = Order.find_by(id: params[:id])
+
+ if @order.nil?
+ flash[:status] = :error
+ flash[:result_text] = "Order does not exist."
+ redirect_to root_path
+ else
+ is_succesfull = @order.update(status: Order::CANCELLED)
+ session[:order_id] = nil
+ flash[:status] = :success
+ flash[:result_text] = "Your order has been cancelled."
+
+ redirect_to root_path
+ end
+ end
+
+ def shipped
+ @order = Order.find_by(id: params[:id])
+
+ if @order
+ @order.update(status: Order::COMPLETE)
+ flash[:status] = :success
+ flash[:result_text] = "Little order ##{@order.id} marked shipped!"
+ else
+ flash[:status] = :warning
+ flash[:result_text] = "An itsy problem occurred: Could not find order"
+ end
+ redirect_to dashboard_path(session[:user_id])
+ end
+
+ private
+
+ def find_order
+ @order = Order.find_by(id: session[:order_id])
+ end
+
+ def order_params
+ return params.require(:order).permit(:address, :name, :status, :cc, :expiration_date, :email, :csv)
+ end
+end
diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb
new file mode 100644
index 0000000000..20630accbe
--- /dev/null
+++ b/app/controllers/products_controller.rb
@@ -0,0 +1,99 @@
+class ProductsController < ApplicationController
+ before_action :find_product, only: [:show, :edit, :update, :status, :retire]
+ before_action :find_merchant, only: [:new, :edit, :create]
+ before_action :require_login, only: [:new, :edit, :update, :create, :retire]
+
+ def index
+ @products = Product.active_products
+ end
+
+ def show
+ @orderitem = Orderitem.new
+ @review = Review.new
+ @reviews = @product.reviews if @product
+ if @product.nil? || @product.active == false
+ flash[:status] = :warning
+ flash[:result_text] = "#{@product.name} is not active."
+ redirect_to dashboard_path(session[:user_id])
+ end
+ # if @product.nil?
+ # flash[:status] = :error
+ # flash[:result_text] = "Product does not exist."
+ # redirect_to dashboard_path
+ # elsif @product.active == false
+ # flash[:status] = :warning
+ # flash[:result_text] = "#{@product.name} is not active."
+ # redirect_to dashboard_path
+ # else
+ # @reviews = @product.reviews
+ # end
+ end
+
+ def retire
+ @product.active = false if @product
+ if @product.save
+ flash[:status] = :success
+ flash[:result_text] = "#{@product.name} has been retired."
+ redirect_to dashboard_path(session[:user_id])
+ end
+ end
+
+ def new
+ @product = Product.new
+ end
+
+ def edit
+ if @product.nil?
+ flash[:status] = :error
+ flash[:result_text] = "Product not found."
+ redirect_to dashboard_path(session[:user_id])
+ end
+ end
+
+ def create
+ params = product_params
+ params[:merchant_id] = session[:user_id]
+ params[:photo_url] = "http://placekitten.com/200/300" if params[:photo_url].nil?
+
+ @product = Product.new(params)
+
+ if @product.save
+ flash[:status] = :success
+ flash[:result_text] = "Successfully created #{@product.name}"
+ redirect_to product_path(@product)
+ else
+ flash[:status] = :error
+ flash[:result_text] = "Experiencing an issue with creating the product."
+ flash[:messages] = @product.errors.messages
+ render :new, status: :bad_request
+ end
+ end
+
+ def update
+ if @product.update(product_params)
+ merchant_id = session[:user_id]
+ flash[:status] = :success
+ flash[:result_text] = "Successfully updated #{@product.name}"
+ redirect_to product_path(@product.id)
+ else
+ flash[:status] = :error
+ flash[:result_text] = "Failed to update"
+ flash[:messages] = @product.errors.messages
+ render :edit, status: :bad_request
+ end
+ end
+
+ private
+
+ def find_product
+ @product = Product.find_by(id: params[:id].to_i)
+
+ if @product.nil?
+ flash.now[:warning] = "Cannot find the product #{params[:id]}"
+ end
+ end
+
+ def product_params
+ params.require(:product).permit(:name, :price, :description, :photo_url, :active, :merchant_id, :stock, category_ids: [])
+ end
+end
diff --git a/app/controllers/reviews_controller.rb b/app/controllers/reviews_controller.rb
new file mode 100644
index 0000000000..220c2d4e7e
--- /dev/null
+++ b/app/controllers/reviews_controller.rb
@@ -0,0 +1,40 @@
+class ReviewsController < ApplicationController
+ def new
+ @review = Review.new
+ end
+
+ def create
+ @product = Product.find_by(id: params[:product_id])
+ @review = Review.new(review_params)
+
+ if @product
+ if @product.merchant_id == session[:user_id]
+ flash[:status] = :error
+ flash[:result_text] = "An itsy problem occurred: You can't rate your own products"
+ redirect_to dashboard_path(session[:user_id])
+ return
+ end
+
+ if @product.reviews << @review
+ flash[:status] = :success
+ flash[:result_text] = "Thank you for your feedback"
+ redirect_to product_path(params[:product_id])
+ else
+ flash[:status] = :error
+ flash[:result_text] = "An itsy problem occurred: Could not process feedback"
+ @review.errors.messages.each do |field, messages|
+ flash.now[field] = messages
+ end
+ render :new, status: :bad_request
+ end
+ else
+ flash[:status] = :error
+ flash[:result_text] = "An itsy problem occurred: Product not found"
+ redirect_to products_path
+ end
+ end
+
+ def review_params
+ return params.require(:review).permit(:rating, :body)
+ end
+end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
new file mode 100644
index 0000000000..02379a2663
--- /dev/null
+++ b/app/controllers/sessions_controller.rb
@@ -0,0 +1,29 @@
+class SessionsController < ApplicationController
+ def create
+ auth_hash = request.env["omniauth.auth"]
+
+ merchant = Merchant.find_by(uid: auth_hash[:uid], provider: "github")
+
+ if merchant
+ flash[:success] = "Welcome #{merchant.username}"
+ else
+ merchant = Merchant.build_from_github(auth_hash)
+
+ if merchant.save
+ flash[:success] = "Logged in as #{merchant.username}"
+ else
+ flash[:error] = "Could not log in with account #{merchant.errors.messages}"
+ return redirect_to root_path
+ end
+ end
+
+ session[:user_id] = merchant.id
+ return redirect_to root_path
+ end
+
+ def destroy
+ session[:user_id] = nil
+ flash[:success] = "Successfully logged out"
+ redirect_to root_path
+ end
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
new file mode 100644
index 0000000000..21dde82cff
--- /dev/null
+++ b/app/helpers/application_helper.rb
@@ -0,0 +1,36 @@
+module ApplicationHelper
+ def display_price(price)
+ ("" + "#{number_to_currency(price)}" + "").html_safe
+ end
+
+ def display_date(date)
+ ("" + "#{date.strftime("%B %d, %Y")} at #{date.strftime("%H:%M %p")}" + "").html_safe
+ end
+
+ def cc_display(order)
+ cc = order.cc_num.gsub(/\D/, '')
+ last = cc.size - 1
+ first = cc.size - 4
+ return cc[first..last]
+ end
+
+ def shopping_cart_count(count)
+ ''.html_safe + "#{count}" ''.html_safe
+ end
+
+ def orderitems_total_quantity(orderitems)
+ if orderitems.nil?
+ return 0
+ else
+ return orderitems.sum {|oi| oi.quantity }
+ end
+ end
+
+ def display_order(order)
+ if order == 1
+ return "Order"
+ else
+ return "Orders"
+ end
+ end
+end
diff --git a/app/helpers/categories_helper.rb b/app/helpers/categories_helper.rb
new file mode 100644
index 0000000000..e06f31554c
--- /dev/null
+++ b/app/helpers/categories_helper.rb
@@ -0,0 +1,2 @@
+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..5337747b0f
--- /dev/null
+++ b/app/helpers/merchants_helper.rb
@@ -0,0 +1,2 @@
+module MerchantsHelper
+end
diff --git a/app/helpers/order_helper.rb b/app/helpers/order_helper.rb
new file mode 100644
index 0000000000..05d197a0c1
--- /dev/null
+++ b/app/helpers/order_helper.rb
@@ -0,0 +1,2 @@
+module OrderHelper
+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..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/jobs/application_job.rb b/app/jobs/application_job.rb
new file mode 100644
index 0000000000..a009ace51c
--- /dev/null
+++ b/app/jobs/application_job.rb
@@ -0,0 +1,2 @@
+class ApplicationJob < ActiveJob::Base
+end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
new file mode 100644
index 0000000000..286b2239d1
--- /dev/null
+++ b/app/mailers/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: 'from@example.com'
+ layout 'mailer'
+end
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
new file mode 100644
index 0000000000..10a4cba84d
--- /dev/null
+++ b/app/models/application_record.rb
@@ -0,0 +1,3 @@
+class ApplicationRecord < ActiveRecord::Base
+ self.abstract_class = true
+end
diff --git a/app/models/category.rb b/app/models/category.rb
new file mode 100644
index 0000000000..6ebaae575b
--- /dev/null
+++ b/app/models/category.rb
@@ -0,0 +1,6 @@
+class Category < ApplicationRecord
+ has_and_belongs_to_many :products
+
+ # unique
+ validates :name, presence: true, uniqueness: true
+end
diff --git a/app/models/concerns/.keep b/app/models/concerns/.keep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/app/models/merchant.rb b/app/models/merchant.rb
new file mode 100644
index 0000000000..104663c623
--- /dev/null
+++ b/app/models/merchant.rb
@@ -0,0 +1,90 @@
+class Merchant < ApplicationRecord
+ STATUSES = %w(Pending Paid Complete Cancelled)
+
+ has_many :products
+ has_many :orderitems, through: :products
+ validates :username, presence: true, uniqueness: true
+ validates :email, presence: true, uniqueness: true
+
+ def self.build_from_github(auth_hash)
+ return Merchant.new(uid: auth_hash[:uid],
+ provider: "github",
+ email: auth_hash["info"]["email"],
+ username: auth_hash["info"]["name"])
+ end
+
+ def items_by_status(status)
+ items = self.orderitems.group_by { |oid| oid.order.status }
+
+ available_statuses = items.keys
+
+ if status == "all"
+ return items
+ else
+ if STATUSES.include?(status) && available_statuses.include?(status)
+ return items[status]
+ # orderitem[status]
+ else
+ return []
+ end
+ end
+ end
+
+ def self.items_by_orderid(items)
+ if items.nil? || items.empty?
+ return []
+ end
+ items = items.group_by { |oi| oi.order.id }
+ return items
+ end
+
+ def total_revenue
+ paid_items = self.items_by_status("Paid")
+ complete_items = self.items_by_status("Complete")
+
+ if paid_items.nil?
+ revenue_paid = 0
+ else
+ revenue_paid = paid_items.sum { |oi| oi.total_price }
+ end
+
+ if complete_items.nil?
+ revenue_complete = 0
+ else
+ revenue_complete = complete_items.sum { |oi| oi.total_price }
+ end
+
+ return revenue_paid + revenue_complete
+ end
+
+ def revenue_by_status
+ revenue = Hash.new
+ paid_items = self.items_by_status("Paid")
+ complete_items = self.items_by_status("Complete")
+
+ if paid_items.nil?
+ revenue["paid"] = 0
+ else
+ revenue["paid"] = paid_items.sum { |oi| oi.total_price }
+ end
+
+ if complete_items.nil?
+ revenue["complete"] = 0
+ else
+ revenue["complete"] = complete_items.sum { |oi| oi.total_price }
+ end
+
+ return revenue
+ end
+
+ def orders_by_status(status)
+ orders = []
+
+ self.orderitems.each do |item|
+ if !orders.include?(Order.where(id: item.order.id)) && item.order.status == status
+ orders << item.order
+ end
+ return orders
+ end
+ end
+end
diff --git a/app/models/order.rb b/app/models/order.rb
new file mode 100644
index 0000000000..4548db42a9
--- /dev/null
+++ b/app/models/order.rb
@@ -0,0 +1,33 @@
+class Order < ApplicationRecord
+ has_many :orderitems
+ # validates :name, presence: true, allow_nil: true, if: :status_nil?
+ validates :name, presence: true, allow_nil: false, unless: :status_nil?
+ # validates :email, presence: true, allow_nil: true, if: :status_nil?
+ validates :email, presence: true, allow_nil: false, unless: :status_nil?
+ validates :address, presence: true, allow_nil: false, unless: :status_nil?
+ validates :cc, presence: true, allow_nil: false, unless: :status_nil?
+ validates :csv, presence: true, allow_nil: false, unless: :status_nil?
+ validates :expiration_date, presence: true, allow_nil: false, unless: :status_nil?
+
+ PENDING = "Pending"
+ PAID = "Paid"
+ COMPLETE = "Complete"
+ CANCELLED = "Cancelled"
+ SHIPPED = "Shipped"
+
+ def status_nil?
+ return true if self.status == nil
+ end
+
+ def sub_total
+ return self.orderitems.map.sum { |item| item.product.price * item.quantity }
+ end
+
+ def tax
+ return sub_total * 0.09
+ end
+
+ def total
+ return tax + sub_total
+ end
+end
diff --git a/app/models/orderitem.rb b/app/models/orderitem.rb
new file mode 100644
index 0000000000..ba0b8f4a8d
--- /dev/null
+++ b/app/models/orderitem.rb
@@ -0,0 +1,24 @@
+class Orderitem < ApplicationRecord
+ belongs_to :order
+ belongs_to :product
+
+ validates :quantity, presence: true, numericality: { greater_than: 0 }
+ def self.status
+ return self.order.status
+ end
+
+ def adjust_quantity
+ product = self.product
+ if product.stock < self.quantity
+ self.quantity = product.stock
+ self.save
+ return product.stock
+ else
+ return self.quantity
+ end
+ end
+
+ def total_price
+ return self.quantity * self.product.price
+ end
+end
diff --git a/app/models/product.rb b/app/models/product.rb
new file mode 100644
index 0000000000..3530ab4dae
--- /dev/null
+++ b/app/models/product.rb
@@ -0,0 +1,30 @@
+class Product < ApplicationRecord
+ has_and_belongs_to_many :categories
+ has_many :reviews
+ belongs_to :merchant
+ has_many :orderitems
+ has_many :orders, through: :orderitems
+
+ validates :name, presence: true, uniqueness: { scope: :merchant, message: "Merchant's products must have unique names " }
+ validates :price, presence: true, numericality: { greater_than: 0, message: "Price must be greater than 0" }
+ validates :stock, presence: true, numericality: { greater_than_or_equal_to: 0, message: "Stock cannot go below 0" }
+
+ def self.active_products
+ return Product.where(active: :true)
+ end
+
+ def average_rating
+ sum = 0
+ count = self.reviews.count
+
+ if count == 0
+ return 0
+ else
+ self.reviews.each do |review|
+ sum += review.rating
+ end
+
+ return (sum * 1.0 / count).round(2)
+ end
+ end
+end
diff --git a/app/models/review.rb b/app/models/review.rb
new file mode 100644
index 0000000000..4723efe3db
--- /dev/null
+++ b/app/models/review.rb
@@ -0,0 +1,8 @@
+class Review < ApplicationRecord
+ belongs_to :product
+
+ validates :rating, presence: true,
+ :inclusion => { :in => 1..5,
+ :message => "must be a number between 1 and 5" }
+ validates :body, presence: true
+end
diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb
new file mode 100644
index 0000000000..0986f687b9
--- /dev/null
+++ b/app/views/categories/index.html.erb
@@ -0,0 +1,12 @@
+Itsy Categories
+ <% @categories.each do |category| %>
+
+
+ <% end %>
+ Create a new category
+
+ <%= form_with model: @category, url: categories_path do |f|%>
+
+ <%= @category.name %>
+
+
+
+
+
+
+
+ <% @category.products.each do |product| %>
+ Photo
+ Name
+ Price
+
+
+ <% end %>
+
+
+ <%= link_to product.name, product_path(product.id) %>
+ <%= product.price %>
+
Itsy is the global marketplace for all things SMALL. It’s home to a
+ universe of perfectly small, extraordinary items, from unique handcrafted pieces to vintage treasures.
+ Born from a shared passion between friends, Itsy is now that #1 retail destination in the
+ world! Mini is the new big, and we're proud to be at the forefront.
+
+
Kate Sandler is fueled by her passion for understanding the nuances of all things + tiny. She considers herself a ‘mini die-hard,’ eager to both build on her + academic foundations in itsyology and stay in tune with the latest + miniature marketing strategies through continued coursework and professional development.
+Itsy Engineer
+Kim Fasbender is fueled by her passion for understanding the nuances of all things + tiny. She considers herself a ‘mini die-hard,’ eager to both build on her + academic foundations in itsyology and stay in tune with the latest + miniature marketing strategies through continued coursework and professional development.
+Itsy Engineer
+Sopheary Chiv is fueled by her passion for understanding the nuances of all things + tiny. She considers herself a ‘mini die-hard,’ eager to both build on her + academic foundations in itsyology and stay in tune with the latest + miniature marketing strategies through continued coursework and professional development.
+Itsy Engineer
+Stephanie Marchante is fueled by her passion for understanding the nuances of all things + tiny. She considers herself a ‘mini die-hard,’ eager to both build on her + academic foundations in itsyology and stay in tune with the latest + miniature marketing strategies through continued coursework and professional development.
+Itsy Engineer
+
+ Bitty Burger
+ + +lucky7
+ +
+ It's a big world, but it's the tiny things that matter. We're passionate about the simple smallities that bring some micro-mini to your day.
+ About Us +
+
+
+
+