diff --git a/app/javascript/application.js b/app/javascript/application.js index d933293..6d426e6 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1,3 +1,3 @@ // Entry point for the build script in your package.json -import "@hotwired/turbo-rails" -import "./controllers" +import "@hotwired/turbo-rails"; +import "./controllers"; diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js index 1213e85..e297a52 100644 --- a/app/javascript/controllers/application.js +++ b/app/javascript/controllers/application.js @@ -1,9 +1,14 @@ -import { Application } from "@hotwired/stimulus" +import { Application } from "@hotwired/stimulus"; +import Alpine from "alpinejs"; -const application = Application.start() +const application = Application.start(); // Configure Stimulus development experience -application.debug = false -window.Stimulus = application +application.debug = false; +window.Stimulus = application; -export { application } +// Configure and load Alpine +window.Alpine = Alpine; +Alpine.start(); + +export { application }; diff --git a/app/models/ticket.rb b/app/models/ticket.rb new file mode 100644 index 0000000..71c236b --- /dev/null +++ b/app/models/ticket.rb @@ -0,0 +1,8 @@ +class Ticket < ApplicationRecord + # Validations + validates :qr_code, presence: true, uniqueness: true + validates :party_id, presence: true + validates :user_id, presence: true + validates :price_cents, presence: true, numericality: { greater_than: 0 } + validates :status, presence: true, inclusion: { in: %w[active used expired refunded] } +end diff --git a/app/models/ticket_type.rb b/app/models/ticket_type.rb new file mode 100644 index 0000000..c3b852b --- /dev/null +++ b/app/models/ticket_type.rb @@ -0,0 +1,24 @@ +class TicketType < ApplicationRecord + # Associations + belongs_to :party + has_many :tickets + + # Validations + validates :name, presence: true, length: { minimum: 3, maximum: 50 } + validates :description, presence: true, length: { minimum: 10, maximum: 500 } + validates :price_cents, presence: true, numericality: { greater_than: 0 } + validates :quantity, presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :party_id, presence: true + validates :sale_start_at, presence: true + validates :sale_end_at, presence: true + validate :sale_end_after_start + validates :requires_id, inclusion: { in: [true, false] } + validates :minimum_age, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 120 }, allow_nil: true + + private + + def sale_end_after_start + return unless sale_start_at && sale_end_at + errors.add(:sale_end_at, "must be after sale start") if sale_end_at <= sale_start_at + end +end diff --git a/db/migrate/20250823170408_create_ticket_types.rb b/db/migrate/20250823170408_create_ticket_types.rb new file mode 100644 index 0000000..315db09 --- /dev/null +++ b/db/migrate/20250823170408_create_ticket_types.rb @@ -0,0 +1,17 @@ +class CreateTicketTypes < ActiveRecord::Migration[8.0] + def change + create_table :ticket_types do |t| + t.references :party, null: false, foreign_key: true + t.string :name + t.text :description + t.integer :price_cents + t.integer :quantity + t.datetime :sale_start_at + t.datetime :sale_end_at + t.boolean :requires_id + t.integer :minimum_age + + t.timestamps + end + end +end diff --git a/db/migrate/20250823171354_create_tickets.rb b/db/migrate/20250823171354_create_tickets.rb new file mode 100644 index 0000000..adf2350 --- /dev/null +++ b/db/migrate/20250823171354_create_tickets.rb @@ -0,0 +1,9 @@ +class CreateTickets < ActiveRecord::Migration[8.0] + def change + create_table :tickets do |t| + t.string :qr_code + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c4f87e2..1870a23 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[8.0].define(version: 2025_08_23_145902) do +ActiveRecord::Schema[8.0].define(version: 2025_08_23_171354) do create_table "parties", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t| t.string "name", null: false t.text "description", null: false @@ -27,6 +27,27 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_23_145902) do t.index ["state"], name: "index_parties_on_state" end + create_table "ticket_types", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t| + t.bigint "party_id", null: false + t.string "name" + t.text "description" + t.integer "price_cents" + t.integer "quantity" + t.datetime "sale_start_at" + t.datetime "sale_end_at" + t.boolean "requires_id" + t.integer "minimum_age" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["party_id"], name: "index_ticket_types_on_party_id" + end + + create_table "tickets", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t| + t.string "qr_code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", charset: "utf8mb4", collation: "utf8mb4_uca1400_ai_ci", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -38,4 +59,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_23_145902) do t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end + + add_foreign_key "ticket_types", "parties" end diff --git a/opencode.json b/opencode.json new file mode 100644 index 0000000..64cb9b2 --- /dev/null +++ b/opencode.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://opencode.ai/config.json", + "provider": { + "myprovider": { + "npm": "@ai-sdk/openai-compatible", + "name": "Scaleway", + "options": { + "baseURL": "https://api.scaleway.ai/v1", + "apiKey": "928c8440-604b-423a-983b-00afd5a1164e" + }, + "models": { + "devstral-small-2505": { + "name": "Devstral 2505" + }, + "qwen3-coder-30b-a3b-instruct": { + "name": "Qwen3 Coder 30b a3b instruct" + } + } + } + } +} diff --git a/test/fixtures/tickets.yml b/test/fixtures/tickets.yml new file mode 100644 index 0000000..558cdf2 --- /dev/null +++ b/test/fixtures/tickets.yml @@ -0,0 +1,7 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + qr_code: MyString + +two: + qr_code: MyString diff --git a/test/models/ticket_test.rb b/test/models/ticket_test.rb new file mode 100644 index 0000000..307fc7e --- /dev/null +++ b/test/models/ticket_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class TicketTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end