From ebe09c112dbe02a7e6e728964eadbc8bc69b1ef5 Mon Sep 17 00:00:00 2001 From: Michael McCarty Date: Fri, 11 Sep 2026 11:39:02 -0700 Subject: [PATCH] feat: persist and toggle reaction log preference across joins --- src/boost/boost.go | 1 + src/boost/boost_button_reactions.go | 7 ++- src/boost/boost_menu.go | 19 +++++-- src/boost/boost_menu_test.go | 88 +++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/boost/boost.go b/src/boost/boost.go index 20154547..96651283 100644 --- a/src/boost/boost.go +++ b/src/boost/boost.go @@ -820,6 +820,7 @@ func AddFarmerToContract(client dc.Client, contract *Contract, guildID string, c if te != "" { b.TECount, _ = strconv.Atoi(te) } + b.DisableEphemeralLog = farmerstate.GetMiscSettingFlag(userID, "DisableEphemeralLog") if contract.State != ContractStateSignup { if contract.Style&ContractFlag4Tokens != 0 { diff --git a/src/boost/boost_button_reactions.go b/src/boost/boost_button_reactions.go index d10204f5..343d0dc2 100644 --- a/src/boost/boost_button_reactions.go +++ b/src/boost/boost_button_reactions.go @@ -1208,9 +1208,10 @@ func getContractReactionsComponents(contract *Contract) []dc.LayoutComponent { Emoji: ei.GetBotComponentEmoji("token"), }) menuOptions = append(menuOptions, dc.SelectOption{ - Label: "Toggle Reaction Log", - Value: "togglerxlog", - Emoji: &dc.Emoji{Name: "📊"}, + Label: "Toggle Reaction Log", + Description: "Toggle token log details on or off", + Value: "togglerxlog", + Emoji: &dc.Emoji{Name: "📊"}, }) menuOptions = append(menuOptions, dc.SelectOption{ Label: "My Chicken Runs", diff --git a/src/boost/boost_menu.go b/src/boost/boost_menu.go index c79783cb..c8b94293 100644 --- a/src/boost/boost_menu.go +++ b/src/boost/boost_menu.go @@ -419,18 +419,27 @@ func HandleMenuReactions(client dc.Client, e *dc.ComponentEvent) { case "togglerxlog": contract.mutex.Lock() booster := contract.Boosters[userID] - msgStr := "You are not part of this contract." + var disabled bool if booster != nil { booster.DisableEphemeralLog = !booster.DisableEphemeralLog - if booster.DisableEphemeralLog { + disabled = booster.DisableEphemeralLog + if disabled { booster.NonTokenMsgID = "" - msgStr = "🚫 **Reaction Summary Log:** Disabled for your button reactions." - } else { - msgStr = "📊 **Reaction Summary Log:** Enabled for your button reactions." } + } else { + disabled = !farmerstate.GetMiscSettingFlag(userID, "DisableEphemeralLog") } contract.mutex.Unlock() + farmerstate.SetMiscSettingFlag(userID, "DisableEphemeralLog", disabled) + + var msgStr string + if disabled { + msgStr = "🚫 **Reaction Summary Log:** Disabled for your button reactions." + } else { + msgStr = "📊 **Reaction Summary Log:** Enabled for your button reactions." + } + _ = e.Respond(dc.Message{ Content: msgStr, Ephemeral: true, diff --git a/src/boost/boost_menu_test.go b/src/boost/boost_menu_test.go index c22ca4cd..3f8c1e5d 100644 --- a/src/boost/boost_menu_test.go +++ b/src/boost/boost_menu_test.go @@ -8,7 +8,9 @@ import ( "time" "github.com/mkmccarty/TokenTimeBoostBot/src/dc" + "github.com/mkmccarty/TokenTimeBoostBot/src/dc/dctest" "github.com/mkmccarty/TokenTimeBoostBot/src/ei" + "github.com/mkmccarty/TokenTimeBoostBot/src/farmerstate" ) func mustSandboxArtifact(t *testing.T, key string) ei.Artifact { @@ -222,3 +224,89 @@ func TestDrawBoostListCompactRange(t *testing.T) { t.Errorf("expected late list compaction '... (8 more) ...' not found in components") } } + +func TestToggleReactionLogPersistenceAndJoin(t *testing.T) { + testUserID := "4" + farmerstate.SetMiscSettingFlag(testUserID, "DisableEphemeralLog", true) + + client := dctest.New().WithUser(testUserID, "Tester", "Tester") + contract := &Contract{ + ContractHash: "test-rx-hash", + ContractID: "test-rx-contract", + CoopID: "test-rx-coop", + CoopSize: 10, + State: ContractStateSignup, + CreatorID: []string{"creator1"}, + Order: make([]string, 0), + Boosters: make(map[string]*Booster), + Location: []*LocationData{{GuildID: "guild1", ChannelID: "channel1"}}, + } + Contracts[contract.ContractHash] = contract + defer delete(Contracts, contract.ContractHash) + + // Test join carries over setting + b, err := AddFarmerToContract(client, contract, "guild1", "channel1", testUserID, ContractOrderSignup, false, false) + if err != nil { + t.Fatalf("unexpected error adding farmer: %v", err) + } + if !b.DisableEphemeralLog { + t.Errorf("expected DisableEphemeralLog to be true on join from farmerstate, got false") + } + + // Test toggling via menu + ev := dctest.ComponentSelectEvent("menu#"+contract.ContractHash, "togglerxlog") + + HandleMenuReactions(client, ev) + + if b.DisableEphemeralLog { + t.Errorf("expected DisableEphemeralLog to be toggled to false, got true") + } + if farmerstate.GetMiscSettingFlag(testUserID, "DisableEphemeralLog") { + t.Errorf("expected farmerstate DisableEphemeralLog to be false after toggle, got true") + } + + // Toggle again + HandleMenuReactions(client, ev) + if !b.DisableEphemeralLog { + t.Errorf("expected DisableEphemeralLog to be toggled back to true, got false") + } + if !farmerstate.GetMiscSettingFlag(testUserID, "DisableEphemeralLog") { + t.Errorf("expected farmerstate DisableEphemeralLog to be true after second toggle, got false") + } +} + +func TestToggleReactionLogMenuComponents(t *testing.T) { + contract := &Contract{ + ContractHash: "test-menu-hash", + ContractID: "test-menu-contract", + CoopID: "test-menu-coop", + State: ContractStateWaiting, + CreatorID: []string{"creator1"}, + Order: make([]string, 0), + Boosters: make(map[string]*Booster), + Location: []*LocationData{{GuildID: "guild1", ChannelID: "channel1"}}, + } + + components := getContractReactionsComponents(contract) + foundOption := false + for _, comp := range components { + if actionRow, ok := comp.(dc.ActionRow); ok { + for _, rowComp := range actionRow.Components { + if selectMenu, ok := rowComp.(dc.SelectMenu); ok { + for _, opt := range selectMenu.Options { + if opt.Value == "togglerxlog" { + foundOption = true + if opt.Description != "Toggle token log details on or off" { + t.Errorf("expected Description 'Toggle token log details on or off', got %q", opt.Description) + } + } + } + } + } + } + } + + if !foundOption { + t.Errorf("expected togglerxlog select option not found in contract reaction components") + } +}