@burdenoff/microfe-housingvista 2026.802.1 → 2026.830.1

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.
Files changed (34) hide show
  1. package/dist/housingvista/hooks/index.d.ts +2 -2
  2. package/dist/housingvista/hooks/index.d.ts.map +1 -1
  3. package/dist/housingvista/hooks/index.js.map +1 -1
  4. package/dist/housingvista/hooks/messages.d.ts +18 -11
  5. package/dist/housingvista/hooks/messages.d.ts.map +1 -1
  6. package/dist/housingvista/hooks/messages.js +33 -13
  7. package/dist/housingvista/hooks/messages.js.map +1 -1
  8. package/dist/housingvista/hooks/platform.d.ts +54 -2
  9. package/dist/housingvista/hooks/platform.d.ts.map +1 -1
  10. package/dist/housingvista/hooks/platform.js +63 -18
  11. package/dist/housingvista/hooks/platform.js.map +1 -1
  12. package/dist/housingvista/pages/HomePage.js +140 -142
  13. package/dist/housingvista/pages/HomePage.js.map +1 -1
  14. package/dist/housingvista/pages/chat/ChatPage.d.ts +4 -2
  15. package/dist/housingvista/pages/chat/ChatPage.d.ts.map +1 -1
  16. package/dist/housingvista/pages/chat/ChatPage.js +305 -151
  17. package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
  18. package/dist/housingvista/pages/properties/PropertiesPage.d.ts.map +1 -1
  19. package/dist/housingvista/pages/properties/PropertiesPage.js +427 -312
  20. package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
  21. package/dist/housingvista/pages/properties/PropertyDetailPage.d.ts.map +1 -1
  22. package/dist/housingvista/pages/properties/PropertyDetailPage.js +491 -374
  23. package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
  24. package/dist/housingvista/pages/transactions/TransactionsPage.d.ts.map +1 -1
  25. package/dist/housingvista/pages/transactions/TransactionsPage.js +153 -155
  26. package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
  27. package/dist/shared/hooks/index.d.ts +2 -0
  28. package/dist/shared/hooks/index.d.ts.map +1 -0
  29. package/dist/shared/hooks/index.js +1 -0
  30. package/dist/shared/hooks/useTr.d.ts +17 -0
  31. package/dist/shared/hooks/useTr.d.ts.map +1 -0
  32. package/dist/shared/hooks/useTr.js +14 -0
  33. package/dist/shared/hooks/useTr.js.map +1 -0
  34. package/package.json +2 -2
@@ -1,251 +1,405 @@
1
1
  import { useHousingVista as e } from "../../context/HousingVistaContext.js";
2
- import { cn as t, getRelativeTime as n } from "../../utils/helpers.js";
3
- import { PageLayout as r } from "../../components/PageLayout.js";
4
- import { StatCard as i } from "../../components/StatCard.js";
5
- import { EmptyState as a } from "../../components/EmptyState.js";
6
- import { useConversationMessages as o, useSendMessage as s } from "../../hooks/platform.js";
7
- import { useTrackPageView as c } from "../../hooks/useHousingVistaAnalytics.js";
8
- import "../../hooks/index.js";
9
- import { notify as l } from "../../lib/toast.js";
2
+ import { cn as t, formatCompactCurrency as n, getRelativeTime as r } from "../../utils/helpers.js";
3
+ import { PageLayout as i } from "../../components/PageLayout.js";
4
+ import { StatCard as a } from "../../components/StatCard.js";
5
+ import { EmptyState as o } from "../../components/EmptyState.js";
6
+ import { useConversationMessages as ee, useFileUpload as te, useSendContextMessage as s, useSendMessage as c } from "../../hooks/platform.js";
7
+ import { useTrackPageView as l } from "../../hooks/useHousingVistaAnalytics.js";
8
+ import { useProperty as u } from "../../hooks/index.js";
9
+ import { notify as d } from "../../lib/toast.js";
10
10
  import "../../components/index.js";
