Chuyển tới nội dung chính

Tin nhắn tương tác

Tin nhắn tương tác cho phép bot của bạn tạo trải nghiệm tin nhắn phong phú, hấp dẫn với nhiều thành phần như nút bấm, trường nhập liệu, menu thả xuống và hơn thế nữa. Mezon SDK cung cấp hai builder chính để tạo tin nhắn tương tác: InteractiveBuilder cho tin nhắn dạng embed phong phú và ButtonBuilder cho nhóm nút đơn giản.

Tổng quan

Tin nhắn tương tác hỗ trợ nhiều loại thành phần:

  • Nút bấm (Buttons) — Nút có thể nhấp với các kiểu khác nhau
  • Trường nhập liệu (Input Fields) — Ô nhập văn bản và textarea
  • Menu thả xuống (Select Dropdowns) — Menu dropdown với các tùy chọn
  • Nút radio (Radio Buttons) — Lựa chọn đơn hoặc nhiều lựa chọn
  • Bộ chọn ngày (Date Pickers) — Thành phần chọn ngày
  • Hoạt ảnh (Animations) — Thành phần hình ảnh có hoạt ảnh

ButtonBuilder

Lớp ButtonBuilder cung cấp cách đơn giản để tạo thành phần nút cho tin nhắn.

Import

import { ButtonBuilder, EButtonMessageStyle } from "mezon-sdk";

Kiểu nút

enum EButtonMessageStyle {
PRIMARY = 1, // Blue primary button
SECONDARY = 2, // Gray secondary button
SUCCESS = 3, // Green success button
DANGER = 4, // Red danger button
LINK = 5, // Link-styled button
}

Cách dùng cơ bản

const buttonBuilder = new ButtonBuilder();

// Add buttons with different styles
buttonBuilder
.addButton("btn-primary", "Click Me", EButtonMessageStyle.PRIMARY)
.addButton("btn-danger", "Delete", EButtonMessageStyle.DANGER)
.addButton("btn-link", "Learn More", EButtonMessageStyle.LINK);

// Build the button components
const buttons = buttonBuilder.build();

// Send message with buttons
await channel.send({
t: "Choose an action:",
components: [{ components: buttons }],
});

Ví dụ: Nút hành động

async function sendActionButtons(channel: TextChannel) {
const buttons = new ButtonBuilder()
.addButton("confirm", "Confirm", EButtonMessageStyle.SUCCESS)
.addButton("cancel", "Cancel", EButtonMessageStyle.SECONDARY)
.addButton("delete", "Delete", EButtonMessageStyle.DANGER)
.build();

await channel.send({
t: "Please confirm your action:",
components: buttons,
});
}

Xử lý sự kiện nhấn nút

Lắng nghe sự kiện nhấn nút bằng sự kiện onMessageButtonClicked:

client.onMessageButtonClicked((event) => {
console.log("Button clicked:", event.id);
console.log("Channel:", event.channel_id);
console.log("User:", event.user_id);

// Handle specific button actions
switch (event.id) {
case "confirm":
// Handle confirm action
break;
case "cancel":
// Handle cancel action
break;
case "delete":
// Handle delete action
break;
}
});

InteractiveBuilder

Lớp InteractiveBuilder cho phép bạn tạo tin nhắn dạng embed phong phú với nhiều thành phần tương tác.

Import

import { InteractiveBuilder, EMessageComponentType } from "mezon-sdk";

Constructor

const interactive = new InteractiveBuilder(title?: string);

Tạo builder tin nhắn tương tác mới với tiêu đề tùy chọn. Mỗi tin nhắn tương tác tự động bao gồm:

  • Màu ngẫu nhiên để phân biệt trực quan
  • Dấu thời gian hiện tại
  • Footer mặc định với thương hiệu Mezon

Thiết lập metadata tin nhắn

Đặt tác giả

setAuthor(name: string, icon_url?: string, url?: string): InteractiveBuilder

Đặt thông tin tác giả hiển thị ở đầu tin nhắn.

interactive.setAuthor(
"Bot Name",
"https://example.com/bot-icon.png",
"https://example.com/bot-profile",
);

