@burdenoff/microfe-housingvista 2026.703.8 → 2026.703.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,66 +7,67 @@ import { useEffect as o, useRef as s, useState as c } from "react";
7
7
  import { Send as l } from "lucide-react";
8
8
  import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
9
9
  import { Button as p, ResponsiveDialog as m, ResponsiveDialogContent as h, ResponsiveDialogDescription as g, ResponsiveDialogHeader as _, ResponsiveDialogTitle as v } from "@burdenoff/fe-libs/ui";
10
+ import { createPortal as y } from "react-dom";
10
11
  //#region src/housingvista/components/ContactOwnerDialog.tsx
11
- var y = ({ entityId: y, entityType: b, title: x, pagePath: S, triggerContent: C, triggerVariant: w = "outline", triggerClassName: T, heading: E = "Contact", description: D }) => {
12
- let { currentUser: O } = e(), { openConversation: k, loading: A } = n(), { sendMessage: j, loading: M } = i(), [N, P] = c(!1), [F, I] = c(), [L, R] = c(""), { data: z, loading: B } = r(F), V = s(null);
12
+ var b = ({ entityId: b, entityType: x, title: S, pagePath: C, triggerContent: w, triggerVariant: T = "outline", triggerClassName: E, heading: D = "Contact", description: O, open: k, onOpenChange: A }) => {
13
+ let { currentUser: j } = e(), { openConversation: M, loading: N } = n(), { sendMessage: P, loading: F } = i(), I = k !== void 0, [L, R] = c(!1), z = I ? k : L, B = (e) => I ? A?.(e) : R(e), [V, H] = c(), [U, W] = c(""), { data: G, loading: K } = r(V), q = s(null);
13
14
  o(() => {
14
- if (!N || F) return;
15
+ if (!z || V) return;
15
16
  let e = !1;
16
- return k({
17
- entityId: y,
18
- entityType: b,
19
- title: x,
20
- contextHref: S,
21
- pagePath: S
17
+ return M({
18
+ entityId: b,
19
+ entityType: x,
20
+ title: S,
21
+ contextHref: C,
22
+ pagePath: C
22
23
  }).then((t) => {
23
- e || I(t.id);
24
+ e || H(t.id);
24
25
  }).catch((e) => a.error("Could not open the conversation", e.message)), () => {
25
26
  e = !0;
26
27
  };
27
28
  }, [
28
- N,
29
- F,
30
- k,
31
- y,
29
+ z,
30
+ V,
31
+ M,
32
32
  b,
33
33
  x,
34
- S
34
+ S,
35
+ C
35
36
  ]), o(() => {
36
- V.current?.scrollTo({ top: V.current.scrollHeight });
37
- }, [z]);
38
- let H = async () => {
39
- let e = L.trim();
40
- if (!(!e || !F)) try {
41
- await j(F, e), R("");
37
+ q.current?.scrollTo({ top: q.current.scrollHeight });
38
+ }, [G]);
39
+ let J = async () => {
40
+ let e = U.trim();
41
+ if (!(!e || !V)) try {
42
+ await P(V, e), W("");
42
43
  } catch (e) {
43
44
  a.error("Message not sent", e.message);
44
45
  }
45
- }, U = O?.id ?? "";
46
- return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(p, {
46
+ }, Y = j?.id ?? "";
47
+ return /* @__PURE__ */ f(u, { children: [!I && /* @__PURE__ */ d(p, {
47
48
  type: "button",
48
- variant: w,
49
- className: T,
50
- onClick: () => P(!0),
51
- children: C
52
- }), /* @__PURE__ */ d(m, {
53
- open: N,
54
- onOpenChange: P,
49
+ variant: T,
50
+ className: E,
51
+ onClick: () => B(!0),
52
+ children: w
53
+ }), y(/* @__PURE__ */ d(m, {
54
+ open: z,
55
+ onOpenChange: B,
55
56
  children: /* @__PURE__ */ f(h, {
56
57
  className: "sm:max-w-lg",
57
58
  children: [
58
- /* @__PURE__ */ f(_, { children: [/* @__PURE__ */ d(v, { children: E }), /* @__PURE__ */ d(g, { children: D ?? `Start a conversation about ${x}. Messages are saved and delivered in your inbox.` })] }),
59
+ /* @__PURE__ */ f(_, { children: [/* @__PURE__ */ d(v, { children: D }), /* @__PURE__ */ d(g, { children: O ?? `Start a conversation about ${S}. Messages are saved and delivered in your inbox.` })] }),
59
60
  /* @__PURE__ */ d("div", {
60
- ref: V,
61
+ ref: q,
61
62
  className: "max-h-72 min-h-40 space-y-2 overflow-y-auto rounded-md border border-border-subtle bg-bg-sunken p-3",
62
- children: A || B ? /* @__PURE__ */ d("p", {
63
+ children: N || K ? /* @__PURE__ */ d("p", {
63
64
  className: "py-8 text-center text-sm text-text-secondary",
64
65
  children: "Loading conversation…"
65
- }) : z.length === 0 ? /* @__PURE__ */ d("p", {
66
+ }) : G.length === 0 ? /* @__PURE__ */ d("p", {
66
67
  className: "py-8 text-center text-sm text-text-secondary",
67
68
  children: "No messages yet. Say hello to get the conversation started."
68
- }) : z.map((e) => {
69
- let n = e.authorId === U;
69
+ }) : G.map((e) => {
70
+ let n = e.authorId === Y;
70
71
  return /* @__PURE__ */ d("div", {
71
72
  className: t("flex", n ? "justify-end" : "justify-start"),
72
73
  children: /* @__PURE__ */ d("div", {
@@ -79,18 +80,18 @@ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, triggerContent: C,
79
80
  /* @__PURE__ */ f("div", {
80
81
  className: "mt-3 flex items-end gap-2",
81
82
  children: [/* @__PURE__ */ d("textarea", {
82
- value: L,
83
- onChange: (e) => R(e.target.value),
83
+ value: U,
84
+ onChange: (e) => W(e.target.value),
84
85
  onKeyDown: (e) => {
85
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), H());
86
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), J());
86
87
  },
87
88
  rows: 2,
88
89
  placeholder: "Write a message…",
89
90
  className: "min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
90
91
  }), /* @__PURE__ */ f(p, {
91
92
  type: "button",
92
- onClick: H,
93
- disabled: !L.trim() || !F || M,
93
+ onClick: J,
94
+ disabled: !U.trim() || !V || F,
94
95
  children: [/* @__PURE__ */ d(l, { className: "h-4 w-4" }), /* @__PURE__ */ d("span", {
95
96
  className: "ml-1",
96
97
  children: "Send"
@@ -99,9 +100,9 @@ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, triggerContent: C,
99
100
  })
100
101
  ]
101
102
  })
102
- })] });
103
+ }), document.body)] });
103
104
  };
104
105
  //#endregion
105
- export { y as ContactOwnerDialog };
106
+ export { b as ContactOwnerDialog };
106
107
 
107
108
  //# sourceMappingURL=ContactOwnerDialog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContactOwnerDialog.js","names":[],"sources":["../../../src/housingvista/components/ContactOwnerDialog.tsx"],"sourcesContent":["/**\n * Real messaging surface backed by wspace-conversations-svc. Any \"Contact /\n * Message / Apply / Contact Owner\" CTA renders this: it resolves (get-or-create)\n * the entity's conversation, shows the persisted thread, and posts messages via\n * `sendMessage`. No stub, no dead-end — everything is persisted server-side.\n * @module housingvista\n */\n\nimport { useEffect, useRef, useState, type FC, type ReactNode } from 'react';\nimport { Send } from 'lucide-react';\nimport {\n Button,\n type ButtonProps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { useContactConversation, useConversationMessages, useSendMessage } from '../hooks';\nimport { useHousingVista } from '../context/HousingVistaContext';\nimport { notify } from '../lib/toast';\nimport { cn } from '../utils/helpers';\n\ninterface ContactOwnerDialogProps {\n /** Stable id of the thing being discussed (property/service/listing id). */\n entityId: string;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string;\n /** Title used when the conversation is first created. */\n title: string;\n /** Router path back into this surface (deep link). */\n pagePath: string;\n /** Inner content of the trigger button (icon + label). */\n triggerContent: ReactNode;\n /** Trigger button variant (defaults to `outline`). */\n triggerVariant?: ButtonProps['variant'];\n /** Extra classes for the trigger button. */\n triggerClassName?: string;\n /** Dialog heading, defaults to \"Contact\". */\n heading?: string;\n description?: string;\n}\n\nexport const ContactOwnerDialog: FC<ContactOwnerDialogProps> = ({\n entityId,\n entityType,\n title,\n pagePath,\n triggerContent,\n triggerVariant = 'outline',\n triggerClassName,\n heading = 'Contact',\n description,\n}) => {\n const { currentUser } = useHousingVista();\n const { openConversation, loading: opening } = useContactConversation();\n const { sendMessage, loading: sending } = useSendMessage();\n const [open, setOpen] = useState(false);\n const [conversationId, setConversationId] = useState<string | undefined>();\n const [draft, setDraft] = useState('');\n const { data: messages, loading: loadingMessages } = useConversationMessages(conversationId);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Resolve the conversation the first time the dialog opens.\n useEffect(() => {\n if (!open || conversationId) return;\n let cancelled = false;\n openConversation({\n entityId,\n entityType,\n title,\n contextHref: pagePath,\n pagePath,\n })\n .then((res) => {\n if (!cancelled) setConversationId(res.id);\n })\n .catch((err: Error) => notify.error('Could not open the conversation', err.message));\n return () => {\n cancelled = true;\n };\n }, [open, conversationId, openConversation, entityId, entityType, title, pagePath]);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages]);\n\n const handleSend = async () => {\n const text = draft.trim();\n if (!text || !conversationId) return;\n try {\n await sendMessage(conversationId, text);\n setDraft('');\n } catch (err) {\n notify.error('Message not sent', (err as Error).message);\n }\n };\n\n const currentUserId = currentUser?.id ?? '';\n\n // Render the trigger as a real Button with a direct onClick — the exact\n // controlled-open pattern the in-page dialogs (e.g. Make Offer) use. Passing a\n // pre-built element through ResponsiveDialogTrigger asChild / cloneElement /\n // a display:contents wrapper all failed to forward the click in production.\n return (\n <>\n <Button\n type=\"button\"\n variant={triggerVariant}\n className={triggerClassName}\n onClick={() => setOpen(true)}\n >\n {triggerContent}\n </Button>\n <ResponsiveDialog open={open} onOpenChange={setOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{heading}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {description ?? `Start a conversation about ${title}. Messages are saved and delivered in your inbox.`}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div\n ref={scrollRef}\n className=\"max-h-72 min-h-40 space-y-2 overflow-y-auto rounded-md border border-border-subtle bg-bg-sunken p-3\"\n >\n {opening || loadingMessages ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">Loading conversation…</p>\n ) : messages.length === 0 ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n No messages yet. Say hello to get the conversation started.\n </p>\n ) : (\n messages.map((message) => {\n const mine = message.authorId === currentUserId;\n return (\n <div key={message.id} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>\n <div\n className={cn(\n 'max-w-[80%] rounded-lg px-3 py-2 text-sm',\n mine\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary border border-border-subtle'\n )}\n >\n {message.text}\n </div>\n </div>\n );\n })\n )}\n </div>\n\n <div className=\"mt-3 flex items-end gap-2\">\n <textarea\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n void handleSend();\n }\n }}\n rows={2}\n placeholder=\"Write a message…\"\n className=\"min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <Button type=\"button\" onClick={handleSend} disabled={!draft.trim() || !conversationId || sending}>\n <Send className=\"h-4 w-4\" />\n <span className=\"ml-1\">Send</span>\n </Button>\n </div>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ContactOwnerDialog.js","names":[],"sources":["../../../src/housingvista/components/ContactOwnerDialog.tsx"],"sourcesContent":["/**\n * Real messaging surface backed by wspace-conversations-svc. Any \"Contact /\n * Message / Apply / Contact Owner\" CTA renders this: it resolves (get-or-create)\n * the entity's conversation, shows the persisted thread, and posts messages via\n * `sendMessage`. No stub, no dead-end — everything is persisted server-side.\n * @module housingvista\n */\n\nimport { useEffect, useRef, useState, type FC, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Send } from 'lucide-react';\nimport {\n Button,\n type ButtonProps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { useContactConversation, useConversationMessages, useSendMessage } from '../hooks';\nimport { useHousingVista } from '../context/HousingVistaContext';\nimport { notify } from '../lib/toast';\nimport { cn } from '../utils/helpers';\n\ninterface ContactOwnerDialogProps {\n /** Stable id of the thing being discussed (property/service/listing id). */\n entityId: string;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string;\n /** Title used when the conversation is first created. */\n title: string;\n /** Router path back into this surface (deep link). */\n pagePath: string;\n /** Inner content of the trigger button (icon + label). Omit in controlled mode. */\n triggerContent?: ReactNode;\n /** Trigger button variant (defaults to `outline`). */\n triggerVariant?: ButtonProps['variant'];\n /** Extra classes for the trigger button. */\n triggerClassName?: string;\n /** Dialog heading, defaults to \"Contact\". */\n heading?: string;\n description?: string;\n /**\n * Controlled-open mode. When `open`/`onOpenChange` are provided the parent\n * owns the state and the internal trigger button is not rendered — the\n * caller renders its own trigger. This is the pattern the in-page dialogs\n * (e.g. Make Offer) use, and it renders the dialog reliably at page root.\n */\n open?: boolean;\n onOpenChange?: (next: boolean) => void;\n}\n\nexport const ContactOwnerDialog: FC<ContactOwnerDialogProps> = ({\n entityId,\n entityType,\n title,\n pagePath,\n triggerContent,\n triggerVariant = 'outline',\n triggerClassName,\n heading = 'Contact',\n description,\n open: openProp,\n onOpenChange,\n}) => {\n const { currentUser } = useHousingVista();\n const { openConversation, loading: opening } = useContactConversation();\n const { sendMessage, loading: sending } = useSendMessage();\n const controlled = openProp !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const open = controlled ? openProp : internalOpen;\n const setOpen = (next: boolean) => (controlled ? onOpenChange?.(next) : setInternalOpen(next));\n const [conversationId, setConversationId] = useState<string | undefined>();\n const [draft, setDraft] = useState('');\n const { data: messages, loading: loadingMessages } = useConversationMessages(conversationId);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Resolve the conversation the first time the dialog opens.\n useEffect(() => {\n if (!open || conversationId) return;\n let cancelled = false;\n openConversation({\n entityId,\n entityType,\n title,\n contextHref: pagePath,\n pagePath,\n })\n .then((res) => {\n if (!cancelled) setConversationId(res.id);\n })\n .catch((err: Error) => notify.error('Could not open the conversation', err.message));\n return () => {\n cancelled = true;\n };\n }, [open, conversationId, openConversation, entityId, entityType, title, pagePath]);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages]);\n\n const handleSend = async () => {\n const text = draft.trim();\n if (!text || !conversationId) return;\n try {\n await sendMessage(conversationId, text);\n setDraft('');\n } catch (err) {\n notify.error('Message not sent', (err as Error).message);\n }\n };\n\n const currentUserId = currentUser?.id ?? '';\n\n // Render the trigger as a real Button with a direct onClick — the exact\n // controlled-open pattern the in-page dialogs (e.g. Make Offer) use. Passing a\n // pre-built element through ResponsiveDialogTrigger asChild / cloneElement /\n // a display:contents wrapper all failed to forward the click in production.\n return (\n <>\n {!controlled && (\n <Button type=\"button\" variant={triggerVariant} className={triggerClassName} onClick={() => setOpen(true)}>\n {triggerContent}\n </Button>\n )}\n {createPortal(\n <ResponsiveDialog open={open} onOpenChange={setOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{heading}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {description ?? `Start a conversation about ${title}. Messages are saved and delivered in your inbox.`}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div\n ref={scrollRef}\n className=\"max-h-72 min-h-40 space-y-2 overflow-y-auto rounded-md border border-border-subtle bg-bg-sunken p-3\"\n >\n {opening || loadingMessages ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">Loading conversation…</p>\n ) : messages.length === 0 ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n No messages yet. Say hello to get the conversation started.\n </p>\n ) : (\n messages.map((message) => {\n const mine = message.authorId === currentUserId;\n return (\n <div key={message.id} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>\n <div\n className={cn(\n 'max-w-[80%] rounded-lg px-3 py-2 text-sm',\n mine\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary border border-border-subtle'\n )}\n >\n {message.text}\n </div>\n </div>\n );\n })\n )}\n </div>\n\n <div className=\"mt-3 flex items-end gap-2\">\n <textarea\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n void handleSend();\n }\n }}\n rows={2}\n placeholder=\"Write a message…\"\n className=\"min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <Button type=\"button\" onClick={handleSend} disabled={!draft.trim() || !conversationId || sending}>\n <Send className=\"h-4 w-4\" />\n <span className=\"ml-1\">Send</span>\n </Button>\n </div>\n </ResponsiveDialogContent>\n </ResponsiveDialog>,\n document.body\n )}\n </>\n );\n};\n"],"mappings":"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"}