はじめに
前回は「24 日目に LINE ミニアプリが完成する初心者 ── Day13. 問い合わせ機能の実装」と題して、Flex Message を使用した問い合わせ種別選択の実装を行いました。
今回は、前回の続きで問い合わせ内容の入力を促し、入力完了後にはお礼メッセージを送るよう実装していきたいと思います。
リファクタリング
前回実装したコードの一部をリファクタリングします。
問い合わせ種別を options としてまとめておきます。
const options = [
"物件情報の問い合わせ",
"お家探しの情報収集のやり方",
"住宅購入資金の考え方・予算について",
"新築と中古どちらを買うべきか?",
"リノベーションの流れについて",
"湘南エリアの魅力",
"リノベ不動産辻堂羽鳥店について",
"その他",
];
これでflexMessageで繰り返しになっている箇所をmapとしてまとめて記述したいと思います。
const flexMessage = {
type: "flex",
altText: "問い合わせカテゴリ",
contents: {
type: "bubble",
body: {
type: "box",
layout: "vertical",
contents: [
{
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: "お問い合わせの種類を選択してください。",
weight: "regular",
offsetStart: "xxl",
margin: "sm",
offsetTop: "md",
},
{
type: "separator",
margin: "xxl",
color: "#e5e5e5",
},
],
backgroundColor: "#fafafa",
},
{
type: "box",
layout: "vertical",
contents: [
...options.map((option) => ({
type: "button",
action: {
type: "message",
label: option,
text: option,
},
})),
],
paddingTop: "md",
paddingBottom: "md",
},
],
paddingAll: "none",
},
styles: {
footer: {
separator: true,
},
},
},
};
メッセージ送信処理は関数としてまとめておきたいと思います。
async function sendReply(replyToken, messages) {
const url = "https://api.line.me/v2/bot/message/reply";
await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_LINE_ACCESS_TOKEN}`,
},
body: JSON.stringify({ replyToken, messages }),
});
}
返信内容の追加
リファクタリングが完了したので、ここから実際に返信内容を追加していきます。
先にステータスが保持できるようコード冒頭で Map を作成しておきます。
const userState = new Map();
今回はユーザー ID ごとに状態を追跡していきます。
これに伴い、お問い合わせがあった際にuserId
でuserState
を更新する行を追加しておきます。
if (userMessage === ">お問い合わせ") {
userState.set(userId, { step: "categorySelection" });
const flexMessage = {
// (中略)
};
await sendReply(event.replyToken, [flexMessage]);
}
お問い合わせ内容確認
問い合わせ種別が選択されたら、「問い合わせ内容を入力してください。」という返信を返すよう追加していきます。
else if
としてuserMessage
が options に含まれているかを確認します。
if (userMessage === ">お問い合わせ") {
// (中略)
} else if (options.includes(userMessage)) {
userState.set(userId, { step: "detailsInput", category: userMessage });
await sendReply(event.replyToken, [
{ type: "text", text: "お問い合わせ内容を入力してください。" },
]);
}
お礼メッセージ
上記同様else if
で条件を追加していきます。
else if (options.includes(userMessage)) {
// (中略)
} else if (
userState.has(userId) &&
userState.get(userId).step === "detailsInput"
) {
userState.get(userId);
userState.delete(userId);
await sendReply(event.replyToken, [
{
type: "text",
text: "お問い合わせいただきありがとうございます!ご回答には通常2営業日以内に返答いたします。なにかご不明点があれば、お気軽にお問合せください!",
},
]);
}
コードの全体像は以下の通りです。
const userState = new Map();
export default async function handler(req, res) {
if (req.method === "POST") {
const { events } = req.body;
if (!events || events.length === 0) {
return res.status(200).json({ message: "No events" });
}
const event = events[0];
if (event.type === "message" && event.message.type === "text") {
const userMessage = event.message.text;
const userId = event.source.userId;
const options = [
"物件情報の問い合わせ",
"お家探しの情報収集のやり方",
"住宅購入資金の考え方・予算について",
"新築と中古どちらを買うべきか?",
"リノベーションの流れについて",
"湘南エリアの魅力",
"リノベ不動産辻堂羽鳥店について",
"その他",
];
if (userMessage === ">お問い合わせ") {
userState.set(userId, { step: "categorySelection" });
const flexMessage = {
type: "flex",
altText: "問い合わせカテゴリ",
contents: {
type: "bubble",
body: {
type: "box",
layout: "vertical",
contents: [
{
type: "box",
layout: "vertical",
contents: [
{
type: "text",
text: "お問い合わせの種類を選択してください。",
weight: "regular",
offsetStart: "xxl",
margin: "sm",
offsetTop: "md",
},
{
type: "separator",
margin: "xxl",
color: "#e5e5e5",
},
],
backgroundColor: "#fafafa",
},
{
type: "box",
layout: "vertical",
contents: [
...options.map((option) => ({
type: "button",
action: {
type: "message",
label: option,
text: option,
},
})),
],
paddingTop: "md",
paddingBottom: "md",
},
],
paddingAll: "none",
},
styles: {
footer: {
separator: true,
},
},
},
};
await sendReply(event.replyToken, [flexMessage]);
} else if (options.includes(userMessage)) {
userState.set(userId, { step: "detailsInput", category: userMessage });
await sendReply(event.replyToken, [
{ type: "text", text: "お問い合わせ内容を入力してください。" },
]);
} else if (
userState.has(userId) &&
userState.get(userId).step === "detailsInput"
) {
userState.get(userId);
userState.delete(userId);
await sendReply(event.replyToken, [
{
type: "text",
text: "お問い合わせいただきありがとうございます!ご回答には通常2営業日以内に返答いたします。なにかご不明点があれば、お気軽にお問合せください!",
},
]);
}
}
return res.status(200).json({ message: "Event processed" });
} else {
res.setHeader("Allow", ["POST"]);
return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
}
}
// メッセージ返信
async function sendReply(replyToken, messages) {
const url = "https://api.line.me/v2/bot/message/reply";
await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_LINE_ACCESS_TOKEN}`,
},
body: JSON.stringify({ replyToken, messages }),
});
}
デプロイ
以下のコマンドでいつも通りデプロイを行っていきましょう。
$ netlify deploy --build --prod
動作確認
LINE の画面で「>お問い合わせ」->「お問い合わせ種別の選択」と進んでみると、先ほど設定したお問い合わせ内容確認と、お礼メッセージが表示されると思います!
まとめ
ここまでで、Flex Message による問い合わせの流れが完成しました。
次回は、問い合わせのあった内容のスプレッドシート出力を実装していきたいと思います。
残りは 10 日!
気になる方は是非フォローやカレンダー購読をお願いします