diff --git a/src/components/orders/quote-line-context.tsx b/src/components/orders/quote-line-context.tsx new file mode 100644 index 0000000..676ac6c --- /dev/null +++ b/src/components/orders/quote-line-context.tsx @@ -0,0 +1,118 @@ +"use client"; + +import { MessageSquare, HelpCircle } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { + AttachmentList, + type MatchedAttachment, +} from "@/components/orders/attachment-list"; + +/** + * QuoteLineContext — everything the buyer / operator needs to know + * about the quote line behind one order line. + * + * Shared by the order detail table (Task 13) and the process page + * (Task 12) so the two never drift. Before this existed, the process + * page owned the only copy and the detail page showed nothing at all. + * + * `tier` drives the framing: a "confident" pair is stated as fact, a + * "possible" pair is explicitly presented as a guess with a confirm + * button, so a buyer is never shown a note from the wrong line + * without being told it might be wrong. + */ + +export interface QuoteLineContextProps { + /** Quote line description. Rendered only when it differs from the order's. */ + quoteDescription: string; + orderDescription: string; + /** Free-text note the estimator left on the quote line. */ + notes: string; + perItemAttachments: MatchedAttachment[]; + quoteAttachments: MatchedAttachment[]; + tier: "confident" | "possible"; + /** Called when the operator confirms a "possible" pair. */ + onConfirm?: () => void; + confirming?: boolean; +} + +export function QuoteLineContext({ + quoteDescription, + orderDescription, + notes, + perItemAttachments, + quoteAttachments, + tier, + onConfirm, + confirming = false, +}: QuoteLineContextProps) { + return ( +
+ {tier === "possible" && ( +
+
+ +
+
+ Possible match — is this the right quote line? +
+

+ The wording differs enough that we're not certain. Confirm to + link them permanently. +

+
+ {onConfirm && ( + + )} +
+
+ )} + + {quoteDescription && quoteDescription !== orderDescription && ( +
+
+ Quote line says +
+
{quoteDescription}
+
+ )} + + {notes.trim() !== "" && ( +
+
+ + Buyer note +
+
+ {notes} +
+
+ )} + + {perItemAttachments.length > 0 && ( + + )} + {quoteAttachments.length > 0 && ( + + )} +
+ ); +} + +/** Shown in place of the panel when the order line has no counterpart + * on the linked quote. Previously this case rendered nothing at all, + * which was indistinguishable from "the quote line had no note." */ +export function QuoteLineNoMatch() { + return ( +
+ No matching line on the linked quote. +
+ ); +}