Đặt mô tả

setDescription(description: string): InteractiveBuilder

Đặt nội dung mô tả chính cho tin nhắn tương tác.

interactive.setDescription(
"This is a detailed description of the form or information being presented.",
);

Đặt thumbnail

setThumbnail(url: string): InteractiveBuilder

Thêm ảnh thumbnail nhỏ vào tin nhắn.

interactive.setThumbnail("https://example.com/thumbnail.png");

Đặt ảnh

setImage(url: string, width?: string, height?: string): InteractiveBuilder

Thêm ảnh lớn hơn vào tin nhắn với kích thước tùy chọn.

interactive.setImage("https://example.com/banner.png", "800px", "400px");

Thêm trường

Thêm trường đơn giản

addField(name: string, value: string, inline: boolean = false): InteractiveBuilder

Thêm trường văn bản đơn giản vào tin nhắn.

interactive
.addField("Status", "Active", true)
.addField("Category", "General", true)
.addField("Description", "Full width field description", false);

Thành phần tương tác

Thêm trường nhập liệu

addInputField(
id: string,
name: string,
placeholder?: string,
options?: InputFieldOption,
description?: string
): InteractiveBuilder

Thêm trường nhập văn bản hoặc textarea.

Giao diện InputFieldOption:

interface InputFieldOption {
defaultValue?: string | number;
type?: string; // HTML input type: "text", "email", "password", etc.
textarea?: boolean; // Use textarea instead of input
disabled?: boolean;
}

Ví dụ:

// Simple text input
interactive.addInputField(
"username",
"Username",
"Enter your username",
{ type: "text" },
"Your preferred username",
);

// Email input
interactive.addInputField("email", "Email Address", "user@example.com", {
type: "email",
});

// Textarea
interactive.addInputField(
"bio",
"Biography",
"Tell us about yourself",
{
textarea: true,
defaultValue: "I am a developer...",
},
"Share your background and interests",
);

// Password input
interactive.addInputField("password", "Password", "Enter password", {
type: "password",
disabled: false,
});

Thêm trường select

addSelectField(
id: string,
name: string,
options: SelectFieldOption[],
valueSelected?: SelectFieldOption,
description?: string
): InteractiveBuilder

Thêm menu thả xuống select.

Giao diện SelectFieldOption:

interface SelectFieldOption {
label: string; // Display text
value: string; // Internal value
}

Ví dụ:

const countryOptions: SelectFieldOption[] = [
{ label: "United States", value: "us" },
{ label: "United Kingdom", value: "uk" },
{ label: "Canada", value: "ca" },
{ label: "Australia", value: "au" },
];

interactive.addSelectField(
"country",
"Country",
countryOptions,
{ label: "United States", value: "us" }, // Pre-selected
"Select your country",
);

Thêm trường radio

addRadioField(
id: string,
name: string,
options: RadioFieldOption[],
description?: string,
max_options?: number
): InteractiveBuilder

Thêm nút radio cho lựa chọn đơn hoặc nhiều lựa chọn.

Giao diện RadioFieldOption:

interface RadioFieldOption {
label: string;
value: string;
name?: string; // Used for multiple choice grouping
description?: string;
style?: EButtonMessageStyle;
disabled?: boolean;
}

Ví dụ:

// Single choice
const singleChoiceOptions: RadioFieldOption[] = [
{ label: "Option A", value: "a", description: "First option" },
{ label: "Option B", value: "b", description: "Second option" },
{ label: "Option C", value: "c", description: "Third option" },
];

interactive.addRadioField(
"choice",
"Choose One",
singleChoiceOptions,
"Select your preferred option",
);

// Multiple choice (with max_options)
const multiChoiceOptions: RadioFieldOption[] = [
{ label: "Feature A", value: "feature_a", name: "features" },
{ label: "Feature B", value: "feature_b", name: "features" },
{ label: "Feature C", value: "feature_c", name: "features" },
{ label: "Feature D", value: "feature_d", name: "features" },
];

interactive.addRadioField(
"features",
"Select Features",
multiChoiceOptions,
"Choose up to 2 features",
2, // Maximum 2 selections
);

