diff --git a/app/furniture/journal/entry.rb b/app/furniture/journal/entry.rb index 00d56713d..24c6d4b5a 100644 --- a/app/furniture/journal/entry.rb +++ b/app/furniture/journal/entry.rb @@ -19,6 +19,8 @@ class Journal::Entry < ApplicationRecord attribute :published_at, :datetime + # @!attribute journal + # @return [Journal::Journal] belongs_to :journal, class_name: "Journal::Journal", inverse_of: :entries delegate :room, :space, to: :journal diff --git a/app/furniture/marketplace.rb b/app/furniture/marketplace.rb index 3a00f2dfe..2cdbd1d60 100644 --- a/app/furniture/marketplace.rb +++ b/app/furniture/marketplace.rb @@ -3,12 +3,15 @@ class Marketplace include Placeable def self.append_routes(router) - router.resource :marketplace, only: [] do - router.resources :products, only: %i[new create index], module: "marketplace" + router.resources :marketplaces, only: [:show], module: "marketplace" do + router.resources :products + router.resources :carts do + router.resources :cart_products + end end end - def products - Marketplace::Product.where(space: space) + def self.from_placement(placement) + placement.becomes(Marketplace) end end diff --git a/app/furniture/marketplace/_marketplace.html.erb b/app/furniture/marketplace/_marketplace.html.erb deleted file mode 100644 index 27b30ca34..000000000 --- a/app/furniture/marketplace/_marketplace.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render partial: "marketplace/marketplace/marketplace", object: marketplace %> \ No newline at end of file diff --git a/app/furniture/marketplace/breadcrumbs.rb b/app/furniture/marketplace/breadcrumbs.rb new file mode 100644 index 000000000..62238802f --- /dev/null +++ b/app/furniture/marketplace/breadcrumbs.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +# @see https://github.com/kzkn/gretel + +crumb :marketplace do |marketplace| + parent :room, marketplace.room + link 'Marketplace', marketplace.location +end + +crumb :marketplace_products do |marketplace| + parent :marketplace, marketplace + link 'Products', marketplace.location(:products) +end + +crumb :marketplace_product do |product| + parent :marketplace_products, product.marketplace + link product.name, product.location +end + +crumb :new_marketplace_product do |product| + parent :marketplace_products, product.marketplace + link 'Add a Product', [:new] + marketplace.location(:product) +end + +crumb :edit_marketplace_product do |product| + parent :marketplace_product, product + link 'Edit', [:edit] + product.location +end diff --git a/app/furniture/marketplace/cart.rb b/app/furniture/marketplace/cart.rb new file mode 100644 index 000000000..f0303412b --- /dev/null +++ b/app/furniture/marketplace/cart.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Marketplace + class Cart < ApplicationRecord + self.table_name = 'marketplace_carts' + + belongs_to :marketplace + delegate :space, :room, to: :marketplace + has_many :cart_products + has_many :products, through: :cart_products + + def self.model_name + @_model_name ||= ActiveModel::Name.new(self, ::Marketplace) + end + end +end diff --git a/app/furniture/marketplace/cart_product.rb b/app/furniture/marketplace/cart_product.rb new file mode 100644 index 000000000..bb25dfd5c --- /dev/null +++ b/app/furniture/marketplace/cart_product.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class Marketplace + class CartProduct < ApplicationRecord + self.table_name = "marketplace_cart_products" + + belongs_to :cart, inverse_of: :cart_products + belongs_to :product, inverse_of: :cart_products + validates_uniqueness_of :product, scope: :cart_id + + attribute :quantity, :integer, default: 0 + + def self.model_name + @_model_name ||= ActiveModel::Name.new(self, ::Marketplace) + end + end +end diff --git a/app/furniture/marketplace/cart_products/_cart_product.html.erb b/app/furniture/marketplace/cart_products/_cart_product.html.erb new file mode 100644 index 000000000..ad0b7c30b --- /dev/null +++ b/app/furniture/marketplace/cart_products/_cart_product.html.erb @@ -0,0 +1,33 @@ +<%- product = cart_product.product %> +<%- cart = cart_product.cart %> + + + <%= product.name %> +
+
<%= product.class.human_attribute_name(:price) %>
+
<%= humanized_money_with_symbol(product.price) %>
+
<%= product.class.human_attribute_name(:description) %>
+
<%= product.description %>
+ +
+ + + <%= product.description %> + + + <%= humanized_money_with_symbol(product.price) %> + + + <%# TODO: Extract minus and plus buttons into components %> + <%- minus_quantity = [cart_product.quantity - 1, 0].max %> + <%- minus_method = minus_quantity.zero? ? :delete : :put %> + <%= render "buttons/minus", disabled: cart_product.quantity.zero?, method: minus_method, title: t('.remove'), disabled: cart_product.quantity.zero?, href: [cart.space, cart.room, cart.marketplace, cart, cart_product, { cart_product: { quantity: minus_quantity, product_id: product.id} }] %> + + + <%= cart_product.quantity %> + + <%- add_quantity = cart_product.quantity + 1 %> + <%- add_method = add_quantity == 1 ? :post : :put %> + <%= render "buttons/plus", method: add_method, title: t('.add'), href: [cart.space, cart.room, cart.marketplace, cart, cart_product, { cart_product: {quantity: add_quantity, product_id: product.id} }] %> + + diff --git a/app/furniture/marketplace/cart_products_controller.rb b/app/furniture/marketplace/cart_products_controller.rb new file mode 100644 index 000000000..d230e5145 --- /dev/null +++ b/app/furniture/marketplace/cart_products_controller.rb @@ -0,0 +1,91 @@ +class Marketplace + class CartProductsController < FurnitureController + def create + cart_product.save + + respond_to do |format| + format.html do + if cart_product.errors.empty? + flash[:notice] = t(".success", + product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = t(".failure", + product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + end + + redirect_to [marketplace.space, marketplace.room] + end + + format.turbo_stream do + render turbo_stream: turbo_stream.replace("cart-product-#{cart_product.product_id}", cart_product) + end + end + end + + def update + cart_product.update(cart_product_params) + respond_to do |format| + format.html do + if cart_product.errors.empty? + flash[:notice] = + t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = + t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + end + + redirect_to [marketplace.space, marketplace.room] + end + format.turbo_stream do + render turbo_stream: turbo_stream.replace("cart-product-#{cart_product.product_id}", cart_product) + end + end + end + + def destroy + cart_product.destroy + respond_to do |format| + format.html do + if cart_product.destroyed? + flash[:notice] = + t(".success", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + else + flash[:alert] = + t(".failure", product: cart_product.product.name.pluralize(cart_product.quantity), + quantity: cart_product.quantity) + end + redirect_to [marketplace.space, marketplace.room] + end + + format.turbo_stream do + render turbo_stream: turbo_stream.replace("cart-product-#{cart_product.product_id}", cart.cart_products.new(product: cart_product.product)) + end + end + end + + def cart_product + @cart_product ||= if params[:id] + cart.cart_products.find(params[:id]) + elsif params[:cart_product] + cart.cart_products.new(cart_product_params) + end + end + + def cart + marketplace.carts.find(params[:cart_id]) + end + + def marketplace + room.furniture_placements.find(params[:marketplace_id]).furniture + end + + def cart_product_params + params.require(:cart_product).permit(:quantity, :product_id) + end + end +end diff --git a/app/furniture/marketplace/locales/en.yml b/app/furniture/marketplace/locales/en.yml new file mode 100644 index 000000000..810cab05a --- /dev/null +++ b/app/furniture/marketplace/locales/en.yml @@ -0,0 +1,21 @@ +en: + marketplace: + products: + index: + new: Add a Product + product: + add: Add Product + remove: Remove Product + cart_products: + cart_product: + remove: Remove from Cart + add: Add to Cart + destroy: + success: "Removed %{quantity} %{product} from Cart" + failure: "Could not remove %{quantity} %{product} from Cart" + create: + success: "Added %{quantity} %{product} to Cart" + failure: "Could not add %{quantity} %{product} to Cart" + update: + success: "Changed %{quantity} %{product} on Cart" + failure: "Could not change %{quantity} %{product} on Cart" diff --git a/app/furniture/marketplace/marketplace.rb b/app/furniture/marketplace/marketplace.rb new file mode 100644 index 000000000..772ab444b --- /dev/null +++ b/app/furniture/marketplace/marketplace.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Marketplace + class Marketplace < FurniturePlacement + has_many :products, inverse_of: :marketplace + has_many :carts, inverse_of: :marketplace + + def self.model_name + @_model_name ||= ActiveModel::Name.new(self, ::Marketplace) + end + + def location(child = nil) + [space, room, self, child].compact + end + end +end diff --git a/app/furniture/marketplace/marketplace/_marketplace.html.erb b/app/furniture/marketplace/marketplace/_marketplace.html.erb deleted file mode 100644 index c8c1b0d8e..000000000 --- a/app/furniture/marketplace/marketplace/_marketplace.html.erb +++ /dev/null @@ -1,26 +0,0 @@ -<%= turbo_frame_tag marketplace do %> -
- - - - - - - - - - - <%= render marketplace.products %> - -
- <%= Marketplace::Product.human_attribute_name(:name) %> - - Actions - <%= render "buttons/new", title: t('marketplace.products.new'), href: [:new, marketplace.space, marketplace.room, marketplace, :product] %> -
-
-<%- end %> \ No newline at end of file diff --git a/app/furniture/marketplace/marketplaces/_marketplace.html.erb b/app/furniture/marketplace/marketplaces/_marketplace.html.erb new file mode 100644 index 000000000..b06f74c8e --- /dev/null +++ b/app/furniture/marketplace/marketplaces/_marketplace.html.erb @@ -0,0 +1,30 @@ + +
+ + + + + + + + + + + <%- cart = marketplace.carts.find_or_create_by(id: session[:current_cart] ||= SecureRandom.uuid) %> + <%- marketplace.products.each do |product| %> + <%= render cart.cart_products.find_or_initialize_by(product: product) %> + <%- end %> + +
+ <%= Marketplace::Product.human_attribute_name(:name) %> +  
+
+
+<%- if policy(marketplace.products.new).create? %> + <%= link_to t('.manage_products'), marketplace.location(:products) %> +<%- end %> +
diff --git a/app/furniture/marketplace/marketplaces/show.html.erb b/app/furniture/marketplace/marketplaces/show.html.erb new file mode 100644 index 000000000..247aa239f --- /dev/null +++ b/app/furniture/marketplace/marketplaces/show.html.erb @@ -0,0 +1,2 @@ +<%- breadcrumb :marketplace, marketplace %> +<%= render marketplace %> diff --git a/app/furniture/marketplace/marketplaces_controller.rb b/app/furniture/marketplace/marketplaces_controller.rb new file mode 100644 index 000000000..a4ef3907f --- /dev/null +++ b/app/furniture/marketplace/marketplaces_controller.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class Marketplace + class MarketplacesController < FurnitureController + def show; end + + helper_method def marketplace + Marketplace.find(params[:id]) + end + end +end diff --git a/app/furniture/marketplace/product.rb b/app/furniture/marketplace/product.rb index 39b451708..b4d1830c0 100644 --- a/app/furniture/marketplace/product.rb +++ b/app/furniture/marketplace/product.rb @@ -2,8 +2,15 @@ class Marketplace class Product < ApplicationRecord - self.table_name = "marketplace_products" - belongs_to :space + self.table_name = 'marketplace_products' + + extend StripsNamespaceFromModelName + + belongs_to :marketplace + delegate :space, to: :marketplace + + has_many :cart_products, inverse_of: :product + has_many :carts, through: :cart_products attribute :name, :string validates :name, presence: true @@ -11,5 +18,9 @@ class Product < ApplicationRecord attribute :description, :string monetize :price_cents + + def location + marketplace.location(self) + end end end diff --git a/app/furniture/marketplace/product_policy.rb b/app/furniture/marketplace/product_policy.rb index bd5817624..5eec79bef 100644 --- a/app/furniture/marketplace/product_policy.rb +++ b/app/furniture/marketplace/product_policy.rb @@ -2,8 +2,17 @@ class Marketplace class ProductPolicy < ApplicationPolicy + alias product object def permitted_attributes(_params) %i[name description price_cents price_currency] end + + def create? + person.member_of?(product.space) + end + + def update? + create? + end end end diff --git a/app/furniture/marketplace/products/_form.html.erb b/app/furniture/marketplace/products/_form.html.erb new file mode 100644 index 000000000..15fde27be --- /dev/null +++ b/app/furniture/marketplace/products/_form.html.erb @@ -0,0 +1,6 @@ +<%= form_with model: product.location do |f| %> + <%= render "text_field", { attribute: :name, form: f} %> + <%= render "text_area", { attribute: :description, form: f} %> + <%= render "number_field", { attribute: :price_cents, form: f} %> + <%= f.submit %> +<% end %> diff --git a/app/furniture/marketplace/products/_product.html.erb b/app/furniture/marketplace/products/_product.html.erb index 15d776a7d..fe7611322 100644 --- a/app/furniture/marketplace/products/_product.html.erb +++ b/app/furniture/marketplace/products/_product.html.erb @@ -1,4 +1,4 @@ - + <%= product.name %>
@@ -13,6 +13,6 @@ <%= humanized_money_with_symbol(product.price) %> - <%= render "buttons/new", label: "🛒", title: t('marketplace.products.new'), href: "#" %> + <%= render "buttons/remove", title: t('.remove'), href: product.location %> - \ No newline at end of file + diff --git a/app/furniture/marketplace/products/index.html.erb b/app/furniture/marketplace/products/index.html.erb new file mode 100644 index 000000000..f0b49b423 --- /dev/null +++ b/app/furniture/marketplace/products/index.html.erb @@ -0,0 +1,25 @@ +<%- breadcrumb :marketplace_products, marketplace%> +
+ + + + + + + + + + <%= render marketplace.products %> + +
+ <%= Marketplace::Product.human_attribute_name(:name) %> +
+
+<%- new_product = marketplace.products.new %> +<%- if policy(new_product).create? %> + <%= render "buttons/new", label: "#{t('.new')} #{t('icons.new')}", title: t('.new'), href: [:new] + marketplace.location + [:product] %> +<%- end %> diff --git a/app/furniture/marketplace/products/new.html.erb b/app/furniture/marketplace/products/new.html.erb index c263ef1ca..9b7d915a2 100644 --- a/app/furniture/marketplace/products/new.html.erb +++ b/app/furniture/marketplace/products/new.html.erb @@ -1,8 +1,3 @@ -<%= turbo_frame_tag marketplace do %> - <%= form_with model: [marketplace.space, marketplace.room, marketplace.products.new] do |f| %> - <%= render "text_field", { attribute: :name, form: f} %> - <%= render "text_area", { attribute: :description, form: f} %> - <%= render "number_field", { attribute: :price_cents, form: f} %> - <%= f.submit %> - <% end %> -<%- end %> \ No newline at end of file +<%- new_product = marketplace.products.new %> +<%- breadcrumb :new_marketplace_product, new_product %> +<%= render "form", product: marketplace.products.new %> diff --git a/app/furniture/marketplace/products_controller.rb b/app/furniture/marketplace/products_controller.rb index ffd89d5ef..956bb1680 100644 --- a/app/furniture/marketplace/products_controller.rb +++ b/app/furniture/marketplace/products_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Marketplace class ProductsController < FurnitureController def new @@ -9,16 +11,32 @@ def create respond_to do |format| format.turbo_stream - format.html { redirect_to [space, room] } + format.html { redirect_to marketplace.location(:products) } + end + end + + def destroy + product = authorize(marketplace.products.find(params[:id])) + + respond_to do |format| + if product.destroy + format.turbo_stream { render turbo_stream: turbo_stream.remove(product) } + format.html { redirect_to marketplace.location(:products) } + else + format.html { redirect_to product.location } + end end end + def index + end + helper_method def marketplace - Marketplace.find_by(room: room) + Marketplace.find(params[:marketplace_id]) end def product_params - policy(Marketplace::Product).permit(params.require(:marketplace_product)) + policy(Product).permit(params.require(:product)) end end end diff --git a/app/views/buttons/_minus.html.erb b/app/views/buttons/_minus.html.erb new file mode 100644 index 000000000..a876ebe01 --- /dev/null +++ b/app/views/buttons/_minus.html.erb @@ -0,0 +1,15 @@ +<%- label = local_assigns.fetch(:label, t('icons.minus')) %> +<%- title = local_assigns.fetch(:title) %> +<%- href = local_assigns.fetch(:href) %> +<%- method = local_assigns.fetch(:method, :put)%> +<%- disabled = local_assigns.fetch(:disabled, false)%> +<%- data = { turbo_method: method, turbo: true} %> +<%- data = data.merge(turbo_confirm: local_assigns[:confirm], confirm: local_assigns[:confirm]) if local_assigns.key?(:confirm) %> + +<%- if !disabled %> + <%= link_to label, href, title: title, method: method, + data: data, + class: 'no-underline bg-transparent hover:bg-primary-100 button' %> +<%- else %> + <%=label%> +<%- end %> diff --git a/app/views/buttons/_new.html.erb b/app/views/buttons/_new.html.erb index be8a3e249..70afe93a8 100644 --- a/app/views/buttons/_new.html.erb +++ b/app/views/buttons/_new.html.erb @@ -3,4 +3,4 @@ <%- href = local_assigns.fetch(:href) %> <%= link_to label, href, title: title, - class: 'no-underline bg-transparent hover:bg-primary-100 button' %> + class: 'no-underline hover:bg-primary-400 bg-primary-500 font-bold py-2 px-4 my-1 rounded text-white text-center transition ease-in-out duration-150 ' %> diff --git a/app/views/buttons/_plus.html.erb b/app/views/buttons/_plus.html.erb new file mode 100644 index 000000000..84e9ed47b --- /dev/null +++ b/app/views/buttons/_plus.html.erb @@ -0,0 +1,10 @@ +<%- label = local_assigns.fetch(:label, t('icons.plus')) %> +<%- title = local_assigns.fetch(:title) %> +<%- href = local_assigns.fetch(:href) %> +<%- method = local_assigns.fetch(:method, :put)%> +<%- data = { turbo_method: method, turbo: true } %> +<%- data = data.merge(turbo_confirm: local_assigns[:confirm], confirm: local_assigns[:confirm]) if local_assigns.key?(:confirm) %> + +<%= link_to label, href, title: title, method: method, + data: data, + class: 'no-underline bg-transparent hover:bg-primary-100 button' %> diff --git a/app/views/buttons/_remove.html.erb b/app/views/buttons/_remove.html.erb index 96c12990e..9ce72be1d 100644 --- a/app/views/buttons/_remove.html.erb +++ b/app/views/buttons/_remove.html.erb @@ -1,7 +1,7 @@ <%- label = local_assigns.fetch(:label, t('icons.remove')) %> <%- title = local_assigns.fetch(:title) %> <%- href = local_assigns.fetch(:href) %> -<%- data = { turbo_method: :delete } %> +<%- data = { turbo_method: :delete, turbo: true } %> <%- data = data.merge(turbo_confirm: local_assigns[:confirm], confirm: local_assigns[:confirm]) if local_assigns.key?(:confirm) %> <%= link_to label, href, title: title, diff --git a/app/views/furniture_placements/_form.html.erb b/app/views/furniture_placements/_form.html.erb index 39cf16c06..a54a1a5ec 100644 --- a/app/views/furniture_placements/_form.html.erb +++ b/app/views/furniture_placements/_form.html.erb @@ -17,4 +17,4 @@ <%- end %> <%- end %> -<%- end %> \ No newline at end of file +<%- end %> diff --git a/config/initializers/money.rb b/config/initializers/money.rb index 633a68193..575df2cdb 100644 --- a/config/initializers/money.rb +++ b/config/initializers/money.rb @@ -82,6 +82,9 @@ # sign_before_symbol: nil # } + config.default_format = { no_cents_if_whole: false } + config.no_cents_if_whole = false + # If you would like to use I18n localization (formatting depends on the # locale): config.locale_backend = :i18n diff --git a/config/locales/icon/en.yml b/config/locales/icon/en.yml index 3a1758717..46fa0f7f9 100644 --- a/config/locales/icon/en.yml +++ b/config/locales/icon/en.yml @@ -2,4 +2,6 @@ en: icons: edit: '⚙️' remove: '🗑️' - new: '➕' \ No newline at end of file + new: '➕' + plus: '➕' + minus: '➖' diff --git a/db/migrate/20221013010533_add_marketplace_carts.rb b/db/migrate/20221013010533_add_marketplace_carts.rb new file mode 100644 index 000000000..2989acf69 --- /dev/null +++ b/db/migrate/20221013010533_add_marketplace_carts.rb @@ -0,0 +1,32 @@ +class AddMarketplaceCarts < ActiveRecord::Migration[7.0] + def change + create_table :marketplace_carts, id: :uuid do |t| + t.references :marketplace, type: :uuid, foreign_key: {to_table: :furniture_placements} + t.timestamps + end + + # We can't change the primary key type so we drop and recreate :'( + drop_table :marketplace_products do |t| + t.references :marketplace, type: :uuid, foreign_key: {to_table: :furniture_placements} + t.string :name + t.string :description + t.monetize :price + t.timestamps + end + + create_table :marketplace_products, id: :uuid do |t| + t.references :marketplace, type: :uuid, foreign_key: {to_table: :furniture_placements} + t.string :name + t.string :description + t.monetize :price + t.timestamps + end + + create_table :marketplace_cart_products, id: :uuid do |t| + t.belongs_to(:cart, foreign_key: {to_table: :marketplace_carts}, type: :uuid) + t.belongs_to(:product, foreign_key: {to_table: :marketplace_products}, type: :uuid) + t.integer :quantity + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index adb16c225..b7414b411 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_10_07_224846) do +ActiveRecord::Schema[7.0].define(version: 2022_10_13_010533) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -134,15 +134,32 @@ t.index ["journal_id"], name: "index_journal_entries_on_journal_id" end - create_table "marketplace_products", force: :cascade do |t| - t.uuid "space_id" + create_table "marketplace_cart_products", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "cart_id" + t.uuid "product_id" + t.integer "quantity" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["cart_id"], name: "index_marketplace_cart_products_on_cart_id" + t.index ["product_id"], name: "index_marketplace_cart_products_on_product_id" + end + + create_table "marketplace_carts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "marketplace_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["marketplace_id"], name: "index_marketplace_carts_on_marketplace_id" + end + + create_table "marketplace_products", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "marketplace_id" t.string "name" t.string "description" t.integer "price_cents", default: 0, null: false t.string "price_currency", default: "USD", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["space_id"], name: "index_marketplace_products_on_space_id" + t.index ["marketplace_id"], name: "index_marketplace_products_on_marketplace_id" end create_table "memberships", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -206,7 +223,10 @@ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "journal_entries", "furniture_placements", column: "journal_id" - add_foreign_key "marketplace_products", "spaces" + add_foreign_key "marketplace_cart_products", "marketplace_carts", column: "cart_id" + add_foreign_key "marketplace_cart_products", "marketplace_products", column: "product_id" + add_foreign_key "marketplace_carts", "furniture_placements", column: "marketplace_id" + add_foreign_key "marketplace_products", "furniture_placements", column: "marketplace_id" add_foreign_key "memberships", "invitations" add_foreign_key "spaces", "rooms", column: "entrance_id" end diff --git a/spec/factories/furniture/marketplace.rb b/spec/factories/furniture/marketplace.rb index 4bbad431f..d43315f55 100644 --- a/spec/factories/furniture/marketplace.rb +++ b/spec/factories/furniture/marketplace.rb @@ -1,18 +1,21 @@ FactoryBot.define do - factory :marketplace do - transient do - room { build(:room) } - end - - placement do - association :furniture_placement, {furniture_kind: "marketplace", room: room} - end + factory :marketplace, class: "Marketplace::Marketplace" do + room end factory :marketplace_product, class: "Marketplace::Product" do name { Faker::TvShows::DrWho.specie } - price_cents { Random.rand(1_00..9999_99) } + price_cents { Random.rand(1_00..999_999) } + + marketplace + end + + factory :marketplace_cart_product, class: "Marketplace::CartProduct" do + association(:product, factory: :marketplace_product) + association(:cart, factory: :marketplace_cart) + end - association :space + factory :marketplace_cart, class: "Marketplace::Cart" do + marketplace end end diff --git a/spec/furniture/marketplace/cart_product_spec.rb b/spec/furniture/marketplace/cart_product_spec.rb new file mode 100644 index 000000000..dca41c82b --- /dev/null +++ b/spec/furniture/marketplace/cart_product_spec.rb @@ -0,0 +1,10 @@ +require "rails_helper" + +RSpec.describe Marketplace::CartProduct, type: :model do + subject(:cart_product) { build(:marketplace_cart_product) } + + it { is_expected.to belong_to(:cart).inverse_of(:cart_products) } + + it { is_expected.to belong_to(:product).inverse_of(:cart_products) } + it { is_expected.to validate_uniqueness_of(:product).scoped_to(:cart_id) } +end diff --git a/spec/furniture/marketplace/cart_spec.rb b/spec/furniture/marketplace/cart_spec.rb new file mode 100644 index 000000000..faf99e70f --- /dev/null +++ b/spec/furniture/marketplace/cart_spec.rb @@ -0,0 +1,9 @@ +require "rails_helper" + +RSpec.describe Marketplace::Cart, type: :model do + it { is_expected.to have_many(:cart_products) } + + it { is_expected.to have_many(:products).through(:cart_products) } + + it { is_expected.to belong_to(:marketplace).class_name("Marketplace::Marketplace") } +end diff --git a/spec/furniture/marketplace/marketplace_spec.rb b/spec/furniture/marketplace/marketplace_spec.rb new file mode 100644 index 000000000..77482df6e --- /dev/null +++ b/spec/furniture/marketplace/marketplace_spec.rb @@ -0,0 +1,6 @@ +require "rails_helper" + +RSpec.describe Marketplace::Marketplace, type: :model do + it { is_expected.to have_many(:products).inverse_of(:marketplace) } + it { is_expected.to have_many(:carts).inverse_of(:marketplace) } +end diff --git a/spec/furniture/marketplace/product_spec.rb b/spec/furniture/marketplace/product_spec.rb index ae0bbf7d9..14b2cd228 100644 --- a/spec/furniture/marketplace/product_spec.rb +++ b/spec/furniture/marketplace/product_spec.rb @@ -1,9 +1,9 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe Marketplace::Product, type: :model do - it { is_expected.to belong_to(:space) } + it { is_expected.to belong_to(:marketplace) } - describe "#name" do + describe '#name' do it { is_expected.to validate_presence_of(:name) } end end diff --git a/spec/furniture/marketplace/products_request_spec.rb b/spec/furniture/marketplace/products_controller_request_spec.rb similarity index 94% rename from spec/furniture/marketplace/products_request_spec.rb rename to spec/furniture/marketplace/products_controller_request_spec.rb index 4b45db67a..c5deb4619 100644 --- a/spec/furniture/marketplace/products_request_spec.rb +++ b/spec/furniture/marketplace/products_controller_request_spec.rb @@ -10,7 +10,8 @@ attributes = attributes_for(:marketplace_product) expect do - post polymorphic_path([space, room, marketplace, :products]), params: {marketplace_product: attributes} + post polymorphic_path([space, room, marketplace, :products]), + params: {product: attributes} end.to change(marketplace.products, :count).by(1) created_product = marketplace.products.last