Files
acmcc/src/lib/messageTopics.ts
T
admin d5145e2515 Messaging: board topic threads with management + board
Add a "Topics" tab to the Messages page so board members can start a
topic-scoped group conversation with management and their own-association
board members. Topic = predefined category + free-text subject; recipients
are multi-selected; replies are visible to all participants.

- New public tables message_threads / message_thread_participants /
  thread_messages (migration board_topic_message_threads), added to the
  realtime publication; RLS scopes reads/writes to thread participants via
  is_thread_participant().
- create_topic_thread() RPC (SECURITY DEFINER) enforces recipient
  eligibility server-side: management (admin/manager) or a board member of
  the caller's own association; rejects anyone else.
- Frontend: messageTopics constant, useMessageThreads/useThreadMessages
  hooks (realtime), TopicThreadList/TopicThreadView/NewTopicThreadDialog,
  and a tabbed MessagesPage. Recipients notified via insert_notification
  with a /dashboard/messages?thread= deep link. Existing 1:1 DMs unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 14:58:50 -04:00

32 lines
1.2 KiB
TypeScript

// Predefined topic categories for board ↔ management/board topic threads.
// Kept as a constant for now; can be moved to a DB table later if associations
// need to customize the list. Order here is the order shown in the dropdown.
export const MESSAGE_TOPICS = [
"Maintenance",
"Landscaping",
"Finances / Budget",
"Violations",
"Architectural (ARC)",
"Meetings",
"Vendors",
"Other",
] as const;
export type MessageTopic = (typeof MESSAGE_TOPICS)[number];
// Tailwind classes for the topic badge so each category is visually distinct.
const TOPIC_BADGE_CLASS: Record<string, string> = {
Maintenance: "bg-amber-100 text-amber-800 border-amber-200",
Landscaping: "bg-green-100 text-green-800 border-green-200",
"Finances / Budget": "bg-blue-100 text-blue-800 border-blue-200",
Violations: "bg-red-100 text-red-800 border-red-200",
"Architectural (ARC)": "bg-purple-100 text-purple-800 border-purple-200",
Meetings: "bg-indigo-100 text-indigo-800 border-indigo-200",
Vendors: "bg-teal-100 text-teal-800 border-teal-200",
Other: "bg-gray-100 text-gray-700 border-gray-200",
};
export function topicBadgeClass(topic: string): string {
return TOPIC_BADGE_CLASS[topic] ?? TOPIC_BADGE_CLASS.Other;
}