diff --git a/Customer b/Customer new file mode 100644 index 00000000..f2d34265 --- /dev/null +++ b/Customer @@ -0,0 +1,378 @@ +=> [#, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + #, + # 5.2' gem "sinatra-activerecord" -gem "sqlite3" +gem "sqlite3", '~> 1.3.6' gem "pry" gem "require_all" +gem "faker" +gem "rake" +gem "tty-prompt" +gem "pastel" +gem "tty-progressbar" +gem "tty-spinner" +gem 'tty-font' +gem 'date' +gem 'rest-client' +gem 'json' + diff --git a/Gemfile.lock b/Gemfile.lock index 9589226d..acfd83fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,56 +1,112 @@ GEM remote: https://rubygems.org/ specs: - activemodel (6.0.3.1) - activesupport (= 6.0.3.1) - activerecord (6.0.3.1) - activemodel (= 6.0.3.1) - activesupport (= 6.0.3.1) - activesupport (6.0.3.1) + activemodel (5.2.4.4) + activesupport (= 5.2.4.4) + activerecord (5.2.4.4) + activemodel (= 5.2.4.4) + activesupport (= 5.2.4.4) + arel (>= 9.0) + activesupport (5.2.4.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - zeitwerk (~> 2.2, >= 2.2.2) - coderay (1.1.1) - concurrent-ruby (1.1.6) - i18n (1.8.2) + arel (9.0.0) + coderay (1.1.3) + concurrent-ruby (1.1.7) + date (3.0.1) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) + faker (2.15.1) + i18n (>= 1.6, < 2) + http-accept (1.7.0) + http-cookie (1.0.3) + domain_name (~> 0.5) + i18n (1.8.5) concurrent-ruby (~> 1.0) - method_source (0.8.2) - minitest (5.14.1) - mustermann (1.0.3) - pry (0.10.4) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) + json (2.3.1) + method_source (1.0.0) + mime-types (3.3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2020.1104) + minitest (5.14.2) + mustermann (1.1.1) + ruby2_keywords (~> 0.0.1) + netrc (0.11.0) + pastel (0.8.0) + tty-color (~> 0.5) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) rack (2.2.3) - rack-protection (2.0.7) + rack-protection (2.1.0) rack - require_all (1.3.3) - sinatra (2.0.7) + rake (13.0.1) + require_all (3.0.0) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) + ruby2_keywords (0.0.2) + sinatra (2.1.0) mustermann (~> 1.0) - rack (~> 2.0) - rack-protection (= 2.0.7) + rack (~> 2.2) + rack-protection (= 2.1.0) tilt (~> 2.0) - sinatra-activerecord (2.0.12) - activerecord (>= 3.2) + sinatra-activerecord (2.0.21) + activerecord (>= 4.1) sinatra (>= 1.0) - slop (3.6.0) sqlite3 (1.3.13) + strings-ansi (0.1.0) thread_safe (0.3.6) tilt (2.0.10) - tzinfo (1.2.7) + tty-color (0.6.0) + tty-cursor (0.7.1) + tty-font (0.5.0) + tty-progressbar (0.17.0) + strings-ansi (~> 0.1.0) + tty-cursor (~> 0.7) + tty-screen (~> 0.7) + unicode-display_width (~> 1.6) + tty-prompt (0.22.0) + pastel (~> 0.8) + tty-reader (~> 0.8) + tty-reader (0.8.0) + tty-cursor (~> 0.7) + tty-screen (~> 0.8) + wisper (~> 2.0) + tty-screen (0.8.1) + tty-spinner (0.9.3) + tty-cursor (~> 0.7) + tzinfo (1.2.8) thread_safe (~> 0.1) - zeitwerk (2.3.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.7) + unicode-display_width (1.7.0) + wisper (2.0.1) PLATFORMS ruby DEPENDENCIES + activerecord (~> 5.2) + date + faker + json + pastel pry + rake require_all + rest-client sinatra-activerecord - sqlite3 + sqlite3 (~> 1.3.6) + tty-font + tty-progressbar + tty-prompt + tty-spinner BUNDLED WITH 1.14.6 diff --git a/app/models/customer.rb b/app/models/customer.rb new file mode 100644 index 00000000..a7f8c277 --- /dev/null +++ b/app/models/customer.rb @@ -0,0 +1,4 @@ +class Customer < ActiveRecord::Base + has_many :orders + has_many :foods, through: :orders +end \ No newline at end of file diff --git a/app/models/food.rb b/app/models/food.rb new file mode 100644 index 00000000..a8e7cd5e --- /dev/null +++ b/app/models/food.rb @@ -0,0 +1,4 @@ +class Food < ActiveRecord::Base + has_many :orders + has_many :customers, through: :orders +end \ No newline at end of file diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 00000000..d5c52a14 --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,4 @@ +class Order < ActiveRecord::Base + belongs_to :customer + belongs_to :food +end diff --git a/bin/cli.rb b/bin/cli.rb new file mode 100644 index 00000000..33d9e470 --- /dev/null +++ b/bin/cli.rb @@ -0,0 +1,321 @@ +require 'io/console' +require 'tty-prompt' +require 'pry' + +class CLI + + attr_reader :prompt, :font + attr_accessor :customer, :cart + + def main_menu + system 'clear' + @font = TTY::Font.new + @pastel = Pastel.new + opener + puts @pastel.cyan(@font.write(" Shopping Cart !!")) + opener + prompt = TTY::Prompt.new + choices = ['🔹Login' ,'🔹Signup', '🔹Exit'] # '🔹Update Name Info', '🔹Delete Account' + choice = prompt.select("\n 🔹Welcome to Shopping Cart, please make a selection🔹\n", choices) # do not use multi_select it leaves an octogon symble + + if choice == '🔹Login' + attempts = 0 + login(attempts) + elsif choice == '🔹Signup' + signup + elsif choice == '🔹Exit' + exit + end + end + + def signup + system 'clear' + puts "Enter user name" + user_name = gets.chomp + puts "Enter password" + user_password = STDIN.noecho(&:gets).chomp + if !Customer.exists?(name: user_name) + Customer.create(name: user_name , password: user_password) + else + puts "Oops! This user name is already taken!" + + prompt = TTY::Prompt.new + choices = ['🔹Sign-Up With Different User Name' , '🔹Login','🔹Exit'] + choice = prompt.select("\n ? \n",choices) + if choice == '🔹Login' + attempts = 0 + login(attempts) + elsif choice == '🔹Sign-Up With Different User Name' + signup + elsif choice == '🔹Exit' + exit + end + end + # accept user_name & password -> update the table with new user if user name is unique else retry + # go to shopping method - TBD + end + + + def login(attempts=0) + attempts = 0 + system 'clear' + if attempts < 3 + puts "Enter user name" + user_name = gets.chomp + puts "Enter password" + user_password = STDIN.noecho(&:gets).chomp + if Customer.exists?(name: user_name, password: user_password) + shopping + return + else + puts "Invalid User Name or Password" + attempts += 1 + + prompt = TTY::Prompt.new + choices = ['🔹Re-Login' ,'🔹Forgot User Name/Password', '🔹Exit'] + choice = prompt.select("\n ? \n",choices) + if choice == '🔹Re-Login' + login(attempts) + elsif choice == '🔹Forgot User Name/Password' + puts "Sign-Up" + signup + elsif choice == '🔹Exit' + exit + end + end + else + puts "Maximum number of login attempts exceeded. Try again later!" + end + end + + # After 3 attempts - prints max login attempts over -> Advanced -> Do a timestamp-based entry + # Forgot password + # gets user_name & password -> check if password matches user_name in table else 1. Error Msg 2. Exit 3. Re-login 4. Reset Password -> Signup + # shopping + + + def shopping + puts 'yay' + prompt = TTY::Prompt.new + choices = [ '🔹View Profile ', '🔹View Cart', '🔹Get To Shopping','🔹Checkout', '🔹Exit'] + system 'clear' + choice = prompt.select("\n 🔹Welcome Back!!🔹 \n", choices) + if choice == '🔹View Profile' + profile + elsif choice == '🔹View Cart' + view_cart + elsif choice == '🔹Get To Shopping' + go_to_shopping + elsif choice == '🔹Checkout' + checkout + elsif choice == '🔹Exit' + exit + end + end + + + #puts "yay" + #choices = [ '🔹View Profile ', '🔹View Cart', '🔹Get To Shopping','🔹Checkout', '🔹Exit'] + + + + def profile + system 'clear' + prompt = TTY::Prompt.new + choices = ['🔹Reset User Name' ,'🔹Reset Password', '🔹Delete Account', '🔹Exit'] + choice = prompt.select("\n ? \n",choices) + if choice == '🔹Reset User Name' + puts "Enter new user name" + user_name = gets.chomp + Customer.update_attribute(name, user_name) + elsif choice == '🔹Reset Password' + puts "Enter new password" + user_password = STDIN.noecho(&:gets).chomp + Customer.update_attribute(password, user_password) + elsif choice == '🔹Delete Account' + puts "Enter your user name" + user_name = gets.chomp + puts "Enter your password" + user_password = STDIN.noecho(&:gets).chomp + Customer.exists?(name: user_name, password: user_password) + User.destroy_all(name: user_name) + puts "Account Deleted. We hope to see you again soon!" + exit + elsif choice == '🔹Exit' + exit + end + # #reset user_name & password + + # delete account + # go_back + + # go_back + # delete account + + end + + def go_back + #-> if else + end + + def go_to_shopping(cart = []) + system 'clear' + prompt = TTY::Prompt.new + choices = ['🔹Fruits', '🔹Vegetables', '🔹Spices','🔹View Cart', '🔹Checkout', '🔹Exit'] + choice = prompt.select("\n Select an Aisle! \n", choices) + if choice == '🔹Fruits' + prompt = TTY::Prompt.new + fruit_choices = Food.where(category: "Fruits").map{|fruit| fruit.name} + prompt.multi_select("Use Space Bar |____| to select/unselect Fruits, and hit Enter when done.", fruit_choices) + cart << fruit_choices + #puts "fruit added" + go_to_shopping(cart.flatten) + #puts "fruit added" + elsif choice == '🔹Vegetables' + prompt = TTY::Prompt.new + vegetable_choices = Food.where(category: "Vegetables").map{|veg| veg.name} + prompt.multi_select("Use Space Bar |____| to select/unselect Vegetables, and hit Enter when done.", vegetable_choices) + cart << vegetable_choices + #puts "Veg added" + go_to_shopping(cart.flatten) + #puts "Veg added" + elsif choice == '🔹Spices' + prompt = TTY::Prompt.new + spice_choices = Food.where(category: "Spices").map{|spice| spice.name} + prompt.multi_select("Use Space Bar |____| to select/unselect Spices, and hit Enter when done.", spice_choices) + puts "Spice has been added to your cart" + cart << spice_choices + #puts "Spice has been added to your cart" + go_to_shopping(cart.flatten) + #puts "Spice has been added to your cart" + elsif choice == '🔹View Cart' + #puts "Cart is #{cart}" + view_cart(cart.flatten) + elsif choice == '🔹Checkout' + checkout(cart) + elsif choice == '🔹Exit' and cart.length == 0 + exit + end + # # choose from aisles choices = [fruits, vegetables, spices, meats, delete items] + # # select foods from aisle and display prices and emojis + # # added to cart -> optional to add quantity + # # at the end of aisles, go back to aisle choices + # go_back + # cart = [] + #shopping + end + + + + def view_cart(cart=[]) + if cart.length == 0 + puts "Your cart is empty" + go_to_shopping + else + puts "Your cart has #{cart} inside." + go_to_shopping + end + + end + + # } + # cart = [] + # total = calculates total + # checkout + # go_back + + + def checkout(cart=[]) + prompt = TTY::Prompt.new + choices = ['🔹Remove & Add', '🔹View Receipt', '🔹Exit'] + choice = prompt.select('\n \n', choices) + if choice == '🔹Remove & Add' + remove_and_add(cart) + elsif choice == '🔹View Receipt' + view_receipt + elsif choice == '🔹Exit' + exit + end + + # customer.food.each{|food| + # puts "Fruits #{}" + # puts "Vegetables #{}" + # puts "Spices #{}" + # have a price and food list and a grand total + + # show receipt + #update cart/remove stuff if need be + ## be able to select items out of the cart + # exit + # go_back + end + + def remove_and_add(cart) + prompt = TTY::Prompt.new + choices = ['🔹Remove', '🔹Add', '🔹Exit'] + choice = prompt.select('\n \n', choices) + if choice == '🔹Remove' + remove(cart) + elsif choice == '🔹Add' + go_to_shopping(cart) + elsif choice == '🔹Exit' + exit + end + + end + + def remove(cart=[]) + trash = [] + puts 'YOU ARE NOW REMOVING ITEMS FROM A CART' + prompt = TTY::Prompt.new + choices = (cart) + choice = prompt.multi_select('\n \n', choices) + if choice == cart.index(0..10) + trash << cart.index(0..10) + trash.destroy_all + checkout + else + puts 'yay' + checkout + end + + + end + + def take_out() + + end + + + + + def view_receipt + + end + + + def exit + puts "**********" + puts "Good Bye!" + puts "**********" + end + + + + def opener + puts "\n 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 🔹 \n " + end + + + +end + +# shopping_cart = CLI.new() +# # shopping_cart.main_menu +# shopping_cart.login(attempts = 0) + + # shopping_cart = CLI.new() + # # shopping_cart.main_menu + # shopping_cart.signup #(attempts = 0) + + diff --git a/bin/run.rb b/bin/run.rb index cf08c338..ac1331d7 100644 --- a/bin/run.rb +++ b/bin/run.rb @@ -1,5 +1,7 @@ require_relative '../config/environment' +require_relative '../bin/cli.rb' +#puts "HELLO WORLD" - -puts "HELLO WORLD" +cli = CLI.new +cli.main_menu diff --git a/config/environment.rb b/config/environment.rb index 4dbe13e5..d816fd23 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -2,4 +2,11 @@ Bundler.require ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'db/development.db') + +ActiveRecord::Base.logger = nil + + +ActiveRecord::Base.logger = nil + require_all 'lib' +require_all 'app' \ No newline at end of file diff --git a/db/migrate/20201202221901_create_orders.rb b/db/migrate/20201202221901_create_orders.rb new file mode 100644 index 00000000..28010be7 --- /dev/null +++ b/db/migrate/20201202221901_create_orders.rb @@ -0,0 +1,13 @@ +class CreateOrders < ActiveRecord::Migration[5.2] + def change + create_table :orders do |t| + t.integer :customer_id + t.integer :food_id + t.integer :quantity + t.integer :total + t.timestamp + + end + + end +end diff --git a/db/migrate/20201202224028_create_foods.rb b/db/migrate/20201202224028_create_foods.rb new file mode 100644 index 00000000..71f94ca3 --- /dev/null +++ b/db/migrate/20201202224028_create_foods.rb @@ -0,0 +1,11 @@ +class CreateFoods < ActiveRecord::Migration[5.2] + def change + create_table :foods do |t| + t.string :name + t.string :category + t.integer :price + t.timestamps + end + + end +end diff --git a/db/migrate/20201202224240_create_customers.rb b/db/migrate/20201202224240_create_customers.rb new file mode 100644 index 00000000..c6b0f4b4 --- /dev/null +++ b/db/migrate/20201202224240_create_customers.rb @@ -0,0 +1,11 @@ +class CreateCustomers < ActiveRecord::Migration[5.2] + def change + create_table :customers do |t| + t.string :name + t.string :password + + t.timestamp + end + + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..ceff928c --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,35 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema.define(version: 2020_12_02_224240) do + + create_table "customers", force: :cascade do |t| + t.string "name" + t.string "password" + end + + create_table "foods", force: :cascade do |t| + t.string "name" + t.string "category" + t.integer "price" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "orders", force: :cascade do |t| + t.integer "customer_id" + t.integer "food_id" + t.integer "quantity" + t.integer "total" + end + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 00000000..c3a0e6e1 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,96 @@ +require_relative "../config/environment.rb" +require_relative "../app/models/customer.rb" +require_relative "../app/models/food.rb" +require_relative "../app/models/order.rb" + +Order.destroy_all +Customer.destroy_all +Food.destroy_all + +puts "Customer" + +20.times do + Customer.create( + name: Faker::Name.name, + password: Faker::Barcode.ean + ) +end + + +Customer.create(name:'Dan', password:'123') +Customer.create(name:'Tee', password:'321') +Customer.create(name:'Bob', password:'111') + +Food.create(name: 'Methi', category: 'Spices', price: 3) +Food.create(name: 'Rosemary', category: 'Spices', price: 1) +Food.create(name: 'Parsnip', category: 'Vegetables', price: 4) +Food.create(name: 'Apple', category: "Fruits", price: 2) + + +Order.create(customer_id: Customer.all.sample.id, food_id: Food.all.sample.id, quantity: 2) +Order.create(customer_id: Customer.all.sample.id, food_id: Food.all.sample.id, quantity: 2) +Order.create(customer_id: Customer.all.sample.id, food_id: Food.all.sample.id, quantity: 2) + + + + +puts "Food" + + +# 30.times do +# Food.create( +# name: Faker::Food.fruits, +# price: rand(20..180), +# category: "Fruits" +# ) +# end + +# 30.times do +# Food.create( +# name: Faker::Food.vegetables, +# price: rand(20..180), +# category: "Vegetables" +# ) +# end + +# 30.times do +# Food.create( +# name: Faker::Food.spice, +# price: rand(20..180), +# category: "Spice" +# ) +# end + + + + +#Faker::Food.vegetables +#Faker::Food.spice +#Faker::Food.fruits + +# 60.times do +# Order.create( +# customer_id: Customer.all.sample.id, +# food_id: Food.all.sample.id, +# quantity: rand(1..20), +# #total: Food.all.map{|foo| foo.price if foo.id == self.food_id} * self.quantity +# ) +# end + +# #Custome(name: "Dan") +# #Food.create(name: "Apple", price: 1 ) +# Order.create(customer_id: 180, food_id: 831, quantity:10) +# #total: Food.all.map{|foo| foo.price if foo.id == self.food_id} * self.quantity + + + + + + + + +# c1 = Customer.create(name:'Dan') + +# f1 = Food.create(name:'pie',price: 2) + +