feat(slack): ask the other person too, and put rating before sharing
ci / lint-test (push) Successful in 43s
ci / lint-test (push) Successful in 43s
Two halves of the same requirement, one of which was quietly missing. Sharing split the money but never reached her: she is not in #smarthome, so the card whose caption said "both verdicts welcome" was one she could not see. Now a share DMs her a card of her own. A DM rather than adding her to the channel, so her surface stays "orders that concern me" instead of the whole house's ops feed. She was already in SLACK_USER_MAP, so her press files under participant 4. Only on the press that turns sharing ON, and only when someone else did the sharing. Re-notifying on every later rating press would turn one shared meal into a stream of DMs, which is how a nudge gets muted. Her card carries no share button: she is being told it was shared, not asked to decide, and two people toggling one split from separate copies of a card is a race with no upside. The app still holds no Slack bot token — it returns a notify instruction and n8n sends it, the same shape as the modal open. If SLACK_USER_MAP has no id for her the DM is skipped silently: the split is correct and complete either way, and failing the press over an unaddressable nudge would be the worse trade. Card reordered to rate -> details -> share. You judge the food, then decide who pays for it; asking "was this shared?" first inverts the order a person thinks in. The status caption moved under the share button it describes rather than sitting orphaned mid-card.
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { queryRaw, queryRow } from "@/lib/db";
|
||||
import { verifySlackSignature, participantForSlackUser } from "@/lib/slack-verify";
|
||||
import { nudgeBlocks, detailsModal } from "@/lib/slack-blocks";
|
||||
import {
|
||||
verifySlackSignature,
|
||||
participantForSlackUser,
|
||||
slackUserForParticipant,
|
||||
} from "@/lib/slack-verify";
|
||||
import { nudgeBlocks, detailsModal, partnerNudgeBlocks } from "@/lib/slack-blocks";
|
||||
import {
|
||||
RATINGS,
|
||||
OWNER_PARTICIPANT_ID,
|
||||
@@ -105,14 +109,50 @@ export async function POST(req: NextRequest) {
|
||||
const state = await nudgeState(transactionId);
|
||||
if (!state) return NextResponse.json({ text: "That order is no longer in the ledger." });
|
||||
|
||||
// Ask the other person for their verdict, but only on the press that turned
|
||||
// sharing ON — and only when it was someone else who shared it with them.
|
||||
// Re-notifying on every subsequent rating press would make one shared meal
|
||||
// a stream of DMs, which is how a useful nudge becomes muted.
|
||||
const notify =
|
||||
verb === "share" && state.shared && participantId !== SECOND_CONSUMER_ID
|
||||
? buildPartnerNotify(state, payload.user?.name)
|
||||
: null;
|
||||
|
||||
return NextResponse.json({
|
||||
replace_original: true,
|
||||
blocks: nudgeBlocks(state),
|
||||
// Notification text for clients that cannot render blocks.
|
||||
text: `${state.merchant} — ${state.currency} ${state.total.toFixed(2)}`,
|
||||
...(notify ? { notify } : {}),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The DM payload for the other person, or null if we cannot address them.
|
||||
*
|
||||
* Returns an instruction rather than sending: the app holds no Slack bot token,
|
||||
* so n8n — which already has the credential — makes the call. Same shape as the
|
||||
* modal open.
|
||||
*
|
||||
* Null when SLACK_USER_MAP has no Slack id for the second consumer. Silent
|
||||
* rather than an error: the split is still correct and complete, and failing
|
||||
* the whole press because a DM could not be addressed would be worse than the
|
||||
* missing nudge.
|
||||
*/
|
||||
function buildPartnerNotify(
|
||||
state: Awaited<ReturnType<typeof nudgeState>>,
|
||||
sharerName?: string
|
||||
) {
|
||||
if (!state) return null;
|
||||
const slackUser = slackUserForParticipant(SECOND_CONSUMER_ID);
|
||||
if (!slackUser) return null;
|
||||
return {
|
||||
user: slackUser,
|
||||
text: `${state.merchant} — shared with you 50/50`,
|
||||
blocks: partnerNudgeBlocks(state, sharerName || "It was"),
|
||||
};
|
||||
}
|
||||
|
||||
/** The modal view, pre-filled with whatever this person already said. */
|
||||
async function buildDetailsModal(transactionId: number, participantId: number) {
|
||||
const row = await queryRow<{
|
||||
|
||||
Reference in New Issue
Block a user