Thêm trường chọn ngày

addDatePickerField(id: string, name: string, description?: string): InteractiveBuilder

Thêm thành phần chọn ngày.

Ví dụ:

interactive.addDatePickerField(
"appointment-date",
"Appointment Date",
"Select your preferred appointment date",
);

Thêm hoạt ảnh

addAnimation(
id: string,
config: AnimationConfig,
name?: string,
description?: string
): InteractiveBuilder

Thêm thành phần hình ảnh có hoạt ảnh vào tin nhắn.

Giao diện AnimationConfig:

interface AnimationConfig {
url_image: string; // Base image URL
url_position: string; // Position data URL
pool: string[]; // Array of animation frame URLs
repeat?: number; // Number of times to repeat (default: infinite)
duration?: number; // Duration in milliseconds
}

Ví dụ:

const animConfig: AnimationConfig = {
url_image: "https://example.com/base-image.png",
url_position: "https://example.com/positions.json",
pool: [
"https://example.com/frame1.png",
"https://example.com/frame2.png",
"https://example.com/frame3.png",
],
repeat: 3,
duration: 2000,
};

interactive.addAnimation(
"welcome-anim",
animConfig,
"Welcome Animation",
"Animated welcome banner",
);

Build và gửi

Build tin nhắn tương tác

build(): IInteractiveMessageProps

Build và trả về đối tượng tin nhắn tương tác hoàn chỉnh.

const interactiveMessage = interactive.build();

Gửi dưới dạng nội dung tin nhắn

// Send interactive message through a channel
await channel.send({
embed: [interactiveMessage],
});

// Send with text and interactive message
await channel.send({
t: "Please fill out this form:",
embed: [interactiveMessage],
});

// Send with buttons
await channel.send({
t: "Choose an option:",
components: buttonComponents,
});

// Send with both interactive message and buttons
await channel.send({
embed: [interactiveMessage],
components: buttonComponents,
});

// Send with additional options (mentions, attachments, etc.)
await channel.send(
{
t: "Form submission required",
embed: [interactiveMessage],
components: buttonComponents,
},
mentions, // Array<ApiMessageMention> - optional
attachments, // Array<ApiMessageAttachment> - optional
false, // mention_everyone - optional
false, // anonymous_message - optional
topic_id, // string - optional (for threads)
0, // code - optional (message type code)
);

Tham số channel.send():

async send(
content: ChannelMessageContent,
mentions?: Array<ApiMessageMention>,
attachments?: Array<ApiMessageAttachment>,
mention_everyone?: boolean,
anonymous_message?: boolean,
topic_id?: string,
code?: number
)
  • content: ChannelMessageContent (bắt buộc) — Đối tượng nội dung tin nhắn gồm:
    • t?: Nội dung văn bản
    • embed?: Mảng tin nhắn tương tác (IInteractiveMessageProps[])
    • components?: Thành phần nút hoặc action row
  • mentions?: Mảng mention người dùng
  • attachments?: Mảng tệp đính kèm
  • mention_everyone?: Có mention mọi người hay không
  • anonymous_message?: Có gửi ẩn danh hay không
  • topic_id?: Định danh topic/chủ đề
  • code?: Mã loại tin nhắn

Ví dụ đầy đủ

Ví dụ 1: Form đăng ký người dùng

import { InteractiveBuilder, TextChannel } from "mezon-sdk";

async function sendRegistrationForm(channel: TextChannel) {
const form = new InteractiveBuilder("User Registration")
.setDescription("Please fill out the registration form below")
.setThumbnail("https://example.com/logo.png")

// Username field
.addInputField(
"username",
"Username",
"Enter username",
{ type: "text" },
"Choose a unique username"
)

// Email field
.addInputField(
"email",
"Email Address",
"user@example.com",
{ type: "email" }
)

// Password field
.addInputField(
"password",
"Password",
"Enter password",
{ type: "password" },
"Must be at least 8 characters"
)

// Country selection
.addSelectField(
"country",
"Country",
[
{ label: "United States", value: "us" },
{ label: "United Kingdom", value: "uk" },
{ label: "Canada", value: "ca" },
]
)

// Terms acceptance
.addRadioField(
"terms",
"Terms & Conditions",
[
{ label: "I accept the terms and conditions", value: "accept" }
]
)

.build();

await channel.send({ embed: [form] });
}

