fix: DM message ordering, consolidate input toolbar, add rich text/WYSIWYG, file upload with drag-drop

- Fix DM backend ListMessages to use DESC + reverse (match channel handler)
- Remove spurious .reverse() from frontend message/conversation stores
- Create shared MessageInput component with Slack-style single toolbar row
- Add file upload via + button with progress bar and drag-and-drop
- Add markdown/rich text toggle with full WYSIWYG block formatting
  (lists, blockquotes, links, headings, code blocks)
- Add frontend+backend security for file uploads (extension + content-type guards)
This commit is contained in:
2026-07-06 17:33:20 +00:00
parent 9512dedec1
commit b3b5ff495d
19 changed files with 1369 additions and 301 deletions
+3 -10
View File
@@ -1,5 +1,4 @@
import { useState } from 'react';
import { api } from '../lib/api.ts';
interface Reaction {
emoji: string;
@@ -9,12 +8,11 @@ interface Reaction {
}
interface ReactionBarProps {
messageId: string;
reactions: Reaction[];
onRefresh: () => void;
onToggle: (emoji: string, isReacted: boolean) => Promise<void>;
}
export function ReactionBar({ messageId, reactions, onRefresh }: ReactionBarProps) {
export function ReactionBar({ reactions, onToggle }: ReactionBarProps) {
const [loading, setLoading] = useState(false);
const toggleReaction = async (emoji: string) => {
@@ -22,12 +20,7 @@ export function ReactionBar({ messageId, reactions, onRefresh }: ReactionBarProp
setLoading(true);
try {
const existing = reactions.find(r => r.emoji === emoji);
if (existing?.reacted) {
await api.delete(`/messages/${messageId}/reactions/${encodeURIComponent(emoji)}`);
} else {
await api.post(`/messages/${messageId}/reactions`, { emoji });
}
onRefresh();
await onToggle(emoji, !!existing?.reacted);
} catch (error) {
console.error('Failed to toggle reaction:', error);
} finally {