Skip to content

Commit

Permalink
Edit card example via server bot (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
kubk authored Dec 20, 2023
1 parent 8ce7d6b commit b8e7343
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 13 deletions.
3 changes: 2 additions & 1 deletion functions/db/user/user-set-server-bot-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export type ServerBotState =
type: "deckSelected";
cardFront: string;
cardBack: string;
cardExample: string | null;
deckId: number;
editingField?: "cardFront" | "cardBack";
editingField?: "cardFront" | "cardBack" | "cardExample";
};

export const userSetServerBotState = async (
Expand Down
1 change: 1 addition & 0 deletions functions/server-bot/callback-query-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum CallbackQueryType {
Deck = "deck",
ConfirmCreateCard = "confirm",
EditFront = "edit-front",
EditExample = "edit-example",
EditBack = "edit-back",
Cancel = "cancel",
}
6 changes: 3 additions & 3 deletions functions/server-bot/escape-markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ const SPECIAL_CHARS = [
"{",
"}",
".",
"!"
"!",
];

// https://core.telegram.org/bots/api#markdownv2-style
export const escapeMarkdown = (text: string) => {
SPECIAL_CHARS.forEach(char => {
const regex = new RegExp(`\\${char}`, 'g');
SPECIAL_CHARS.forEach((char) => {
const regex = new RegExp(`\\${char}`, "g");
text = text.replace(regex, `\\${char}`);
});
return text;
Expand Down
47 changes: 40 additions & 7 deletions functions/server-bot/on-callback-query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,37 @@ import {
import { sendCardCreateConfirmMessage } from "./send-card-create-confirm-message.ts";
import { DatabaseException } from "../db/database-exception.ts";

type CallbackQueryEdit =
| CallbackQueryType.EditFront
| CallbackQueryType.EditBack
| CallbackQueryType.EditExample;

const callbackQueryEditTypeToField = (data: CallbackQueryEdit) => {
switch (data) {
case CallbackQueryType.EditFront:
return "cardFront";
case CallbackQueryType.EditBack:
return "cardBack";
case CallbackQueryType.EditExample:
return "cardExample";
default:
return data satisfies never;
}
};

const callbackQueryToHumanReadable = (data: CallbackQueryEdit) => {
switch (data) {
case CallbackQueryType.EditFront:
return "front";
case CallbackQueryType.EditBack:
return "back";
case CallbackQueryType.EditExample:
return "example";
default:
return data satisfies never;
}
};

export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => {
assert(ctx.callbackQuery);
assert(ctx.from);
Expand All @@ -34,6 +65,7 @@ export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => {
type: "deckSelected",
cardBack: state.cardBack,
cardFront: state.cardFront,
cardExample: null,
deckId,
});

Expand All @@ -44,19 +76,19 @@ export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => {

if (
data === CallbackQueryType.EditFront ||
data === CallbackQueryType.EditBack
data === CallbackQueryType.EditBack ||
data === CallbackQueryType.EditExample
) {
const isFront = data === CallbackQueryType.EditFront;
const state = await userGetServerBotState(envSafe, ctx.from.id);
assert(state?.type === "deckSelected", "State is not deckSelected");
const editingField = callbackQueryEditTypeToField(data);
const editingFieldHuman = callbackQueryToHumanReadable(data);
await userSetServerBotState(envSafe, ctx.from.id, {
...state,
editingField: isFront ? "cardFront" : "cardBack",
editingField,
});
await ctx.deleteMessage();
await ctx.reply(
`Send a message with the new ${isFront ? "front" : "back"}:`,
);
await ctx.reply(`Send a message with the new ${editingFieldHuman}:`);
return;
}

Expand All @@ -75,13 +107,14 @@ export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => {
deck_id: state.deckId,
front: state.cardFront,
back: state.cardBack,
example: state.cardExample,
});

if (createCardsResult.error) {
throw new DatabaseException(createCardsResult.error);
}

await ctx.reply('Card has been created');
await ctx.reply("Card has been created");
await ctx.deleteMessage();
await userSetServerBotState(envSafe, ctx.from.id, null);
return;
Expand Down
16 changes: 14 additions & 2 deletions functions/server-bot/send-card-create-confirm-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import {
import { CallbackQueryType } from "./callback-query-type.ts";
import { escapeMarkdown } from "./escape-markdown.ts";

const renderFieldValue = (value: string | null) => {
if (!value) {
return "_None_";
}

return escapeMarkdown(value);
};

export const sendCardCreateConfirmMessage = async (
envSafe: EnvSafe,
ctx: Context,
Expand All @@ -21,14 +29,17 @@ export const sendCardCreateConfirmMessage = async (
cardBack: state.cardBack,
cardFront: state.cardFront,
deckId: state.deckId,
cardExample: state.cardExample,
});

await ctx.deleteMessage();

await ctx.reply(
`Confirm card creation:\n\n*Front:*\n${escapeMarkdown(
`Confirm card creation:\n\n*Front:* ${renderFieldValue(
state.cardFront,
)}\n\n*Back:*\n${escapeMarkdown(state.cardBack)}`,
)}\n\n*Back:* ${renderFieldValue(
state.cardBack,
)}\n\n*Example:* ${renderFieldValue(state.cardExample)}`,
{
parse_mode: "MarkdownV2",
reply_markup: InlineKeyboard.from([
Expand All @@ -41,6 +52,7 @@ export const sendCardCreateConfirmMessage = async (
[
InlineKeyboard.text(`✏️ Edit front`, CallbackQueryType.EditFront),
InlineKeyboard.text(`✏️ Edit back`, CallbackQueryType.EditBack),
InlineKeyboard.text(`✏️ Edit example`, CallbackQueryType.EditExample),
],
[InlineKeyboard.text(`❌ Cancel`, CallbackQueryType.Cancel)],
]),
Expand Down

0 comments on commit b8e7343

Please sign in to comment.