Ví dụ 2: Khảo sát với nhiều thành phần

async function sendSurvey(channel: TextChannel) {
const survey = new InteractiveBuilder("Customer Satisfaction Survey")
.setAuthor("Survey Bot", "https://example.com/bot-icon.png")
.setDescription(
"Help us improve our service by completing this short survey",
)
.setImage("https://example.com/survey-banner.png")

// Name input
.addInputField("name", "Your Name", "Enter your name", { type: "text" })

// Satisfaction rating
.addRadioField("satisfaction", "How satisfied are you with our service?", [
{ label: "Very Satisfied", value: "5" },
{ label: "Satisfied", value: "4" },
{ label: "Neutral", value: "3" },
{ label: "Dissatisfied", value: "2" },
{ label: "Very Dissatisfied", value: "1" },
])

// Product categories
.addSelectField("category", "Which product did you use?", [
{ label: "Product A", value: "product-a" },
{ label: "Product B", value: "product-b" },
{ label: "Product C", value: "product-c" },
])

// Features used (multiple choice)
.addRadioField(
"features",
"Which features did you use?",
[
{ label: "Feature X", value: "feature-x", name: "features" },
{ label: "Feature Y", value: "feature-y", name: "features" },
{ label: "Feature Z", value: "feature-z", name: "features" },
],
"Select all that apply",
3,
)

// Feedback textarea
.addInputField(
"feedback",
"Additional Feedback",
"Share your thoughts...",
{ textarea: true },
"Optional: Tell us more about your experience",
)

.build();

await channel.send({ embed: [survey] });
}

Ví dụ 3: Kết hợp tin nhắn tương tác với nút bấm

import {
InteractiveBuilder,
ButtonBuilder,
EButtonMessageStyle,
} from "mezon-sdk";

async function sendFormWithButtons(channel: TextChannel) {
// Create the interactive form
const form = new InteractiveBuilder("Event Registration")
.setDescription("Register for our upcoming event")

.addInputField("name", "Full Name", "Enter your name")
.addInputField("email", "Email", "your@email.com", { type: "email" })
.addDatePickerField("date", "Preferred Date", "Select event date")

.build();

// Create action buttons
const buttons = new ButtonBuilder()
.addButton("submit", "Submit Registration", EButtonMessageStyle.PRIMARY)
.addButton("cancel", "Cancel", EButtonMessageStyle.SECONDARY)
.build();

// Send combined message
await channel.send({
embed: [form],
components: buttons,
});
}

Ví dụ 4: Form động với trường có điều kiện

async function sendDynamicForm(channel: TextChannel, userType: string) {
const form = new InteractiveBuilder("Profile Setup");

// Common fields for all users
form
.addInputField("username", "Username", "Enter username")
.addInputField("email", "Email", "your@email.com", { type: "email" });

// Conditional fields based on user type
if (userType === "developer") {
form
.addSelectField("experience", "Experience Level", [
{ label: "Junior (0-2 years)", value: "junior" },
{ label: "Mid-level (2-5 years)", value: "mid" },
{ label: "Senior (5+ years)", value: "senior" },
])
.addRadioField(
"languages",
"Programming Languages",
[
{ label: "JavaScript/TypeScript", value: "js", name: "langs" },
{ label: "Python", value: "python", name: "langs" },
{ label: "Java", value: "java", name: "langs" },
{ label: "Go", value: "go", name: "langs" },
],
"Select your primary languages",
3,
);
} else if (userType === "designer") {
form
.addSelectField("specialty", "Design Specialty", [
{ label: "UI/UX Design", value: "uiux" },
{ label: "Graphic Design", value: "graphic" },
{ label: "Motion Graphics", value: "motion" },
])
.addInputField("portfolio", "Portfolio URL", "https://", { type: "url" });
}

// Bio field for all
form.addInputField("bio", "Bio", "Tell us about yourself", {
textarea: true,
});

await channel.send({ embed: [form.build()] });
}

