Q&A掲示板
来場者からの匿名質問受付と運営本部によるリアルタイム回答管理。質問の投稿・閲覧、管理者による回答作成・編集理由の記録、不適切投稿の削除に対応。
使い方
参加者向け
import QAStatus from "@/features/qa/components/QAStatus";
<QAStatus />全体管理者向け
import QAManager from "@/features/qa/components/QAManager";
<QAManager />API src/features/qa/api.ts
質問・回答一覧の取得はアプリ共通の DataContext.FetchedData.questions を通じて自動ポーリング・キャッシュ管理され、質問投稿・回答・削除は以下の API を通じて行われます。更新時は自動でキャッシュが無効化されます。
| API 関数 | 引数 / ペイロード | 役割 |
|---|---|---|
askQuestion(text) | text : string | 来場者から匿名で質問を投稿し qa キャッシュを無効化 |
replyToQuestion(id, answer, reason?) | id : stringanswer : stringreason? : string | 管理者専用 : 回答を投稿・更新。修正時は edit_reason に時刻付きで理由を記録 |
deleteQuestion(id) | id : string | 管理者専用 : 不適切な質問や解決済みの問い合わせを削除 |
コード
回答・編集理由のタイムスタンプ記録 src/features/qa/api.ts
回答内容を更新する際、管理者が入力した修正理由に現在時刻 (HH:mm) を付与して edit_reason カラムへ記録します。
export const replyToQuestion = async (id: string, answer: string, reason?: string) => {
return performMutation(async () => {
const updates: { answer: string; edit_reason?: string } = { answer };
if (reason && reason.trim() !== "") {
const now = new Date();
const timeStr = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
updates.edit_reason = `${reason} (${timeStr})`;
}
const { error } = await supabase.from("questions").update(updates).eq("id", id);
if (error) throw error;
return { success: true };
});
};データベーススキーマ
CREATE TABLE questions (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
question TEXT NOT NULL,
answer TEXT,
edit_reason TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()),
answered_at TIMESTAMP WITH TIME ZONE
);