11
- import { useHousingVistaConversations as u } from "../../hooks/messages.js";
12
- import { useEffect as d, useMemo as f, useRef as p, useState as m } from "react";
13
- import { ArrowLeft as h, MapPin as g, MessageSquare as _, Search as v, Send as y } from "lucide-react";
14
- import { useNavigate as b } from "react-router";
15
- import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
16
- import { Button as w, EmphasisPanel as T, GlassCard as E } from "@burdenoff/fe-libs/ui";
11
+ import { useHousingVistaConversations as ne } from "../../hooks/messages.js";
12
+ import { useEffect as f, useMemo as p, useRef as m, useState as h } from "react";
13
+ import { ArrowLeft as g, FileText as _, Loader2 as re, MapPin as ie, MessageSquare as v, Paperclip as ae, Search as oe, Send as y, X as se } from "lucide-react";
14
+ import { useNavigate as ce } from "react-router";
15
+ import { Fragment as b, jsx as x, jsxs as S } from "react/jsx-runtime";
16
+ import { Button as C, EmphasisPanel as le, GlassCard as ue } from "@burdenoff/fe-libs/ui";
17
17
  //#region src/housingvista/pages/chat/ChatPage.tsx
18
- var D = [
18
+ var w = [
19
19
  "bg-status-info-bg-subtle text-status-info-text",
20
20
  "bg-status-success-bg-subtle text-status-success-text",
21
21
  "bg-status-warning-bg-subtle text-status-warning-text",
22
22
  "bg-action-primary-bg/15 text-primary"
23
23
  ];
24
- function O(e) {
24
+ function T(e) {
25
25
  let t = e.trim().split(/\s+/).filter(Boolean);
26
26
  return t.length === 0 ? "?" : t.length === 1 ? t[0].slice(0, 2).toUpperCase() : (t[0][0] + t[t.length - 1][0]).toUpperCase();
27
27
  }
28
- function k(e) {
28
+ function E(e) {
29
29
  let t = 0;
30
30
  for (let n = 0; n < e.length; n += 1) t += e.charCodeAt(n);
31
- return D[t % D.length];
31
+ return w[t % w.length];
32
32
  }
33
- function A(e) {
33
+ function de(e) {
34
34
  let t = new Date(e);
35
35
  return Number.isNaN(t.getTime()) ? "" : t.toLocaleTimeString("en-US", {
36
36
  hour: "numeric",
37
37
  minute: "2-digit"
38
38
  });
39
39
  }
40
- function j({ title: e, id: n, size: r = "md" }) {
41
- return /* @__PURE__ */ S("span", {
42
- className: t("inline-flex shrink-0 items-center justify-center rounded-full font-semibold", r === "md" ? "h-10 w-10 text-sm" : "h-9 w-9 text-xs", k(n)),
40
+ var D = {
41
+ "housingvista-property": "Property",
42
+ "housingvista-marketplace-service": "Marketplace service",
43
+ "housingvista-legal-service": "Legal service",
44
+ "housingvista-home-loan": "Home loan"
45
+ };
46
+ function O(e) {
47
+ if (!e) return null;
48
+ let t = D[e];
49
+ if (t) return t;
50
+ let n = e.replace(/^housingvista-/, "").replace(/[-_]/g, " ").trim();
51
+ return n ? n.charAt(0).toUpperCase() + n.slice(1) : null;
52
+ }
53
+ function k(e) {
54
+ return !Number.isFinite(e) || e <= 0 ? "" : e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${Math.round(e / 1024)} KB` : `${(e / (1024 * 1024)).toFixed(1)} MB`;
55
+ }
56
+ function A(e) {
57
+ return e && /^(https?:|data:image\/|\/)/.test(e) ? e : null;
58
+ }
59
+ function j({ title: e, id: n, size: r = "md", imageUrl: i }) {
60
+ let a = r === "md" ? "h-10 w-10 text-sm" : "h-9 w-9 text-xs", o = A(i);
61
+ return o ? /* @__PURE__ */ x("img", {
62
+ src: o,
63
+ alt: "",
43
64
  "aria-hidden": !0,
44
- children: O(e)
65
+ className: t("shrink-0 rounded-full object-cover", a)
66
+ }) : /* @__PURE__ */ x("span", {
67
+ className: t("inline-flex shrink-0 items-center justify-center rounded-full font-semibold", a, E(n)),
68
+ "aria-hidden": !0,
69
+ children: T(e)
70
+ });
71
+ }
72
+ function fe({ attachments: e, mine: n }) {
73
+ return e.length === 0 ? null : /* @__PURE__ */ x("ul", {
74
+ className: t("mt-1.5 space-y-1", n ? "flex flex-col items-end" : ""),
75
+ children: e.map((e) => {
76
+ let t = k(e.fileSize), n = /* @__PURE__ */ S(b, { children: [
77
+ /* @__PURE__ */ x(_, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
78
+ /* @__PURE__ */ x("span", {
79
+ className: "truncate",
80
+ children: e.fileName
81
+ }),
82
+ t && /* @__PURE__ */ x("span", {
83
+ className: "shrink-0 text-xs text-text-secondary",
84
+ children: t
85
+ })
86
+ ] });
87
+ return /* @__PURE__ */ x("li", {
88
+ className: "max-w-full",
89
+ children: e.downloadUrl ? /* @__PURE__ */ x("a", {
90
+ href: e.downloadUrl,
91
+ target: "_blank",
92
+ rel: "noopener noreferrer",
93
+ className: "flex items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-2.5 py-1.5 text-sm text-text-primary hover:underline",
94
+ children: n
95
+ }) : /* @__PURE__ */ x("span", {
96
+ className: "flex items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-2.5 py-1.5 text-sm text-text-secondary",
97
+ title: "This attachment has no download link",
98
+ children: n
99
+ })
100
+ }, e.id);
101
+ })
45
102
  });
46
103
  }
47
104
  function M() {
48
- c("housingvista.chat.viewed");
49
- let D = b(), { currentUser: O } = e(), k = O?.id ?? "", { data: M, loading: N, refetch: P } = u(), { sendMessage: F, loading: I } = s(), [L, R] = m(), [z, B] = m(""), [V, H] = m(""), U = p(null);
50
- d(() => {
51
- !L && M.length > 0 && typeof window < "u" && window.innerWidth >= 1024 && R(M[0].id);
52
- }, [M, L]);
53
- let W = f(() => M.find((e) => e.id === L), [M, L]), { data: G, loading: K } = o(L);
54
- d(() => {
55
- U.current?.scrollTo({ top: U.current.scrollHeight });
56
- }, [G, L]);
57
- let q = f(() => {
58
- let e = z.trim().toLowerCase();
59
- return e ? M.filter((t) => t.title.toLowerCase().includes(e) || t.lastMessageText.toLowerCase().includes(e)) : M;
60
- }, [M, z]), J = M.filter((e) => e.unreadCount > 0).length, Y = async () => {
105
+ l("housingvista.chat.viewed");
106
+ let w = ce(), { currentUser: T } = e(), E = T?.id ?? "", { data: D, loading: A, refetch: M } = ne(), { sendMessage: N, loading: P } = c(), { sendContextMessage: F, loading: I } = s(), { uploadFile: L } = te(), [R, z] = h(), [B, pe] = h(""), [V, H] = h(""), [U, W] = h([]), [G, K] = h(!1), q = m(null), J = m(null);
107
+ f(() => {
108
+ !R && D.length > 0 && typeof window < "u" && window.innerWidth >= 1024 && z(D[0].id);
109
+ }, [D, R]);
110
+ let Y = p(() => D.find((e) => e.id === R), [D, R]), { data: X, loading: me } = ee(R), { data: Z } = u(Y?.entityType === "housingvista-property" ? Y.entityId ?? void 0 : void 0);
111
+ f(() => {
112
+ J.current?.scrollTo({ top: J.current.scrollHeight });
113
+ }, [X, R]);
114
+ let Q = p(() => {
115
+ let e = B.trim().toLowerCase();
116
+ return e ? D.filter((t) => t.title.toLowerCase().includes(e) || t.lastMessageText.toLowerCase().includes(e)) : D;
117
+ }, [D, B]), he = D.filter((e) => e.unreadCount > 0).length, ge = !!Y?.sourceContext, _e = P || I || G, ve = async (e) => {
118
+ if (!(!e || e.length === 0)) {
119
+ K(!0);
120
+ try {
121
+ let t = [];
122
+ for (let n of Array.from(e)) t.push(await L(n));
123
+ W((e) => [...e, ...t]);
124
+ } catch (e) {
125
+ d.error("Upload failed", e.message);
126
+ } finally {
127
+ K(!1), q.current && (q.current.value = "");
128
+ }
129
+ }
130
+ }, $ = async () => {
61
131
  let e = V.trim();
62
- if (!(!e || !L)) try {
63
- await F(L, e), H(""), P();
132
+ if (R && !(!e && U.length === 0)) try {
133
+ if (U.length > 0 && Y?.sourceContext) await F({
134
+ sourceContext: Y.sourceContext,
135
+ text: e,
136
+ attachments: U
137
+ });
138
+ else {
139
+ if (!e) return;
140
+ await N(R, e);
141
+ }
142
+ H(""), W([]), M();
64
143
  } catch (e) {
65
- l.error("Message not sent", e.message);
144
+ d.error("Message not sent", e.message);
66
145
  }
67
- }, X = !N && M.length === 0;
68
- return /* @__PURE__ */ C(r, {
146
+ }, ye = !A && D.length === 0;
147
+ return /* @__PURE__ */ S(i, {
69
148
  title: "Messages",
70
149
  description: "Your conversations with property owners, agents, and service providers",
71
150
  purpose: "Every thread you start from a property, listing, or service lands here — read the full history, pick up where you left off, and reply. Messages are delivered to the other party's inbox in real time.",
72
- children: [/* @__PURE__ */ S(T, {
151
+ children: [/* @__PURE__ */ x(le, {
73
152
  className: "p-4",
74
- children: /* @__PURE__ */ C("div", {
153
+ children: /* @__PURE__ */ S("div", {
75
154
  className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
76
155
  children: [
77
- /* @__PURE__ */ S(i, {
156
+ /* @__PURE__ */ x(a, {
78
157
  label: "Conversations",
79
- value: M.length,
80
- icon: /* @__PURE__ */ S(_, { className: "h-4 w-4" })
158
+ value: D.length,
159
+ icon: /* @__PURE__ */ x(v, { className: "h-4 w-4" })
81
160
  }),
82
- /* @__PURE__ */ S(i, {
161
+ /* @__PURE__ */ x(a, {
83
162
  label: "Unread threads",
84
- value: J,
85
- icon: /* @__PURE__ */ S(_, { className: "h-4 w-4" })
163
+ value: he,
164
+ icon: /* @__PURE__ */ x(v, { className: "h-4 w-4" })
86
165
  }),
87
- /* @__PURE__ */ S(i, {
166
+ /* @__PURE__ */ x(a, {
88
167
  label: "With updates today",
89
- value: M.filter((e) => e.lastMessageAt && n(e.lastMessageAt) === "Today").length,
90
- icon: /* @__PURE__ */ S(y, { className: "h-4 w-4" })
168
+ value: D.filter((e) => e.lastMessageAt && r(e.lastMessageAt) === "Today").length,
169
+ icon: /* @__PURE__ */ x(y, { className: "h-4 w-4" })
91
170
  })
92
171
  ]
93
172
  })
94
- }), X ? /* @__PURE__ */ S(a, {
173
+ }), ye ? /* @__PURE__ */ x(o, {
95
174
  illustration: "empty-generic",
96
- icon: /* @__PURE__ */ S(_, { className: "h-12 w-12" }),
175
+ icon: /* @__PURE__ */ x(v, { className: "h-12 w-12" }),
97
176
  title: "No messages yet",
98
177
  description: "Start a conversation from any property or service — reach out to an owner or provider and your thread will show up here.",
99
- action: /* @__PURE__ */ S(w, {
100
- onClick: () => D("../properties"),
178
+ action: /* @__PURE__ */ x(C, {
179
+ onClick: () => w("../properties"),
101
180
  children: "Browse properties"
102
181
  })
103
- }) : /* @__PURE__ */ S(E, {
182
+ }) : /* @__PURE__ */ x(ue, {
104
183
  treatment: "plain",
105
184
  className: "overflow-hidden p-0",
106
- children: /* @__PURE__ */ C("div", {
185
+ children: /* @__PURE__ */ S("div", {
107
186
  className: "grid h-[68vh] min-h-[26rem] grid-cols-1 lg:grid-cols-[20rem_1fr]",
108
- children: [/* @__PURE__ */ C("aside", {
109
- className: t("flex flex-col border-border-subtle lg:border-r", L ? "hidden lg:flex" : "flex"),
110
- children: [/* @__PURE__ */ S("div", {
187
+ children: [/* @__PURE__ */ S("aside", {
188
+ className: t("flex flex-col border-border-subtle lg:border-r", R ? "hidden lg:flex" : "flex"),
189
+ children: [/* @__PURE__ */ x("div", {
111
190
  className: "border-b border-border-subtle p-3",
112
- children: /* @__PURE__ */ C("div", {
191
+ children: /* @__PURE__ */ S("div", {
113
192
  className: "relative",
114
- children: [/* @__PURE__ */ S(v, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ S("input", {
193
+ children: [/* @__PURE__ */ x(oe, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ x("input", {
115
194
  type: "search",
116
- value: z,
117
- onChange: (e) => B(e.target.value),
195
+ value: B,
196
+ onChange: (e) => pe(e.target.value),
118
197
  placeholder: "Search conversations",
119
198
  "aria-label": "Search conversations",
120
199
  className: "h-10 w-full rounded-md border border-border-subtle bg-bg-surface pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
121
200
  })]
122
201
  })
123
- }), /* @__PURE__ */ S("div", {
202
+ }), /* @__PURE__ */ x("div", {
124
203
  className: "min-h-0 flex-1 overflow-y-auto",
125
- children: N && M.length === 0 ? /* @__PURE__ */ S("p", {
204
+ children: A && D.length === 0 ? /* @__PURE__ */ x("p", {
126
205
  className: "p-6 text-center text-sm text-text-secondary",
127
206
  children: "Loading conversations…"
128
- }) : q.length === 0 ? /* @__PURE__ */ S("p", {
207
+ }) : Q.length === 0 ? /* @__PURE__ */ x("p", {
129
208
  className: "p-6 text-center text-sm text-text-secondary",
130
209
  children: "No conversations match your search."
131
- }) : /* @__PURE__ */ S("ul", { children: q.map((e) => /* @__PURE__ */ S("li", { children: /* @__PURE__ */ C("button", {
210
+ }) : /* @__PURE__ */ x("ul", { children: Q.map((e) => /* @__PURE__ */ x("li", { children: /* @__PURE__ */ S("button", {
132
211
  type: "button",
133
212
  onClick: () => {
134
- R(e.id), H("");
213
+ z(e.id), H(""), W([]);
135
214
  },
136
- className: t("flex w-full items-start gap-3 border-b border-border-subtle px-3 py-3 text-left transition-colors", e.id === L ? "bg-action-primary-bg/10" : "hover:bg-bg-sunken"),
137
- children: [/* @__PURE__ */ S(j, {
215
+ className: t("flex w-full items-start gap-3 border-b border-border-subtle px-3 py-3 text-left transition-colors", e.id === R ? "bg-action-primary-bg/10" : "hover:bg-bg-sunken"),
216
+ children: [/* @__PURE__ */ x(j, {
138
217
  title: e.title,
139
- id: e.id
140
- }), /* @__PURE__ */ C("div", {
218
+ id: e.id,
219
+ imageUrl: e.avatar
220
+ }), /* @__PURE__ */ S("div", {
141
221
  className: "min-w-0 flex-1",
142
- children: [/* @__PURE__ */ C("div", {
143
- className: "flex items-center justify-between gap-2",
144
- children: [/* @__PURE__ */ S("span", {
145
- className: "truncate text-sm font-semibold text-text-primary",
146
- children: e.title
147
- }), e.lastMessageAt && /* @__PURE__ */ S("span", {
148
- className: "shrink-0 text-xs text-text-secondary",
149
- children: n(e.lastMessageAt)
150
- })]
151
- }), /* @__PURE__ */ C("div", {
152
- className: "mt-0.5 flex items-center gap-2",
153
- children: [/* @__PURE__ */ S("span", {
154
- className: "min-w-0 flex-1 truncate text-xs text-text-secondary",
155
- children: e.lastMessageText || "No messages yet"
156
- }), e.unreadCount > 0 && /* @__PURE__ */ S("span", {
157
- className: "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-action-primary-bg px-1.5 text-[0.65rem] font-semibold text-action-primary-text",
158
- children: e.unreadCount
159
- })]
160
- })]
222
+ children: [
223
+ /* @__PURE__ */ S("div", {
224
+ className: "flex items-center justify-between gap-2",
225
+ children: [/* @__PURE__ */ x("span", {
226
+ className: "truncate text-sm font-semibold text-text-primary",
227
+ children: e.title
228
+ }), e.lastMessageAt && /* @__PURE__ */ x("span", {
229
+ className: "shrink-0 text-xs text-text-secondary",
230
+ children: r(e.lastMessageAt)
231
+ })]
232
+ }),
233
+ O(e.entityType) && /* @__PURE__ */ x("span", {
234
+ className: "mt-0.5 block truncate text-xs font-medium text-text-secondary",
235
+ children: O(e.entityType)
236
+ }),
237
+ /* @__PURE__ */ S("div", {
238
+ className: "mt-0.5 flex items-center gap-2",
239
+ children: [/* @__PURE__ */ x("span", {
240
+ className: "min-w-0 flex-1 truncate text-xs text-text-secondary",
241
+ children: e.lastMessageText || (e.lastMessageIsFile ? "Attachment" : "No messages yet")
242
+ }), e.unreadCount > 0 && /* @__PURE__ */ x("span", {
243
+ className: "inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-action-primary-bg px-1.5 text-[0.65rem] font-semibold text-action-primary-text",
244
+ children: e.unreadCount
245
+ })]
246
+ })
247
+ ]
161
248
  })]
162
249
  }) }, e.id)) })
163
250
  })]
164
- }), /* @__PURE__ */ S("section", {
165
- className: t("flex min-h-0 flex-col", L ? "flex" : "hidden lg:flex"),
166
- children: W ? /* @__PURE__ */ C(x, { children: [
167
- /* @__PURE__ */ C("header", {
251
+ }), /* @__PURE__ */ x("section", {
252
+ className: t("flex min-h-0 flex-col", R ? "flex" : "hidden lg:flex"),
253
+ children: Y ? /* @__PURE__ */ S(b, { children: [
254
+ /* @__PURE__ */ S("header", {
168
255
  className: "flex items-center gap-3 border-b border-border-subtle p-3",
169
256
  children: [
170
- /* @__PURE__ */ S("button", {
257
+ /* @__PURE__ */ x("button", {
171
258
  type: "button",
172
- onClick: () => R(void 0),
259
+ onClick: () => z(void 0),
173
260
  className: "rounded-md p-1.5 text-text-secondary transition-colors hover:bg-bg-sunken lg:hidden",
174
261
  "aria-label": "Back to conversations",
175
- children: /* @__PURE__ */ S(h, { className: "h-5 w-5" })
262
+ children: /* @__PURE__ */ x(g, { className: "h-5 w-5" })
176
263
  }),
177
- /* @__PURE__ */ S(j, {
178
- title: W.title,
179
- id: W.id,
180
- size: "sm"
264
+ /* @__PURE__ */ x(j, {
265
+ title: Y.title,
266
+ id: Y.id,
267
+ size: "sm",
268
+ imageUrl: Y.avatar
181
269
  }),
182
- /* @__PURE__ */ C("div", {
270
+ /* @__PURE__ */ S("div", {
183
271
  className: "min-w-0 flex-1",
184
- children: [/* @__PURE__ */ S("h2", {
185
- className: "truncate text-sm font-semibold text-text-primary",
186
- children: W.title
187
- }), W.contextHref && /* @__PURE__ */ C("button", {
188
- type: "button",
189
- onClick: () => D(`..${W.contextHref}`),
190
- className: "flex items-center gap-1 text-xs text-text-secondary transition-colors hover:text-primary",
191
- children: [/* @__PURE__ */ S(g, { className: "h-3 w-3" }), "View listing"]
272
+ children: [/* @__PURE__ */ S("div", {
273
+ className: "flex min-w-0 items-baseline gap-2",
274
+ children: [/* @__PURE__ */ x("h2", {
275
+ className: "truncate text-sm font-semibold text-text-primary",
276
+ children: Y.title
277
+ }), Z && /* @__PURE__ */ S("span", {
278
+ className: "shrink-0 text-sm font-semibold text-primary",
279
+ children: [n(Z.price.amount, Z.price.currency), Z.price.type === "rent" && Z.price.period === "monthly" ? "/mo" : ""]
280
+ })]
281
+ }), /* @__PURE__ */ S("div", {
282
+ className: "flex items-center gap-2",
283
+ children: [O(Y.entityType) && /* @__PURE__ */ x("span", {
284
+ className: "text-xs text-text-secondary",
285
+ children: O(Y.entityType)
286
+ }), Y.contextHref && /* @__PURE__ */ S("button", {
287
+ type: "button",
288
+ onClick: () => w(`..${Y.contextHref}`),
289
+ className: "flex items-center gap-1 text-xs text-text-secondary transition-colors hover:text-primary",
290
+ children: [/* @__PURE__ */ x(ie, { className: "h-3 w-3" }), "View listing"]
291
+ })]
192
292
  })]
193
293
  })
194
294
  ]
195
295
  }),
196
- /* @__PURE__ */ S("div", {
197
- ref: U,
296
+ /* @__PURE__ */ x("div", {
297
+ ref: J,
198
298
  className: "min-h-0 flex-1 space-y-2 overflow-y-auto bg-bg-sunken/40 p-4",
199
- children: K && G.length === 0 ? /* @__PURE__ */ S("p", {
299
+ children: me && X.length === 0 ? /* @__PURE__ */ x("p", {
200
300
  className: "py-10 text-center text-sm text-text-secondary",
201
301
  children: "Loading messages…"
202
- }) : G.length === 0 ? /* @__PURE__ */ S("p", {
302
+ }) : X.length === 0 ? /* @__PURE__ */ x("p", {
203
303
  className: "py-10 text-center text-sm text-text-secondary",
204
304
  children: "No messages yet. Say hello to get the conversation started."
205
- }) : G.map((e) => {
206
- let n = e.authorId === k;
207
- return /* @__PURE__ */ S("div", {
305
+ }) : X.map((e) => {
306
+ let n = e.authorId === E;
307
+ return /* @__PURE__ */ x("div", {
208
308
  className: t("flex", n ? "justify-end" : "justify-start"),
209
- children: /* @__PURE__ */ C("div", {
309
+ children: /* @__PURE__ */ S("div", {
210
310
  className: t("max-w-[78%]", n ? "items-end" : "items-start"),
211
- children: [/* @__PURE__ */ S("div", {
212
- className: t("rounded-2xl px-3.5 py-2 text-sm", n ? "rounded-br-sm bg-action-primary-bg text-action-primary-text" : "rounded-bl-sm border border-border-subtle bg-bg-surface text-text-primary"),
213
- children: e.text
214
- }), /* @__PURE__ */ S("div", {
215
- className: t("mt-1 px-1 text-[0.65rem] text-text-secondary", n && "text-right"),
216
- children: A(e.createdAt)
217
- })]
311
+ children: [
312
+ !n && e.authorName && /* @__PURE__ */ x("div", {
313
+ className: "mb-0.5 px-1 text-xs font-medium text-text-secondary",
314
+ children: e.authorName
315
+ }),
316
+ e.text && /* @__PURE__ */ x("div", {
317
+ className: t("rounded-2xl px-3.5 py-2 text-sm", n ? "rounded-br-sm bg-action-primary-bg text-action-primary-text" : "rounded-bl-sm border border-border-subtle bg-bg-surface text-text-primary"),
318
+ children: e.text
319
+ }),
320
+ /* @__PURE__ */ x(fe, {
321
+ attachments: e.attachments,
322
+ mine: n
323
+ }),
324
+ /* @__PURE__ */ x("div", {
325
+ className: t("mt-1 px-1 text-[0.65rem] text-text-secondary", n && "text-right"),
326
+ children: de(e.createdAt)
327
+ })
328
+ ]
218
329
  })
219
330
  }, e.id);
220
331
  })
221
332
  }),
222
- /* @__PURE__ */ C("div", {
223
- className: "flex items-end gap-2 border-t border-border-subtle p-3",
224
- children: [/* @__PURE__ */ S("textarea", {
225
- value: V,
226
- onChange: (e) => H(e.target.value),
227
- onKeyDown: (e) => {
228
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), Y());
229
- },
230
- rows: 1,
231
- placeholder: "Type a message…",
232
- "aria-label": "Message",
233
- className: "max-h-32 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)]"
234
- }), /* @__PURE__ */ C(w, {
235
- type: "button",
236
- onClick: Y,
237
- disabled: !V.trim() || I,
238
- children: [/* @__PURE__ */ S(y, { className: "h-4 w-4" }), /* @__PURE__ */ S("span", {
239
- className: "ml-1 hidden sm:inline",
240
- children: "Send"
241
- })]
333
+ /* @__PURE__ */ S("div", {
334
+ className: "border-t border-border-subtle p-3",
335
+ children: [U.length > 0 && /* @__PURE__ */ x("ul", {
336
+ className: "mb-2 flex flex-wrap gap-2",
337
+ children: U.map((e) => /* @__PURE__ */ S("li", {
338
+ className: "flex max-w-full items-center gap-2 rounded-md border border-border-subtle bg-bg-surface px-2.5 py-1.5 text-sm text-text-primary",
339
+ children: [
340
+ /* @__PURE__ */ x(_, { className: "h-4 w-4 shrink-0 text-text-secondary" }),
341
+ /* @__PURE__ */ x("span", {
342
+ className: "truncate",
343
+ children: e.name
344
+ }),
345
+ k(e.size) && /* @__PURE__ */ x("span", {
346
+ className: "shrink-0 text-xs text-text-secondary",
347
+ children: k(e.size)
348
+ }),
349
+ /* @__PURE__ */ x("button", {
350
+ type: "button",
351
+ onClick: () => W((t) => t.filter((t) => t.id !== e.id)),
352
+ "aria-label": `Remove ${e.name}`,
353
+ className: "shrink-0 text-text-secondary transition-colors hover:text-status-error-text",
354
+ children: /* @__PURE__ */ x(se, { className: "h-4 w-4" })
355
+ })
356
+ ]
357
+ }, e.id))
358
+ }), /* @__PURE__ */ S("div", {
359
+ className: "flex items-end gap-2",
360
+ children: [
361
+ /* @__PURE__ */ x("textarea", {
362
+ value: V,
363
+ onChange: (e) => H(e.target.value),
364
+ onKeyDown: (e) => {
365
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), $());
366
+ },
367
+ rows: 1,
368
+ placeholder: "Type a message…",
369
+ "aria-label": "Message",
370
+ className: "max-h-32 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)]"
371
+ }),
372
+ ge && /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("input", {
373
+ ref: q,
374
+ type: "file",
375
+ multiple: !0,
376
+ className: "hidden",
377
+ onChange: (e) => void ve(e.target.files)
378
+ }), /* @__PURE__ */ x("button", {
379
+ type: "button",
380
+ onClick: () => q.current?.click(),
381
+ disabled: G,
382
+ "aria-label": "Attach files",
383
+ className: "rounded-md border border-border-subtle p-2.5 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary disabled:opacity-60",
384
+ children: G ? /* @__PURE__ */ x(re, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ x(ae, { className: "h-4 w-4" })
385
+ })] }),
386
+ /* @__PURE__ */ S(C, {
387
+ type: "button",
388
+ onClick: $,
389
+ disabled: !V.trim() && U.length === 0 || _e,
390
+ children: [/* @__PURE__ */ x(y, { className: "h-4 w-4" }), /* @__PURE__ */ x("span", {
391
+ className: "ml-1 hidden sm:inline",
392
+ children: "Send"
393
+ })]
394
+ })
395
+ ]
242
396
  })]
243
397
  })
244
- ] }) : /* @__PURE__ */ S("div", {
398
+ ] }) : /* @__PURE__ */ x("div", {
245
399
  className: "hidden flex-1 items-center justify-center p-8 lg:flex",
246
- children: /* @__PURE__ */ C("div", {
400
+ children: /* @__PURE__ */ S("div", {
247
401
  className: "text-center",
248
- children: [/* @__PURE__ */ S(_, { className: "mx-auto h-10 w-10 text-text-secondary" }), /* @__PURE__ */ S("p", {
402
+ children: [/* @__PURE__ */ x(v, { className: "mx-auto h-10 w-10 text-text-secondary" }), /* @__PURE__ */ x("p", {
249
403
  className: "mt-3 text-sm text-text-secondary",
250
404
  children: "Select a conversation to read and reply."
251
405
  })]