shoc-frontend-new/src/components/common/comment-timeline.tsx
Arthur Bassi f35fce9bd5
feat(work-orders): comment @mentions autocomplete (SH-217) (#91)
* docs(work-orders): add pending BE contract checklist for design parity gaps

* feat(work-orders): add mentions in work-order comments composer

* docs(work-orders): align pr description with jira and qa residuals

* refactor(workorders): split work order view page into view components

* fix(work-orders): export comment assignment vendor input types for view hook

* fix(work-orders): drop preferredContact from vendor update payload

Align with WorkOrderVendorUpdatePayload on current dev so the mentions branch typechecks.

* fix(work-orders): remove Preferred Contact from WO vendor editor (SH-180)

EOF

* fix(work-orders): harden comment mentions and clear draft on success

* fix(work-orders): harden mention highlight boundary and submit catch [SH-217]

* fix(work-orders): keep mention cursor sync on current value [SH-217]

* fix(work-orders): keep mention menu open after typing @

Pass live text into syncCursor instead of a render-time valueRef.
Add a composer interaction regression for @ autocomplete visibility.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Alexandre Brandizzi <alex_brandizzi@hotmail.com>
2026-08-11 14:07:02 -03:00

59 lines
1.8 KiB
TypeScript

import { useMemo } from "react";
import { Box, Stack } from "@mui/material";
import { CommentBodyWithMentions } from "@/components/common/comment-body-with-mentions";
import { Text } from "@/components/ui/text";
import type { MentionLookup } from "@/domain/work-orders/utils/comment-mentions";
import { formatDateTime } from "@/lib/time-utils";
export type CommentTimelineItem = {
id: string | number;
author: string;
createdAt?: string;
body: string;
mentions?: string[];
};
type CommentTimelineProps = {
items: CommentTimelineItem[];
emptyMessage?: string;
maxHeightClass?: string;
mentionUsers?: MentionLookup[];
};
export function CommentTimeline({
items,
emptyMessage = "No comments yet.",
maxHeightClass = "max-h-72",
mentionUsers,
}: CommentTimelineProps) {
const sorted = useMemo(
() =>
[...items].sort((a, b) => {
const aTime = a.createdAt ? new Date(a.createdAt).getTime() : 0;
const bTime = b.createdAt ? new Date(b.createdAt).getTime() : 0;
return aTime - bTime;
}),
[items],
);
if (!sorted.length) {
return <Text tone="muted">{emptyMessage}</Text>;
}
return (
<Stack spacing={2} className={`${maxHeightClass} overflow-y-auto`}>
{sorted.map((item) => (
<Box key={String(item.id)} className="rounded border border-border p-3">
<Stack direction="row" className="mb-1" sx={{ justifyContent: "space-between" }}>
<Text variant="caption" className="font-semibold">
{item.author}
</Text>
<Text variant="caption" tone="muted">
{item.createdAt ? formatDateTime(item.createdAt) : ""}
</Text>
</Stack>
<CommentBodyWithMentions text={item.body} mentions={item.mentions} users={mentionUsers} />
</Box>
))}
</Stack>
);
}