diff --git a/app/controllers/bubbles/pops_controller.rb b/app/controllers/bubbles/pops_controller.rb
index 7abedb285..395f241e2 100644
--- a/app/controllers/bubbles/pops_controller.rb
+++ b/app/controllers/bubbles/pops_controller.rb
@@ -2,7 +2,7 @@ class Bubbles::PopsController < ApplicationController
include BubbleScoped, BucketScoped
def create
- @bubble.pop!(user: Current.user)
+ @bubble.pop!(user: Current.user, reason: params[:reason])
redirect_to @bubble
end
diff --git a/app/models/account.rb b/app/models/account.rb
index f8fc136b9..146674e23 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -13,6 +13,12 @@ class Account < ApplicationRecord
has_many :workflows, dependent: :destroy
has_many :stages, through: :workflows, class_name: "Workflow::Stage"
+ has_many :pop_reasons, dependent: :destroy, class_name: "Pop::Reason" do
+ def labels
+ pluck(:label).presence || [ Pop::Reason::FALLBACK_LABEL ]
+ end
+ end
+
has_many :tags, dependent: :destroy
has_many_attached :uploads
diff --git a/app/models/bubble/poppable.rb b/app/models/bubble/poppable.rb
index b8e1ef855..a3425bfe6 100644
--- a/app/models/bubble/poppable.rb
+++ b/app/models/bubble/poppable.rb
@@ -40,10 +40,10 @@ module Bubble::Poppable
pop&.created_at
end
- def pop!(user: Current.user)
+ def pop!(user: Current.user, reason: nil)
unless popped?
transaction do
- create_pop!(user: user)
+ create_pop! user: user, reason: reason
track_event :popped, creator: user
end
end
diff --git a/app/models/pop.rb b/app/models/pop.rb
index 45ccb2411..619b8d1c2 100644
--- a/app/models/pop.rb
+++ b/app/models/pop.rb
@@ -1,4 +1,8 @@
class Pop < ApplicationRecord
belongs_to :bubble, touch: true
belongs_to :user, optional: true
+
+ def reason
+ super || Pop::Reason::FALLBACK_LABEL
+ end
end
diff --git a/app/models/pop/reason.rb b/app/models/pop/reason.rb
new file mode 100644
index 000000000..14cafa266
--- /dev/null
+++ b/app/models/pop/reason.rb
@@ -0,0 +1,5 @@
+class Pop::Reason < ApplicationRecord
+ belongs_to :account
+
+ FALLBACK_LABEL = "Done"
+end
diff --git a/app/views/bubbles/_card.html.erb b/app/views/bubbles/_card.html.erb
index 3099d5c04..a557b5a94 100644
--- a/app/views/bubbles/_card.html.erb
+++ b/app/views/bubbles/_card.html.erb
@@ -51,7 +51,7 @@
<% if bubble.popped? %>
- <%= bubble.popped_by.system? ? "Closed" : "Completed" %>
+ <%= bubble.popped_by.system? ? "Closed" : bubble.pop.reason %>
<%= bubble.popped_at.strftime("%b %d, %Y") %>
by <%= bubble.popped_by.name %>
diff --git a/app/views/bubbles/_pop_toggle.html.erb b/app/views/bubbles/_pop_toggle.html.erb
index 0bcb1b818..d55fbbdab 100644
--- a/app/views/bubbles/_pop_toggle.html.erb
+++ b/app/views/bubbles/_pop_toggle.html.erb
@@ -14,18 +14,13 @@
aria-label="Close as…" aria-description="Close this card and select a reason.."
data-dialog-target="dialog" data-action="turbo:before-cache@document->dialog#close">
- <%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
- Completed
- <% end %>
- <%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
- Duplicate
- <% end %>
- <%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
- Maybe later
- <% end %>
- <%= button_to bucket_bubble_pop_path(bubble.bucket, bubble), class: "btn popup__item full-width", form_class: "full-width" do %>
- Working as intended
+
+ <% Current.account.pop_reasons.labels.each do |label| %>
+ <%= button_to bucket_bubble_pop_path(bubble.bucket, bubble, reason: label), class: "btn popup__item full-width", form_class: "full-width" do %>
+ <%= label %>
+ <% end %>
<% end %>
+
<% if bubble.doing? %>
<%= button_to bucket_bubble_engagement_path(bubble.bucket, bubble), method: :delete, class: "btn popup__item full-width" do %>
diff --git a/db/migrate/20250404083727_add_reason_to_pops.rb b/db/migrate/20250404083727_add_reason_to_pops.rb
new file mode 100644
index 000000000..25d2f72f9
--- /dev/null
+++ b/db/migrate/20250404083727_add_reason_to_pops.rb
@@ -0,0 +1,12 @@
+class AddReasonToPops < ActiveRecord::Migration[8.1]
+ def change
+ add_column :pops, :reason, :string
+
+ create_table :pop_reasons do |t|
+ t.references :account, index: true
+ t.string :label
+
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6d7611a79..d273dee5b 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.1].define(version: 2025_04_04_074315) do
+ActiveRecord::Schema[8.1].define(version: 2025_04_04_083727) do
create_table "accesses", force: :cascade do |t|
t.integer "bucket_id", null: false
t.datetime "created_at", null: false
@@ -235,9 +235,18 @@ ActiveRecord::Schema[8.1].define(version: 2025_04_04_074315) do
t.index ["user_id"], name: "index_pins_on_user_id"
end
+ create_table "pop_reasons", force: :cascade do |t|
+ t.integer "account_id"
+ t.datetime "created_at", null: false
+ t.string "label"
+ t.datetime "updated_at", null: false
+ t.index ["account_id"], name: "index_pop_reasons_on_account_id"
+ end
+
create_table "pops", force: :cascade do |t|
t.integer "bubble_id", null: false
t.datetime "created_at", null: false
+ t.string "reason"
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["bubble_id"], name: "index_pops_on_bubble_id", unique: true
diff --git a/db/schema_cache.yml b/db/schema_cache.yml
index b15f1e0cc..9d9673f00 100644
--- a/db/schema_cache.yml
+++ b/db/schema_cache.yml
@@ -468,6 +468,16 @@ columns:
default_function:
collation:
comment:
+ - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
+ auto_increment:
+ name: last_active_at
+ cast_type: *3
+ sql_type_metadata: *4
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
auto_increment:
name: stage_id
@@ -499,16 +509,6 @@ columns:
collation:
comment:
- *9
- - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
- auto_increment:
- name: last_active_at
- cast_type: *3
- sql_type_metadata: *4
- 'null': true
- default:
- default_function:
- collation:
- comment:
buckets:
- *5
- &32 !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
@@ -748,6 +748,30 @@ columns:
- *6
- *9
- *30
+ pop_reasons:
+ - *5
+ - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
+ auto_increment:
+ name: account_id
+ cast_type: *1
+ sql_type_metadata: *2
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
+ - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
+ auto_increment:
+ name: label
+ cast_type: *7
+ sql_type_metadata: *8
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
+ - *6
+ - *9
pops:
- *5
- *25
@@ -763,6 +787,16 @@ columns:
default_function:
collation:
comment:
+ - !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
+ auto_increment:
+ name: reason
+ cast_type: *7
+ sql_type_metadata: *8
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
reactions:
- *5
- !ruby/object:ActiveRecord::ConnectionAdapters::SQLite3::Column
@@ -963,6 +997,7 @@ primary_keys:
messages: id
notifications: id
pins: id
+ pop_reasons: id
pops: id
reactions: id
schema_migrations: version
@@ -998,6 +1033,7 @@ data_sources:
messages: true
notifications: true
pins: true
+ pop_reasons: true
pops: true
reactions: true
schema_migrations: true
@@ -1318,11 +1354,10 @@ indexes:
bubbles:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: bubbles
- name: index_bubbles_on_last_active_at_and_status
+ name: index_bubbles_on_stage_id
unique: false
columns:
- - last_active_at
- - status
+ - stage_id
lengths: {}
orders: {}
opclasses: {}
@@ -1335,10 +1370,11 @@ indexes:
valid: true
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: bubbles
- name: index_bubbles_on_stage_id
+ name: index_bubbles_on_last_active_at_and_status
unique: false
columns:
- - stage_id
+ - last_active_at
+ - status
lengths: {}
orders: {}
opclasses: {}
@@ -1802,6 +1838,23 @@ indexes:
nulls_not_distinct:
comment:
valid: true
+ pop_reasons:
+ - !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
+ table: pop_reasons
+ name: index_pop_reasons_on_account_id
+ unique: false
+ columns:
+ - account_id
+ lengths: {}
+ orders: {}
+ opclasses: {}
+ where:
+ type:
+ using:
+ include:
+ nulls_not_distinct:
+ comment:
+ valid: true
pops:
- !ruby/object:ActiveRecord::ConnectionAdapters::IndexDefinition
table: pops
@@ -2053,4 +2106,4 @@ indexes:
nulls_not_distinct:
comment:
valid: true
-version: 20250404074315
+version: 20250404083727