Xử lý sự kiện

Xử lý đầu vào của người dùng

Khi người dùng tương tác với tin nhắn tương tác của bạn, bạn sẽ nhận các sự kiện có thể xử lý:

// Button clicks
client.onMessageButtonClicked((event) => {
console.log("Button clicked:", event.id);
// Handle button action
});

// Dropdown selections
client.onDropdownBoxSelected((event) => {
console.log("Dropdown selected:", event.id, event.value);
// Handle selection
});

// Handle other interactive events as needed

Xử lý gửi form

client.onMessageButtonClicked(async (event) => {
if (event.id === "submit-form") {
// Collect form data from the message
// Process the submission
const channel = await client.channels.fetch(event.channel_id);

await channel.send({
t: `Thank you for submitting the form! ✅`,
});
}
});

Thực hành tốt nhất

1. Dùng đúng loại thành phần

  • Trường nhập liệu: Cho nhập văn bản tự do
  • Menu thả xuống: Cho 4–10 tùy chọn định sẵn
  • Nút radio: Cho 2–5 lựa chọn loại trừ lẫn nhau
  • Bộ chọn ngày: Cho chọn ngày/giờ

2. Cung cấp nhãn và mô tả rõ ràng

// Good
interactive.addInputField(
"email",
"Email Address",
"user@example.com",
{ type: "email" },
"We'll never share your email with anyone",
);

// Less clear
interactive.addInputField("email", "Email", "...");

3. Đặt giá trị mặc định hợp lý

interactive.addSelectField(
"country",
"Country",
countryOptions,
{ label: "United States", value: "us" }, // Default selection
"Select your country",
);

4. Xác thực đầu vào người dùng

Luôn xác thực và làm sạch đầu vào người dùng ở phía server khi xử lý gửi form.

5. Cung cấp phản hồi

Sau khi gửi form, hãy phản hồi rõ ràng cho người dùng:

client.onMessageButtonClicked(async (event) => {
if (event.id === "submit") {
try {
// Process form...
await channel.send({ t: "✅ Form submitted successfully!" });
} catch (error) {
await channel.send({ t: "❌ Error submitting form. Please try again." });
}
}
});

6. Giới hạn độ phức tạp của form

Giữ form tập trung, không quá dài. Chia form phức tạp thành nhiều bước nếu cần.

7. Dùng kiểu nhất quán

Dùng kiểu nút nhất quán trong toàn bộ bot:

  • PRIMARY: Hành động chính (Gửi, Lưu, Xác nhận)
  • SUCCESS: Hành động tích cực (Phê duyệt, Chấp nhận)
  • DANGER: Hành động phá hủy (Xóa, Gỡ)
  • SECONDARY: Hành động thay thế (Hủy, Bỏ qua)
  • LINK: Điều hướng hoặc hành động ít nổi bật hơn

Tham chiếu loại thành phần

enum EMessageComponentType {
BUTTON = 1, // Clickable buttons
SELECT = 2, // Dropdown select menus
INPUT = 3, // Text inputs and textareas
DATEPICKER = 4, // Date selection components
RADIO = 5, // Radio buttons (single/multiple choice)
ANIMATION = 6, // Animated elements
GRID = 7, // Grid layouts
}

Khắc phục sự cố

Tin nhắn tương tác không hiển thị

Đảm bảo bạn build và gửi tin nhắn đúng cách:

const interactive = new InteractiveBuilder("Title")
.addField("Name", "Value")
.build(); // Don't forget to call build()!

await channel.send({ embed: [interactive] });

Nút không phản hồi

Hãy chắc chắn bạn đã đăng ký handler sự kiện nhấn nút:

client.onMessageButtonClicked((event) => {
// Handle button clicks
});

Không thu thập được dữ liệu form

Dữ liệu tin nhắn tương tác được gửi qua các sự kiện cụ thể. Hãy lắng nghe đúng sự kiện theo loại thành phần bạn dùng.

Tài nguyên bổ sung