snapshot_poker_uiux_cleanup_2

This commit is contained in:
DeSqBlocki
2026-09-08 21:05:52 +02:00
parent 82cef1b34a
commit c61e34c241
6 changed files with 475 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
const {
EmbedBuilder,
ActionRowBuilder,
ButtonBuilder,
ButtonStyle
} = require("discord.js");
const {
getPokerService
} = require("../../utils/crumbPoker");
const {
POKER_TABLE_FOOTER_PREFIX,
deferPokerReply,
editPokerError,
getPokerGameIdFromInteraction
} = require("../../utils/pokerDiscord");
module.exports = {
name: "pokerCancel",
async execute(interaction) {
await deferPokerReply(interaction);
const gameId =
getPokerGameIdFromInteraction(interaction);
if (!gameId) {
return interaction.editReply({
content: "❌ This Poker table is no longer active.",
embeds: [],
components: []
});
}
try {
const game =
await getPokerService().getTable({ gameId });
if (
String(game.data.ownerId) !==
String(interaction.user.id)
) {
return interaction.editReply({
content: "❌ Only the table owner can cancel this Poker table.",
embeds: [],
components: []
});
}
return interaction.editReply({
content: "",
embeds: [
new EmbedBuilder()
.setTitle("🛑 Cancel Poker Table?")
.setDescription(
[
"All seated players will be safely cashed out.",
"",
"This cannot be undone."
].join("\n")
)
.setFooter({
text: `${POKER_TABLE_FOOTER_PREFIX}:${gameId}`
})
],
components: [
new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId("pokerCancelConfirm")
.setLabel("Cancel Table")
.setEmoji("🛑")
.setStyle(ButtonStyle.Danger),
new ButtonBuilder()
.setCustomId("pokerCancelKeep")
.setLabel("Keep Table")
.setStyle(ButtonStyle.Secondary)
)
]
});
} catch (error) {
return editPokerError(interaction, error);
}
}
};
+50
View File
@@ -0,0 +1,50 @@
const {
getPokerService
} = require("../../utils/crumbPoker");
const {
deferPokerReply,
editPokerError,
getPokerGameIdFromInteraction,
refreshPokerTableMessage
} = require("../../utils/pokerDiscord");
module.exports = {
name: "pokerCancelConfirm",
async execute(interaction) {
await deferPokerReply(interaction);
const gameId =
getPokerGameIdFromInteraction(interaction);
if (!gameId) {
return interaction.editReply({
content: "❌ This Poker table is no longer active.",
embeds: [],
components: []
});
}
try {
const game =
await getPokerService().cancelTable({
gameId,
userId: interaction.user.id
});
await refreshPokerTableMessage(
interaction.client,
game
);
return interaction.editReply({
content: "✅ Poker table cancelled. All seated players were cashed out.",
embeds: [],
components: []
});
} catch (error) {
return editPokerError(interaction, error);
}
}
};
+17
View File
@@ -0,0 +1,17 @@
const {
deferPokerReply
} = require("../../utils/pokerDiscord");
module.exports = {
name: "pokerCancelKeep",
async execute(interaction) {
await deferPokerReply(interaction);
return interaction.editReply({
content: "✅ Poker table left open.",
embeds: [],
components: []
});
}
};
+41
View File
@@ -470,6 +470,46 @@ async function changeCookiesOnce(
} }
async function clearCookieOperation(
userId,
operationId
) {
if (
typeof operationId !==
"string"
||
!/^[A-Za-z0-9:_-]{1,160}$/.test(
operationId
)
) {
throw new Error(
"INVALID_COOKIE_OPERATION_ID"
);
}
const {
cookies
} =
getCollections();
const result =
await cookies.updateOne(
{
userId
},
{
$pull: {
appliedCookieOperations:
operationId
}
}
);
return result.modifiedCount ===
1;
}
async function hasCookieOperation( async function hasCookieOperation(
userId, userId,
operationId operationId
@@ -1435,6 +1475,7 @@ module.exports = {
changeCookies, changeCookies,
changeCookiesOnce, changeCookiesOnce,
hasCookieOperation, hasCookieOperation,
clearCookieOperation,
transferCookies, transferCookies,
getCooldown, getCooldown,
+264
View File
@@ -818,6 +818,22 @@ function createMongoPokerStore(
); );
}, },
async deleteGame(
gameId
) {
const result =
await collection.deleteOne({
gameId,
gameType:
POKER_GAME_TYPE,
recordType:
"game"
});
return result.deletedCount ===
1;
},
async listActiveGames() { async listActiveGames() {
const documents = const documents =
await collection await collection
@@ -1114,6 +1130,22 @@ function createDefaultPokerEconomy() {
userId, userId,
operationId operationId
); );
},
async clearOperation(
userId,
operationId
) {
const {
clearCookieOperation
} = require(
"./cookieEconomy"
);
return clearCookieOperation(
userId,
operationId
);
} }
}; };
} }
@@ -1139,6 +1171,43 @@ function createPokerService({
lobbyTimeout = lobbyTimeout =
POKER_LOBBY_TIMEOUT POKER_LOBBY_TIMEOUT
} = {}) { } = {}) {
async function clearOperationQuietly(
userId,
operationId
) {
try {
await economy.clearOperation(
userId,
operationId
);
}
catch (error) {
console.error(
`[Poker] Failed to clear completed Cookie operation ${operationId} for ${userId}:`,
error
);
}
}
async function deleteGameQuietly(
gameId
) {
try {
await store.deleteGame(
gameId
);
}
catch (error) {
console.error(
`[Poker] Failed to delete settled table ${gameId}:`,
error
);
}
}
async function readGame( async function readGame(
gameId gameId
) { ) {
@@ -1234,6 +1303,22 @@ function createPokerService({
gameId, gameId,
sessionId sessionId
); );
await clearOperationQuietly(
userId,
buyInOperationId(
gameId,
sessionId
)
);
await clearOperationQuietly(
userId,
buyInRefundOperationId(
gameId,
sessionId
)
);
} }
} }
@@ -1362,6 +1447,14 @@ function createPokerService({
sessionId, sessionId,
now() now()
); );
await clearOperationQuietly(
ownerId,
buyInOperationId(
gameId,
sessionId
)
);
} }
catch (error) { catch (error) {
@@ -1519,6 +1612,14 @@ function createPokerService({
sessionId, sessionId,
now() now()
); );
await clearOperationQuietly(
userId,
buyInOperationId(
gameId,
sessionId
)
);
} }
catch (error) { catch (error) {
@@ -2317,6 +2418,23 @@ function createPokerService({
player.sessionId player.sessionId
); );
await clearOperationQuietly(
userId,
cashOutOperationId(
gameId,
player.sessionId
)
);
if (
nextGame.state ===
"CLOSED"
) {
await deleteGameQuietly(
gameId
);
}
return { return {
amount, amount,
game: game:
@@ -2403,6 +2521,23 @@ function createPokerService({
closed closed
) )
) { ) {
for (
const player
of current.data.players
) {
await clearOperationQuietly(
player.userId,
cashOutOperationId(
gameId,
player.sessionId
)
);
}
await deleteGameQuietly(
gameId
);
return closed; return closed;
} }
} }
@@ -2413,6 +2548,88 @@ function createPokerService({
); );
} }
async function cancelTable({
gameId,
userId
}) {
const game =
await readGame(
gameId
);
if (
String(game.data.ownerId) !==
String(userId)
) {
throw new PokerTableError(
"NOT_TABLE_OWNER",
"Only the Poker table owner can cancel this table."
);
}
if (
isHandActive(
game
)
) {
throw new PokerTableError(
"CANCEL_HAND_ACTIVE",
"Finish the current hand before cancelling the table."
);
}
if (
game.state ===
"CLOSING"
) {
return finishClosingTable(
gameId
);
}
if (
!POKER_OPEN_STATES.includes(
game.state
)
) {
throw new PokerTableError(
"TABLE_NOT_CANCELLABLE",
"This Poker table cannot be cancelled in its current state."
);
}
const closing =
clone(game);
closing.state =
"CLOSING";
closing.version =
game.version + 1;
closing.updatedAt =
now();
const committed =
await store.updateGameVersion(
gameId,
game.version,
closing
);
if (!committed) {
throw new PokerTableError(
"STATE_CONFLICT",
"Poker table changed while cancellation was starting."
);
}
return finishClosingTable(
gameId
);
}
async function expireLobby( async function expireLobby(
gameId gameId
) { ) {
@@ -2569,6 +2786,28 @@ function createPokerService({
player.sessionId player.sessionId
); );
await clearOperationQuietly(
player.userId,
cashOutOperationId(
game.gameId,
player.sessionId
)
);
const remainingGame =
await store.getGame(
game.gameId
);
if (
remainingGame?.state ===
"CLOSED"
) {
await deleteGameQuietly(
game.gameId
);
}
results.push({ results.push({
gameId: gameId:
game.gameId, game.gameId,
@@ -2651,6 +2890,14 @@ function createPokerService({
now() now()
); );
await clearOperationQuietly(
userId,
buyInOperationId(
tableGameId,
sessionId
)
);
results.push({ results.push({
userId, userId,
gameId: gameId:
@@ -2692,6 +2939,22 @@ function createPokerService({
sessionId sessionId
); );
await clearOperationQuietly(
userId,
buyInOperationId(
tableGameId,
sessionId
)
);
await clearOperationQuietly(
userId,
buyInRefundOperationId(
tableGameId,
sessionId
)
);
results.push({ results.push({
userId, userId,
gameId: gameId:
@@ -2750,6 +3013,7 @@ function createPokerService({
processTurnTimeout, processTurnTimeout,
processExpiredTurns, processExpiredTurns,
cashOut, cashOut,
cancelTable,
finishClosingTable, finishClosingTable,
expireLobby, expireLobby,
processExpiredLobbies, processExpiredLobbies,
+18
View File
@@ -110,6 +110,10 @@ function formatPokerError(
"There is no active Poker hand.", "There is no active Poker hand.",
HAND_ACTIVE: HAND_ACTIVE:
"You cannot cash out during an active Poker hand.", "You cannot cash out during an active Poker hand.",
CANCEL_HAND_ACTIVE:
"Finish the current hand before cancelling the table.",
TABLE_NOT_CANCELLABLE:
"This Poker table cannot be cancelled right now.",
OUT_OF_TURN: OUT_OF_TURN:
"It isn't your turn.", "It isn't your turn.",
TURN_EXPIRED: TURN_EXPIRED:
@@ -715,6 +719,20 @@ function buildPokerTableComponents(
) )
.setStyle( .setStyle(
ButtonStyle.Secondary ButtonStyle.Secondary
),
new ButtonBuilder()
.setCustomId(
"pokerCancel"
)
.setLabel(
"Cancel Table"
)
.setEmoji(
"🛑"
)
.setStyle(
ButtonStyle.Danger
) )
) )
]; ];