diff --git a/apps/web/components/markdown/Markdown.tsx b/apps/web/components/markdown/Markdown.tsx index 00038dad..d09f31a5 100644 --- a/apps/web/components/markdown/Markdown.tsx +++ b/apps/web/components/markdown/Markdown.tsx @@ -3,7 +3,6 @@ import ReactMarkdown, { type Components } from 'react-markdown' import rehypeRaw from 'rehype-raw' import remarkGfm from 'remark-gfm' import { cn } from '@/lib/utils' -import { MentionHoverCard } from '@/components/common/mention-hover-card' import { CodeBlock, InlineCode } from './CodeBlock' import { preprocessLinks } from './linkify' @@ -61,15 +60,10 @@ function createComponents( a: ({ href, children }) => { // Mention links: mention://member/id or mention://agent/id if (href?.startsWith('mention://')) { - const parts = href.replace('mention://', '').split('/') - const mentionType = parts[0] ?? 'member' - const mentionId = parts[1] ?? '' return ( - - - {children} - - + + {children} + ) } diff --git a/apps/web/features/issues/components/comment-input.tsx b/apps/web/features/issues/components/comment-input.tsx index 6e2b8052..6aaa2041 100644 --- a/apps/web/features/issues/components/comment-input.tsx +++ b/apps/web/features/issues/components/comment-input.tsx @@ -1,7 +1,7 @@ "use client"; import { useRef, useState } from "react"; -import { ArrowUp } from "lucide-react"; +import { ArrowUp, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { RichTextEditor, type RichTextEditorRef } from "@/components/common/rich-text-editor"; @@ -44,7 +44,7 @@ function CommentInput({ onSubmit }: CommentInputProps) { disabled={isEmpty || submitting} onClick={handleSubmit} > - + {submitting ? : } diff --git a/apps/web/features/issues/components/reply-input.tsx b/apps/web/features/issues/components/reply-input.tsx index b95662c4..d58c8443 100644 --- a/apps/web/features/issues/components/reply-input.tsx +++ b/apps/web/features/issues/components/reply-input.tsx @@ -1,7 +1,7 @@ "use client"; import { useRef, useState } from "react"; -import { ArrowUp } from "lucide-react"; +import { ArrowUp, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { RichTextEditor, type RichTextEditorRef } from "@/components/common/rich-text-editor"; import { ActorAvatar } from "@/components/common/actor-avatar"; @@ -83,7 +83,7 @@ function ReplyInput({ onClick={handleSubmit} tabIndex={isEmpty ? -1 : 0} > - + {submitting ? : } diff --git a/apps/web/features/issues/hooks/use-issue-timeline.ts b/apps/web/features/issues/hooks/use-issue-timeline.ts index 98530d9a..63555d0c 100644 --- a/apps/web/features/issues/hooks/use-issue-timeline.ts +++ b/apps/web/features/issues/hooks/use-issue-timeline.ts @@ -176,27 +176,14 @@ export function useIssueTimeline(issueId: string, userId?: string) { const submitComment = useCallback( async (content: string) => { if (!content.trim() || submitting || !userId) return; - const tempId = "temp-" + Date.now(); - const tempEntry: TimelineEntry = { - type: "comment", - id: tempId, - actor_type: "member", - actor_id: userId, - content, - parent_id: null, - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - comment_type: "comment", - }; - setTimeline((prev) => [...prev, tempEntry]); setSubmitting(true); try { const comment = await api.createComment(issueId, content); - setTimeline((prev) => - prev.map((e) => (e.id === tempId ? commentToTimelineEntry(comment) : e)), - ); + setTimeline((prev) => { + if (prev.some((e) => e.id === comment.id)) return prev; + return [...prev, commentToTimelineEntry(comment)]; + }); } catch { - setTimeline((prev) => prev.filter((e) => e.id !== tempId)); toast.error("Failed to send comment"); } finally { setSubmitting(false); @@ -208,26 +195,13 @@ export function useIssueTimeline(issueId: string, userId?: string) { const submitReply = useCallback( async (parentId: string, content: string) => { if (!content.trim() || !userId) return; - const tempId = "temp-" + Date.now(); - const tempEntry: TimelineEntry = { - type: "comment", - id: tempId, - actor_type: "member", - actor_id: userId, - content, - parent_id: parentId, - created_at: new Date().toISOString(), - updated_at: new Date().toISOString(), - comment_type: "comment", - }; - setTimeline((prev) => [...prev, tempEntry]); try { const comment = await api.createComment(issueId, content, "comment", parentId); - setTimeline((prev) => - prev.map((e) => (e.id === tempId ? commentToTimelineEntry(comment) : e)), - ); + setTimeline((prev) => { + if (prev.some((e) => e.id === comment.id)) return prev; + return [...prev, commentToTimelineEntry(comment)]; + }); } catch { - setTimeline((prev) => prev.filter((e) => e.id !== tempId)); toast.error("Failed to send reply"); } },