feat: chat stickers
This commit is contained in:
+26
-1
@@ -171,7 +171,8 @@ export type AttachmentKind =
|
||||
| "file"
|
||||
| "link"
|
||||
| "entity"
|
||||
| "quote";
|
||||
| "quote"
|
||||
| "sticker";
|
||||
|
||||
/** One emoji on a message, grouped across everyone who chose it. */
|
||||
export type Reaction = {
|
||||
@@ -181,6 +182,15 @@ export type Reaction = {
|
||||
mine: boolean;
|
||||
};
|
||||
|
||||
/** A piece of reward artwork the caller may send. */
|
||||
export type Sticker = {
|
||||
key: string;
|
||||
name: string;
|
||||
image_url: string;
|
||||
/** Came from a chat rather than from sādhana. */
|
||||
saved: boolean;
|
||||
};
|
||||
|
||||
/** One person's reaction, for the "who reacted" list. */
|
||||
export type ReactionDetail = {
|
||||
user: ChatPeer;
|
||||
@@ -303,6 +313,8 @@ export const chat = {
|
||||
quote?: QuotePayload;
|
||||
/** Share a post as a card. Only the reference — the BFF resolves it. */
|
||||
entity?: { type: "post"; id: string };
|
||||
/** Send reward artwork. Ownership is checked server-side. */
|
||||
stickerKey?: string;
|
||||
},
|
||||
) =>
|
||||
call<ChatMessage>(`/chat/conversations/${conversationId}/messages`, {
|
||||
@@ -316,6 +328,7 @@ export const chat = {
|
||||
attachments: opts?.attachments ?? [],
|
||||
quote: opts?.quote ?? null,
|
||||
entity: opts?.entity ?? null,
|
||||
sticker_key: opts?.stickerKey ?? null,
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -441,6 +454,18 @@ export const chat = {
|
||||
method: "POST",
|
||||
}),
|
||||
|
||||
/** Everything the caller can send: earned through sādhana, or saved from
|
||||
* a chat. */
|
||||
stickers: () => call<Sticker[]>("/chat/stickers"),
|
||||
|
||||
/** Keep a sticker someone sent. Keyed to the message it arrived on, which
|
||||
* is what proves it was actually sent to you. */
|
||||
saveSticker: (conversationId: string, messageId: string, key: string) =>
|
||||
call<void>(
|
||||
`/chat/conversations/${conversationId}/messages/${messageId}/sticker`,
|
||||
{ method: "POST", body: JSON.stringify({ key }) },
|
||||
),
|
||||
|
||||
/** Who reacted, and with what. Only fetched when the list is opened —
|
||||
* the thread renders from the grouped counts on each message. */
|
||||
reactionDetails: (conversationId: string, messageId: string) =>
|
||||
|
||||
+11
-1
@@ -111,9 +111,13 @@ export type SadhnaReward = {
|
||||
|
||||
/** A reward earned at a streak milestone (a multiple of 7 days). */
|
||||
export type SadhnaRewardGrant = {
|
||||
milestone: number;
|
||||
/** The streak day this was earned on. Null for an occasional gift. */
|
||||
milestone: number | null;
|
||||
granted_at: string;
|
||||
reward: SadhnaReward;
|
||||
source: "streak" | "gift";
|
||||
/** False while a gift is still wrapped — the gallery blurs those. */
|
||||
opened: boolean;
|
||||
};
|
||||
|
||||
// ─── API ───────────────────────────────────────────────────────────────
|
||||
@@ -140,6 +144,12 @@ export const sadhna = {
|
||||
rewards: () =>
|
||||
call<{ collected: SadhnaRewardGrant[]; total: number }>("/sadhna/rewards"),
|
||||
|
||||
/** Open one gift, after its celebration is dismissed. Idempotent. */
|
||||
openGift: (rewardKey: string) =>
|
||||
call<void>(`/sadhna/rewards/gifts/${encodeURIComponent(rewardKey)}/open`, {
|
||||
method: "POST",
|
||||
}),
|
||||
|
||||
/** Acknowledge pending celebrations after showing the confetti. */
|
||||
ackRewards: () => call<void>("/sadhna/rewards/ack", { method: "POST" }),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user