@burdenoff/microfe-housingvista 2026.930.2 → 2026.1001.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.
@@ -1 +1 @@
1
- {"version":3,"file":"OffersPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/offers/OffersPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwIH,wBAAgB,UAAU,gCA2SzB"}
1
+ {"version":3,"file":"OffersPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/offers/OffersPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyIH,wBAAgB,UAAU,gCA6UzB"}
@@ -4,17 +4,18 @@ import { StatCard as i } from "../../components/StatCard.js";
4
4
  import { StatusBadge as a } from "../../components/StatusBadge.js";
5
5
  import { EmptyState as o } from "../../components/EmptyState.js";
6
6
  import { useTrackPageView as s } from "../../hooks/useHousingVistaAnalytics.js";
7
- import { useOffers as c, useRespondOffer as l, useWithdrawOffer as u } from "../../hooks/index.js";
8
- import { notify as d } from "../../lib/toast.js";
7
+ import { useOffers as c, useRespondOffer as ee, useWithdrawOffer as l } from "../../hooks/index.js";
8
+ import { notify as u } from "../../lib/toast.js";
9
+ import { ContactOwnerDialog as d } from "../../components/ContactOwnerDialog.js";
9
10
  import "../../components/index.js";
10
11
  import { useServerPagination as f } from "../../hooks/useServerPagination.js";
11
12
  import { useState as p } from "react";
12
- import { ArrowRight as m, Check as h, Home as g, MapPin as _, Repeat as v, Tag as y, Undo2 as b, X as ee } from "lucide-react";
13
- import { useNavigate as x } from "react-router";
14
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
15
- import { Button as w, EmphasisPanel as T, GlassCard as te, Pagination as ne, ResponsiveDialog as re, ResponsiveDialogContent as ie, ResponsiveDialogDescription as E, ResponsiveDialogFooter as D, ResponsiveDialogHeader as O, ResponsiveDialogTitle as k } from "@burdenoff/fe-libs/ui";
13
+ import { ArrowRight as m, Check as h, Home as g, MapPin as _, MessageSquare as v, Repeat as y, Tag as b, Undo2 as te, X as x } from "lucide-react";
14
+ import { useNavigate as S } from "react-router";
15
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
16
+ import { Button as T, EmphasisPanel as ne, GlassCard as re, Pagination as ie, ResponsiveDialog as ae, ResponsiveDialogContent as oe, ResponsiveDialogDescription as se, ResponsiveDialogFooter as E, ResponsiveDialogHeader as D, ResponsiveDialogTitle as O } from "@burdenoff/fe-libs/ui";
16
17
  //#region src/housingvista/pages/offers/OffersPage.tsx
17
- var A = [
18
+ var k = [
18
19
  {
19
20
  value: "all",
20
21
  label: "All"
@@ -44,7 +45,7 @@ var A = [
44
45
  label: "Expired"
45
46
  }
46
47
  ];
47
- function j(e) {
48
+ function A(e) {
48
49
  switch (e) {
49
50
  case "accepted": return "success";
50
51
  case "countered": return "warning";
@@ -53,14 +54,14 @@ function j(e) {
53
54
  default: return "muted";
54
55
  }
55
56
  }
56
- var M = {
57
+ var j = {
57
58
  success: "bg-status-success",
58
59
  warning: "bg-status-warning",
59
60
  error: "bg-status-error",
60
61
  info: "bg-status-info",
61
62
  muted: "bg-text-secondary"
62
63
  };
63
- function N(e) {
64
+ function M(e) {
64
65
  let t = {
65
66
  label: "Submitted",
66
67
  date: e.createdAt,
@@ -130,24 +131,24 @@ function N(e) {
130
131
  }];
131
132
  }
132
133
  }
133
- function P({ offer: t }) {
134
- let r = N(t);
135
- return /* @__PURE__ */ S("ol", {
134
+ function N({ offer: t }) {
135
+ let r = M(t);
136
+ return /* @__PURE__ */ C("ol", {
136
137
  className: "flex items-start",
137
138
  "aria-label": "Offer status timeline",
138
139
  children: r.map((t, i) => {
139
140
  let a = i === r.length - 1, o = !a && r[i + 1].filled;
140
- return /* @__PURE__ */ C("li", {
141
+ return /* @__PURE__ */ w("li", {
141
142
  className: e("flex flex-col items-center", !a && "flex-1"),
142
- children: [/* @__PURE__ */ C("div", {
143
+ children: [/* @__PURE__ */ w("div", {
143
144
  className: "flex w-full items-center",
144
- children: [/* @__PURE__ */ S("span", { className: e("flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full", t.filled ? M[t.tone] : "border-2 border-border-subtle bg-bg-surface") }), !a && /* @__PURE__ */ S("span", { className: e("mx-1 h-0.5 flex-1 rounded-full", t.filled && o ? M[t.tone] : "bg-border-subtle") })]
145
- }), /* @__PURE__ */ C("div", {
145
+ children: [/* @__PURE__ */ C("span", { className: e("flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full", t.filled ? j[t.tone] : "border-2 border-border-subtle bg-bg-surface") }), !a && /* @__PURE__ */ C("span", { className: e("mx-1 h-0.5 flex-1 rounded-full", t.filled && o ? j[t.tone] : "bg-border-subtle") })]
146
+ }), /* @__PURE__ */ w("div", {
146
147
  className: e("mt-1.5 text-center", a ? "items-end" : ""),
147
- children: [/* @__PURE__ */ S("span", {
148
+ children: [/* @__PURE__ */ C("span", {
148
149
  className: "block text-xs font-medium text-text-primary",
149
150
  children: t.label
150
- }), t.date && /* @__PURE__ */ S("span", {
151
+ }), t.date && /* @__PURE__ */ C("span", {
151
152
  className: "block text-[0.65rem] text-text-secondary",
152
153
  children: n(t.date)
153
154
  })]
@@ -156,283 +157,302 @@ function P({ offer: t }) {
156
157
  })
157
158
  });
158
159
  }
159
- var F = "h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
160
- function I() {
160
+ var P = "h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
161
+ function F() {
161
162
  s("housingvista.offer.viewed");
162
- let M = x(), N = f(10), [I, L] = p("all"), { data: R, loading: z } = c({
163
- filter: I === "all" ? void 0 : { status: I },
164
- pagination: N.pagination
165
- }), { data: B } = c({ pagination: {
163
+ let j = S(), M = f(10), [F, I] = p("all"), { data: L, loading: R } = c({
164
+ filter: F === "all" ? void 0 : { status: F },
165
+ pagination: M.pagination
166
+ }), { data: z } = c({ pagination: {
166
167
  limit: 100,
167
168
  offset: 0
168
- } }), { respondOffer: V, loading: H } = l(), { withdrawOffer: U, loading: W } = u(), [G, K] = p(null), [q, J] = p("accept"), [Y, X] = p(""), [Z, Q] = p(""), ae = (e) => {
169
- K(e), J("accept"), X(String(e.amount)), Q("");
170
- }, oe = async (e) => {
171
- if (e.preventDefault(), G) {
172
- if (q === "counter") {
173
- let e = Number(Y);
169
+ } }), { respondOffer: B, loading: V } = ee(), { withdrawOffer: H, loading: U } = l(), [W, G] = p(null), [K, q] = p(null), [J, Y] = p("accept"), [X, Z] = p(""), [Q, $] = p(""), ce = (e) => {
170
+ G(e), Y("accept"), Z(String(e.amount)), $("");
171
+ }, le = async (e) => {
172
+ if (e.preventDefault(), W) {
173
+ if (J === "counter") {
174
+ let e = Number(X);
174
175
  if (!Number.isFinite(e) || e <= 0) {
175
- d.warning("Enter a valid counter amount");
176
+ u.warning("Enter a valid counter amount");
176
177
  return;
177
178
  }
178
179
  }
179
180
  try {
180
- await V(G.id, {
181
- action: q,
182
- counterAmount: q === "counter" ? Number(Y) : void 0,
183
- notes: Z.trim() || void 0
184
- }), d.success("Response sent", `Offer ${q === "accept" ? "accepted" : q === "reject" ? "rejected" : "countered"}.`), K(null);
181
+ await B(W.id, {
182
+ action: J,
183
+ counterAmount: J === "counter" ? Number(X) : void 0,
184
+ notes: Q.trim() || void 0
185
+ }), u.success("Response sent", `Offer ${J === "accept" ? "accepted" : J === "reject" ? "rejected" : "countered"}.`), G(null);
185
186
  } catch (e) {
186
- d.error("Could not respond to offer", e.message);
187
+ u.error("Could not respond to offer", e.message);
187
188
  }
188
189
  }
189
- }, se = async (e) => {
190
+ }, ue = async (e) => {
190
191
  try {
191
- await U(e.id), d.success("Offer withdrawn");
192
+ await H(e.id), u.success("Offer withdrawn");
192
193
  } catch (e) {
193
- d.error("Could not withdraw offer", e.message);
194
+ u.error("Could not withdraw offer", e.message);
194
195
  }
195
- }, ce = (e) => e === "all" ? B.length : B.filter((t) => t.status === e).length, le = B.filter((e) => e.status === "submitted" || e.status === "countered").length, $ = B.filter((e) => e.status === "accepted").length;
196
- return /* @__PURE__ */ C(r, {
196
+ }, de = (e) => e === "all" ? z.length : z.filter((t) => t.status === e).length, fe = z.filter((e) => e.status === "submitted" || e.status === "countered").length, pe = z.filter((e) => e.status === "accepted").length;
197
+ return /* @__PURE__ */ w(r, {
197
198
  title: "Offers",
198
199
  description: "Track the offers you have made and respond to offers on your listings",
199
200
  purpose: "Every offer in one place: watch its status move from submitted to countered, accepted, or rejected — withdraw one you no longer want, or respond to offers coming in on properties you own.",
200
201
  children: [
201
- /* @__PURE__ */ S(T, {
202
+ /* @__PURE__ */ C(ne, {
202
203
  className: "p-4",
203
- children: /* @__PURE__ */ C("div", {
204
+ children: /* @__PURE__ */ w("div", {
204
205
  className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
205
206
  children: [
206
- /* @__PURE__ */ S(i, {
207
+ /* @__PURE__ */ C(i, {
207
208
  label: "Total offers",
208
- value: B.length,
209
- icon: /* @__PURE__ */ S(y, { className: "h-4 w-4" })
209
+ value: z.length,
210
+ icon: /* @__PURE__ */ C(b, { className: "h-4 w-4" })
210
211
  }),
211
- /* @__PURE__ */ S(i, {
212
+ /* @__PURE__ */ C(i, {
212
213
  label: "Awaiting action",
213
- value: le,
214
- icon: /* @__PURE__ */ S(v, { className: "h-4 w-4" })
214
+ value: fe,
215
+ icon: /* @__PURE__ */ C(y, { className: "h-4 w-4" })
215
216
  }),
216
- /* @__PURE__ */ S(i, {
217
+ /* @__PURE__ */ C(i, {
217
218
  label: "Accepted",
218
- value: $,
219
- icon: /* @__PURE__ */ S(h, { className: "h-4 w-4" })
219
+ value: pe,
220
+ icon: /* @__PURE__ */ C(h, { className: "h-4 w-4" })
220
221
  })
221
222
  ]
222
223
  })
223
224
  }),
224
- /* @__PURE__ */ S("div", {
225
+ /* @__PURE__ */ C("div", {
225
226
  className: "-mx-1 flex flex-nowrap items-center gap-2 overflow-x-auto px-1 pb-1 sm:flex-wrap sm:overflow-visible",
226
- children: A.map((t) => {
227
- let n = ce(t.value), r = I === t.value;
228
- return /* @__PURE__ */ C("button", {
227
+ children: k.map((t) => {
228
+ let n = de(t.value), r = F === t.value;
229
+ return /* @__PURE__ */ w("button", {
229
230
  onClick: () => {
230
- L(t.value), N.setPage(1);
231
+ I(t.value), M.setPage(1);
231
232
  },
232
233
  className: e("inline-flex shrink-0 items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors", r ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
233
- children: [t.label, /* @__PURE__ */ S("span", {
234
+ children: [t.label, /* @__PURE__ */ C("span", {
234
235
  className: e("inline-flex min-w-5 items-center justify-center rounded-full px-1.5 text-[0.65rem] font-semibold tabular-nums", r ? "bg-action-primary-text/20 text-action-primary-text" : "bg-bg-surface text-text-secondary"),
235
236
  children: n
236
237
  })]
237
238
  }, t.value);
238
239
  })
239
240
  }),
240
- R.length === 0 && !z ? /* @__PURE__ */ S(o, {
241
+ L.length === 0 && !R ? /* @__PURE__ */ C(o, {
241
242
  illustration: "empty-search",
242
- icon: /* @__PURE__ */ S(y, { className: "h-12 w-12" }),
243
+ icon: /* @__PURE__ */ C(b, { className: "h-12 w-12" }),
243
244
  title: "No offers here",
244
245
  description: "Offers you submit on properties — and offers made on your listings — will appear here.",
245
- action: /* @__PURE__ */ S(w, {
246
- onClick: () => M("../properties"),
246
+ action: /* @__PURE__ */ C(T, {
247
+ onClick: () => j("../properties"),
247
248
  children: "Browse properties"
248
249
  })
249
- }) : /* @__PURE__ */ C("div", {
250
+ }) : /* @__PURE__ */ w("div", {
250
251
  className: "space-y-4",
251
- children: [/* @__PURE__ */ S("div", {
252
+ children: [/* @__PURE__ */ C("div", {
252
253
  className: "grid grid-cols-1 gap-4 xl:grid-cols-2",
253
- children: R.map((e) => {
254
+ children: L.map((e) => {
254
255
  let r = e.property?.images.find((e) => e.isPrimary) ?? e.property?.images[0], i = e.status === "submitted" || e.status === "countered";
255
- return /* @__PURE__ */ C(te, {
256
+ return /* @__PURE__ */ w(re, {
256
257
  treatment: i ? "insight" : "plain",
257
258
  glow: i,
258
259
  className: "flex flex-col gap-4 p-5",
259
260
  children: [
260
- /* @__PURE__ */ C("div", {
261
+ /* @__PURE__ */ w("div", {
261
262
  className: "flex items-start gap-3",
262
- children: [/* @__PURE__ */ S("button", {
263
+ children: [/* @__PURE__ */ C("button", {
263
264
  type: "button",
264
- onClick: () => e.property && M(`../properties/${e.property.id}`),
265
+ onClick: () => e.property && j(`../properties/${e.property.id}`),
265
266
  className: "shrink-0",
266
267
  "aria-label": `Open ${e.property?.title ?? "property"}`,
267
- children: r ? /* @__PURE__ */ S("img", {
268
+ children: r ? /* @__PURE__ */ C("img", {
268
269
  src: r.url,
269
270
  alt: "",
270
271
  className: "h-16 w-16 rounded-lg object-cover"
271
- }) : /* @__PURE__ */ S("div", {
272
+ }) : /* @__PURE__ */ C("div", {
272
273
  className: "flex h-16 w-16 items-center justify-center rounded-lg bg-bg-sunken",
273
- children: /* @__PURE__ */ S(g, { className: "h-6 w-6 text-text-secondary" })
274
+ children: /* @__PURE__ */ C(g, { className: "h-6 w-6 text-text-secondary" })
274
275
  })
275
- }), /* @__PURE__ */ C("div", {
276
+ }), /* @__PURE__ */ w("div", {
276
277
  className: "min-w-0 flex-1",
277
278
  children: [
278
- /* @__PURE__ */ C("div", {
279
+ /* @__PURE__ */ w("div", {
279
280
  className: "flex flex-wrap items-start justify-between gap-2",
280
- children: [/* @__PURE__ */ C("button", {
281
+ children: [/* @__PURE__ */ w("button", {
281
282
  type: "button",
282
- onClick: () => e.property && M(`../properties/${e.property.id}`),
283
+ onClick: () => e.property && j(`../properties/${e.property.id}`),
283
284
  className: "text-left",
284
- children: [/* @__PURE__ */ S("h3", {
285
+ children: [/* @__PURE__ */ C("h3", {
285
286
  className: "font-semibold text-text-primary hover:text-primary",
286
287
  children: e.property?.title ?? "Property"
287
- }), e.property && /* @__PURE__ */ C("p", {
288
+ }), e.property && /* @__PURE__ */ w("p", {
288
289
  className: "flex items-center gap-1 text-xs text-text-secondary",
289
290
  children: [
290
- /* @__PURE__ */ S(_, { className: "h-3 w-3" }),
291
+ /* @__PURE__ */ C(_, { className: "h-3 w-3" }),
291
292
  e.property.location.city,
292
293
  ", ",
293
294
  e.property.location.state
294
295
  ]
295
296
  })]
296
- }), /* @__PURE__ */ S(a, {
297
+ }), /* @__PURE__ */ C(a, {
297
298
  label: e.status,
298
- variant: j(e.status),
299
+ variant: A(e.status),
299
300
  dot: !0
300
301
  })]
301
302
  }),
302
- /* @__PURE__ */ C("div", {
303
+ /* @__PURE__ */ w("div", {
303
304
  className: "mt-2 flex items-baseline gap-3",
304
- children: [/* @__PURE__ */ S("span", {
305
+ children: [/* @__PURE__ */ C("span", {
305
306
  className: "text-xl font-bold tabular-nums text-text-primary",
306
307
  children: t(e.amount, e.currency)
307
- }), e.counterAmount != null && /* @__PURE__ */ C("span", {
308
+ }), e.counterAmount != null && /* @__PURE__ */ w("span", {
308
309
  className: "text-sm text-text-secondary",
309
310
  children: [
310
311
  "Counter",
311
312
  " ",
312
- /* @__PURE__ */ S("span", {
313
+ /* @__PURE__ */ C("span", {
313
314
  className: "font-semibold text-status-warning-text",
314
315
  children: t(e.counterAmount, e.currency)
315
316
  })
316
317
  ]
317
318
  })]
318
319
  }),
319
- /* @__PURE__ */ C("p", {
320
+ /* @__PURE__ */ w("p", {
320
321
  className: "mt-0.5 text-xs text-text-secondary",
321
322
  children: ["Submitted ", n(e.createdAt)]
322
323
  }),
323
- (e.status === "submitted" || e.status === "countered") && e.expiresAt && /* @__PURE__ */ C("p", {
324
+ (e.status === "submitted" || e.status === "countered") && e.expiresAt && /* @__PURE__ */ w("p", {
324
325
  className: "mt-0.5 text-xs text-text-secondary",
325
326
  children: ["Expires ", n(e.expiresAt)]
326
327
  })
327
328
  ]
328
329
  })]
329
330
  }),
330
- /* @__PURE__ */ S("div", {
331
+ /* @__PURE__ */ C("div", {
331
332
  className: "rounded-lg bg-bg-sunken/50 p-3",
332
- children: /* @__PURE__ */ S(P, { offer: e })
333
+ children: /* @__PURE__ */ C(N, { offer: e })
333
334
  }),
334
- i && /* @__PURE__ */ C("div", {
335
+ (i || e.property) && /* @__PURE__ */ w("div", {
335
336
  className: "flex flex-wrap gap-2",
336
337
  children: [
337
- /* @__PURE__ */ C(w, {
338
+ i && /* @__PURE__ */ w(T, {
338
339
  size: "sm",
339
- onClick: () => ae(e),
340
- children: [/* @__PURE__ */ S(h, { className: "h-4 w-4" }), /* @__PURE__ */ S("span", {
340
+ onClick: () => ce(e),
341
+ children: [/* @__PURE__ */ C(h, { className: "h-4 w-4" }), /* @__PURE__ */ C("span", {
341
342
  className: "ml-1",
342
343
  children: "Respond"
343
344
  })]
344
345
  }),
345
- /* @__PURE__ */ C(w, {
346
+ i && /* @__PURE__ */ w(T, {
346
347
  variant: "outline",
347
348
  size: "sm",
348
- disabled: W,
349
- onClick: () => se(e),
350
- children: [/* @__PURE__ */ S(b, { className: "h-4 w-4" }), /* @__PURE__ */ S("span", {
349
+ disabled: U,
350
+ onClick: () => ue(e),
351
+ children: [/* @__PURE__ */ C(te, { className: "h-4 w-4" }), /* @__PURE__ */ C("span", {
351
352
  className: "ml-1",
352
353
  children: "Withdraw"
353
354
  })]
354
355
  }),
355
- e.property && /* @__PURE__ */ C(w, {
356
+ e.property && /* @__PURE__ */ w(T, {
357
+ variant: "ghost",
358
+ size: "sm",
359
+ onClick: () => q(e),
360
+ children: [/* @__PURE__ */ C(v, { className: "h-4 w-4" }), /* @__PURE__ */ C("span", {
361
+ className: "ml-1",
362
+ children: "Message"
363
+ })]
364
+ }),
365
+ e.property && /* @__PURE__ */ w(T, {
356
366
  variant: "ghost",
357
367
  size: "sm",
358
- onClick: () => M(`../properties/${e.property?.id}`),
359
- children: [/* @__PURE__ */ S("span", { children: "View property" }), /* @__PURE__ */ S(m, { className: "ml-1 h-4 w-4" })]
368
+ onClick: () => j(`../properties/${e.property?.id}`),
369
+ children: [/* @__PURE__ */ C("span", { children: "View property" }), /* @__PURE__ */ C(m, { className: "ml-1 h-4 w-4" })]
360
370
  })
361
371
  ]
362
372
  })
363
373
  ]
364
374
  }, e.id);
365
375
  })
366
- }), /* @__PURE__ */ S(ne, {
367
- page: N.page,
368
- pageSize: N.pageSize,
369
- hasNextPage: R.length >= N.pageSize,
370
- hasPreviousPage: N.page > 1,
371
- onPageChange: N.setPage,
372
- onPageSizeChange: N.setPageSize
376
+ }), /* @__PURE__ */ C(ie, {
377
+ page: M.page,
378
+ pageSize: M.pageSize,
379
+ hasNextPage: L.length >= M.pageSize,
380
+ hasPreviousPage: M.page > 1,
381
+ onPageChange: M.setPage,
382
+ onPageSizeChange: M.setPageSize
373
383
  })]
374
384
  }),
375
- /* @__PURE__ */ S(re, {
376
- open: G !== null,
377
- onOpenChange: (e) => !e && K(null),
378
- children: /* @__PURE__ */ S(ie, {
385
+ K?.property && /* @__PURE__ */ C(d, {
386
+ open: K !== null,
387
+ onOpenChange: (e) => !e && q(null),
388
+ entityId: K.property.id,
389
+ entityType: "housingvista-property",
390
+ title: K.property.title,
391
+ pagePath: "/housingvista/offers",
392
+ heading: "Message",
393
+ description: `Discuss ${K.property.title} with the other party. The thread also appears in Messages.`
394
+ }, K.property.id),
395
+ /* @__PURE__ */ C(ae, {
396
+ open: W !== null,
397
+ onOpenChange: (e) => !e && G(null),
398
+ children: /* @__PURE__ */ C(oe, {
379
399
  className: "sm:max-w-md",
380
- children: /* @__PURE__ */ C("form", {
381
- onSubmit: oe,
400
+ children: /* @__PURE__ */ w("form", {
401
+ onSubmit: le,
382
402
  children: [
383
- /* @__PURE__ */ C(O, { children: [/* @__PURE__ */ S(k, { children: "Respond to offer" }), /* @__PURE__ */ S(E, { children: G?.property?.title ? `Offer of ${t(G.amount, G.currency)} on ${G.property.title}.` : "Accept, counter, or reject this offer." })] }),
384
- /* @__PURE__ */ C("div", {
403
+ /* @__PURE__ */ w(D, { children: [/* @__PURE__ */ C(O, { children: "Respond to offer" }), /* @__PURE__ */ C(se, { children: W?.property?.title ? `Offer of ${t(W.amount, W.currency)} on ${W.property.title}.` : "Accept, counter, or reject this offer." })] }),
404
+ /* @__PURE__ */ w("div", {
385
405
  className: "space-y-3 py-2",
386
406
  children: [
387
- /* @__PURE__ */ S("div", {
407
+ /* @__PURE__ */ C("div", {
388
408
  className: "flex flex-wrap gap-2",
389
409
  children: [
390
410
  "accept",
391
411
  "counter",
392
412
  "reject"
393
- ].map((t) => /* @__PURE__ */ C("button", {
413
+ ].map((t) => /* @__PURE__ */ w("button", {
394
414
  type: "button",
395
- onClick: () => J(t),
396
- className: e("inline-flex items-center gap-1 rounded-md px-3 py-1.5 text-sm font-medium capitalize transition-colors", q === t ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
415
+ onClick: () => Y(t),
416
+ className: e("inline-flex items-center gap-1 rounded-md px-3 py-1.5 text-sm font-medium capitalize transition-colors", J === t ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
397
417
  children: [
398
- t === "accept" && /* @__PURE__ */ S(h, { className: "h-4 w-4" }),
399
- t === "counter" && /* @__PURE__ */ S(v, { className: "h-4 w-4" }),
400
- t === "reject" && /* @__PURE__ */ S(ee, { className: "h-4 w-4" }),
418
+ t === "accept" && /* @__PURE__ */ C(h, { className: "h-4 w-4" }),
419
+ t === "counter" && /* @__PURE__ */ C(y, { className: "h-4 w-4" }),
420
+ t === "reject" && /* @__PURE__ */ C(x, { className: "h-4 w-4" }),
401
421
  t
402
422
  ]
403
423
  }, t))
404
424
  }),
405
- q === "counter" && /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("label", {
425
+ J === "counter" && /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("label", {
406
426
  className: "mb-1.5 block text-sm font-medium text-text-primary",
407
427
  children: "Counter amount *"
408
- }), /* @__PURE__ */ S("input", {
428
+ }), /* @__PURE__ */ C("input", {
409
429
  type: "number",
410
430
  min: 1,
411
431
  step: "any",
412
- value: Y,
413
- onChange: (e) => X(e.target.value),
414
- className: F
432
+ value: X,
433
+ onChange: (e) => Z(e.target.value),
434
+ className: P
415
435
  })] }),
416
- /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("label", {
436
+ /* @__PURE__ */ w("div", { children: [/* @__PURE__ */ C("label", {
417
437
  className: "mb-1.5 block text-sm font-medium text-text-primary",
418
438
  children: "Note (optional)"
419
- }), /* @__PURE__ */ S("textarea", {
420
- value: Z,
421
- onChange: (e) => Q(e.target.value),
439
+ }), /* @__PURE__ */ C("textarea", {
440
+ value: Q,
441
+ onChange: (e) => $(e.target.value),
422
442
  rows: 2,
423
443
  className: "w-full 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)]"
424
444
  })] })
425
445
  ]
426
446
  }),
427
- /* @__PURE__ */ C(D, { children: [/* @__PURE__ */ S(w, {
447
+ /* @__PURE__ */ w(E, { children: [/* @__PURE__ */ C(T, {
428
448
  type: "button",
429
449
  variant: "outline",
430
- onClick: () => K(null),
450
+ onClick: () => G(null),
431
451
  children: "Cancel"
432
- }), /* @__PURE__ */ S(w, {
452
+ }), /* @__PURE__ */ C(T, {
433
453
  type: "submit",
434
- disabled: H,
435
- children: H ? "Sending…" : "Send response"
454
+ disabled: V,
455
+ children: V ? "Sending…" : "Send response"
436
456
  })] })
437
457
  ]
438
458
  })
@@ -442,6 +462,6 @@ function I() {
442
462
  });
443
463
  }
444
464
  //#endregion
445
- export { I as OffersPage };
465
+ export { F as OffersPage };
446
466
 
447
467
  //# sourceMappingURL=OffersPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OffersPage.js","names":[],"sources":["../../../../src/housingvista/pages/offers/OffersPage.tsx"],"sourcesContent":["/**\n * Offers — the buyer/owner surface for property offers. Buyers track offers they\n * submitted (status timeline submitted→countered→accepted/rejected/withdrawn)\n * and can withdraw; owners can respond (accept / counter / reject). Server-side\n * status filter + pagination, with live per-status tab counts driven off a real\n * unfiltered read (no fabricated numbers).\n * @module housingvista\n */\n\nimport { useState, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Tag, Check, X, Repeat, Undo2, MapPin, ArrowRight, Home } from 'lucide-react';\nimport {\n Button,\n Pagination,\n EmphasisPanel,\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, StatCard, StatusBadge, EmptyState } from '../../components';\nimport { useOffers, useRespondOffer, useWithdrawOffer, type OfferRow } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst statusTabs: { value: string; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'submitted', label: 'Submitted' },\n { value: 'countered', label: 'Countered' },\n { value: 'accepted', label: 'Accepted' },\n { value: 'rejected', label: 'Rejected' },\n { value: 'withdrawn', label: 'Withdrawn' },\n { value: 'expired', label: 'Expired' },\n];\n\nfunction statusVariant(status: OfferRow['status']): 'success' | 'warning' | 'error' | 'info' | 'muted' {\n switch (status) {\n case 'accepted':\n return 'success';\n case 'countered':\n return 'warning';\n case 'rejected':\n return 'error';\n case 'submitted':\n return 'info';\n default:\n return 'muted';\n }\n}\n\n// ---- Status timeline (submitted → countered → accepted / rejected / withdrawn) ----\n\ntype NodeTone = 'success' | 'warning' | 'error' | 'info' | 'muted';\ninterface TimelineNode {\n label: string;\n date: string | null;\n tone: NodeTone;\n filled: boolean;\n}\n\nconst toneFill: Record<NodeTone, string> = {\n success: 'bg-status-success',\n warning: 'bg-status-warning',\n error: 'bg-status-error',\n info: 'bg-status-info',\n muted: 'bg-text-secondary',\n};\n\nfunction buildTimeline(offer: OfferRow): TimelineNode[] {\n const submitted: TimelineNode = { label: 'Submitted', date: offer.createdAt, tone: 'info', filled: true };\n const respondedAt = offer.respondedAt;\n switch (offer.status) {\n case 'accepted':\n return [\n { ...submitted, tone: 'success' },\n ...(offer.counterAmount != null\n ? [{ label: 'Countered', date: null, tone: 'success' as NodeTone, filled: true }]\n : []),\n { label: 'Accepted', date: respondedAt, tone: 'success', filled: true },\n ];\n case 'countered':\n return [\n { ...submitted, tone: 'warning' },\n { label: 'Countered', date: respondedAt, tone: 'warning', filled: true },\n { label: 'Accepted', date: null, tone: 'muted', filled: false },\n ];\n case 'rejected':\n return [{ ...submitted }, { label: 'Rejected', date: respondedAt, tone: 'error', filled: true }];\n case 'withdrawn':\n return [{ ...submitted }, { label: 'Withdrawn', date: offer.updatedAt, tone: 'muted', filled: true }];\n case 'expired':\n return [{ ...submitted }, { label: 'Expired', date: offer.expiresAt, tone: 'muted', filled: true }];\n default:\n // submitted\n return [{ ...submitted }, { label: 'Accepted', date: null, tone: 'muted', filled: false }];\n }\n}\n\nfunction OfferTimeline({ offer }: { offer: OfferRow }) {\n const nodes = buildTimeline(offer);\n return (\n <ol className=\"flex items-start\" aria-label=\"Offer status timeline\">\n {nodes.map((node, index) => {\n const isLast = index === nodes.length - 1;\n const nextFilled = !isLast && nodes[index + 1].filled;\n return (\n <li key={node.label} className={cn('flex flex-col items-center', !isLast && 'flex-1')}>\n <div className=\"flex w-full items-center\">\n <span\n className={cn(\n 'flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full',\n node.filled ? toneFill[node.tone] : 'border-2 border-border-subtle bg-bg-surface'\n )}\n />\n {!isLast && (\n <span\n className={cn(\n 'mx-1 h-0.5 flex-1 rounded-full',\n node.filled && nextFilled ? toneFill[node.tone] : 'bg-border-subtle'\n )}\n />\n )}\n </div>\n <div className={cn('mt-1.5 text-center', isLast ? 'items-end' : '')}>\n <span className=\"block text-xs font-medium text-text-primary\">{node.label}</span>\n {node.date && <span className=\"block text-[0.65rem] text-text-secondary\">{formatDate(node.date)}</span>}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nexport function OffersPage() {\n useTrackPageView('housingvista.offer.viewed');\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n const [activeTab, setActiveTab] = useState('all');\n const { data: offers, loading } = useOffers({\n filter: activeTab === 'all' ? undefined : { status: activeTab },\n pagination: pagination.pagination,\n });\n // Unfiltered read powers the live tab counts + summary stats (real data).\n const { data: allOffers } = useOffers({ pagination: { limit: 100, offset: 0 } });\n const { respondOffer, loading: responding } = useRespondOffer();\n const { withdrawOffer, loading: withdrawing } = useWithdrawOffer();\n\n const [respondTarget, setRespondTarget] = useState<OfferRow | null>(null);\n const [action, setAction] = useState<'accept' | 'reject' | 'counter'>('accept');\n const [counterAmount, setCounterAmount] = useState('');\n const [notes, setNotes] = useState('');\n\n const openRespond = (offer: OfferRow) => {\n setRespondTarget(offer);\n setAction('accept');\n setCounterAmount(String(offer.amount));\n setNotes('');\n };\n\n const handleRespond = async (event: FormEvent) => {\n event.preventDefault();\n if (!respondTarget) return;\n if (action === 'counter') {\n const amount = Number(counterAmount);\n if (!Number.isFinite(amount) || amount <= 0) {\n notify.warning('Enter a valid counter amount');\n return;\n }\n }\n try {\n await respondOffer(respondTarget.id, {\n action,\n counterAmount: action === 'counter' ? Number(counterAmount) : undefined,\n notes: notes.trim() || undefined,\n });\n notify.success(\n 'Response sent',\n `Offer ${action === 'accept' ? 'accepted' : action === 'reject' ? 'rejected' : 'countered'}.`\n );\n setRespondTarget(null);\n } catch (err) {\n notify.error('Could not respond to offer', (err as Error).message);\n }\n };\n\n const handleWithdraw = async (offer: OfferRow) => {\n try {\n await withdrawOffer(offer.id);\n notify.success('Offer withdrawn');\n } catch (err) {\n notify.error('Could not withdraw offer', (err as Error).message);\n }\n };\n\n const countFor = (value: string): number =>\n value === 'all' ? allOffers.length : allOffers.filter((o) => o.status === value).length;\n\n const activeCount = allOffers.filter((o) => o.status === 'submitted' || o.status === 'countered').length;\n const acceptedCount = allOffers.filter((o) => o.status === 'accepted').length;\n\n return (\n <PageLayout\n title=\"Offers\"\n description=\"Track the offers you have made and respond to offers on your listings\"\n purpose=\"Every offer in one place: watch its status move from submitted to countered, accepted, or rejected — withdraw one you no longer want, or respond to offers coming in on properties you own.\"\n >\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <StatCard label=\"Total offers\" value={allOffers.length} icon={<Tag className=\"h-4 w-4\" />} />\n <StatCard label=\"Awaiting action\" value={activeCount} icon={<Repeat className=\"h-4 w-4\" />} />\n <StatCard label=\"Accepted\" value={acceptedCount} icon={<Check className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n <div className=\"-mx-1 flex flex-nowrap items-center gap-2 overflow-x-auto px-1 pb-1 sm:flex-wrap sm:overflow-visible\">\n {statusTabs.map((tab) => {\n const count = countFor(tab.value);\n const isActive = activeTab === tab.value;\n return (\n <button\n key={tab.value}\n onClick={() => {\n setActiveTab(tab.value);\n pagination.setPage(1);\n }}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.label}\n <span\n className={cn(\n 'inline-flex min-w-5 items-center justify-center rounded-full px-1.5 text-[0.65rem] font-semibold tabular-nums',\n isActive ? 'bg-action-primary-text/20 text-action-primary-text' : 'bg-bg-surface text-text-secondary'\n )}\n >\n {count}\n </span>\n </button>\n );\n })}\n </div>\n\n {offers.length === 0 && !loading ? (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Tag className=\"h-12 w-12\" />}\n title=\"No offers here\"\n description=\"Offers you submit on properties — and offers made on your listings — will appear here.\"\n action={<Button onClick={() => navigate('../properties')}>Browse properties</Button>}\n />\n ) : (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 xl:grid-cols-2\">\n {offers.map((offer) => {\n const image = offer.property?.images.find((img) => img.isPrimary) ?? offer.property?.images[0];\n const canAct = offer.status === 'submitted' || offer.status === 'countered';\n return (\n <GlassCard\n key={offer.id}\n treatment={canAct ? 'insight' : 'plain'}\n glow={canAct}\n className=\"flex flex-col gap-4 p-5\"\n >\n <div className=\"flex items-start gap-3\">\n <button\n type=\"button\"\n onClick={() => offer.property && navigate(`../properties/${offer.property.id}`)}\n className=\"shrink-0\"\n aria-label={`Open ${offer.property?.title ?? 'property'}`}\n >\n {image ? (\n <img src={image.url} alt=\"\" className=\"h-16 w-16 rounded-lg object-cover\" />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-bg-sunken\">\n <Home className=\"h-6 w-6 text-text-secondary\" />\n </div>\n )}\n </button>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <button\n type=\"button\"\n onClick={() => offer.property && navigate(`../properties/${offer.property.id}`)}\n className=\"text-left\"\n >\n <h3 className=\"font-semibold text-text-primary hover:text-primary\">\n {offer.property?.title ?? 'Property'}\n </h3>\n {offer.property && (\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <MapPin className=\"h-3 w-3\" />\n {offer.property.location.city}, {offer.property.location.state}\n </p>\n )}\n </button>\n <StatusBadge label={offer.status} variant={statusVariant(offer.status)} dot />\n </div>\n <div className=\"mt-2 flex items-baseline gap-3\">\n <span className=\"text-xl font-bold tabular-nums text-text-primary\">\n {formatCurrency(offer.amount, offer.currency)}\n </span>\n {offer.counterAmount != null && (\n <span className=\"text-sm text-text-secondary\">\n Counter{' '}\n <span className=\"font-semibold text-status-warning-text\">\n {formatCurrency(offer.counterAmount, offer.currency)}\n </span>\n </span>\n )}\n </div>\n <p className=\"mt-0.5 text-xs text-text-secondary\">Submitted {formatDate(offer.createdAt)}</p>\n {(offer.status === 'submitted' || offer.status === 'countered') && offer.expiresAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">Expires {formatDate(offer.expiresAt)}</p>\n )}\n </div>\n </div>\n\n <div className=\"rounded-lg bg-bg-sunken/50 p-3\">\n <OfferTimeline offer={offer} />\n </div>\n\n {canAct && (\n <div className=\"flex flex-wrap gap-2\">\n <Button size=\"sm\" onClick={() => openRespond(offer)}>\n <Check className=\"h-4 w-4\" />\n <span className=\"ml-1\">Respond</span>\n </Button>\n <Button variant=\"outline\" size=\"sm\" disabled={withdrawing} onClick={() => handleWithdraw(offer)}>\n <Undo2 className=\"h-4 w-4\" />\n <span className=\"ml-1\">Withdraw</span>\n </Button>\n {offer.property && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => navigate(`../properties/${offer.property?.id}`)}\n >\n <span>View property</span>\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n )}\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={offers.length >= pagination.pageSize}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n )}\n\n {/* Respond to offer */}\n <ResponsiveDialog open={respondTarget !== null} onOpenChange={(open) => !open && setRespondTarget(null)}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleRespond}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Respond to offer</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {respondTarget?.property?.title\n ? `Offer of ${formatCurrency(respondTarget.amount, respondTarget.currency)} on ${respondTarget.property.title}.`\n : 'Accept, counter, or reject this offer.'}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div className=\"flex flex-wrap gap-2\">\n {(['accept', 'counter', 'reject'] as const).map((value) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => setAction(value)}\n className={cn(\n 'inline-flex items-center gap-1 rounded-md px-3 py-1.5 text-sm font-medium capitalize transition-colors',\n action === value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {value === 'accept' && <Check className=\"h-4 w-4\" />}\n {value === 'counter' && <Repeat className=\"h-4 w-4\" />}\n {value === 'reject' && <X className=\"h-4 w-4\" />}\n {value}\n </button>\n ))}\n </div>\n {action === 'counter' && (\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Counter amount *</label>\n <input\n type=\"number\"\n min={1}\n step=\"any\"\n value={counterAmount}\n onChange={(event) => setCounterAmount(event.target.value)}\n className={inputClass}\n />\n </div>\n )}\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Note (optional)</label>\n <textarea\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n rows={2}\n className=\"w-full 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 </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setRespondTarget(null)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={responding}>\n {responding ? 'Sending…' : 'Send response'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OffersPage.js","names":[],"sources":["../../../../src/housingvista/pages/offers/OffersPage.tsx"],"sourcesContent":["/**\n * Offers — the buyer/owner surface for property offers. Buyers track offers they\n * submitted (status timeline submitted→countered→accepted/rejected/withdrawn)\n * and can withdraw; owners can respond (accept / counter / reject). Server-side\n * status filter + pagination, with live per-status tab counts driven off a real\n * unfiltered read (no fabricated numbers).\n * @module housingvista\n */\n\nimport { useState, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Tag, Check, X, Repeat, Undo2, MapPin, ArrowRight, Home, MessageSquare } from 'lucide-react';\nimport {\n Button,\n Pagination,\n EmphasisPanel,\n GlassCard,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, StatCard, StatusBadge, EmptyState } from '../../components';\nimport { ContactOwnerDialog } from '../../components';\nimport { useOffers, useRespondOffer, useWithdrawOffer, type OfferRow } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst statusTabs: { value: string; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'submitted', label: 'Submitted' },\n { value: 'countered', label: 'Countered' },\n { value: 'accepted', label: 'Accepted' },\n { value: 'rejected', label: 'Rejected' },\n { value: 'withdrawn', label: 'Withdrawn' },\n { value: 'expired', label: 'Expired' },\n];\n\nfunction statusVariant(status: OfferRow['status']): 'success' | 'warning' | 'error' | 'info' | 'muted' {\n switch (status) {\n case 'accepted':\n return 'success';\n case 'countered':\n return 'warning';\n case 'rejected':\n return 'error';\n case 'submitted':\n return 'info';\n default:\n return 'muted';\n }\n}\n\n// ---- Status timeline (submitted → countered → accepted / rejected / withdrawn) ----\n\ntype NodeTone = 'success' | 'warning' | 'error' | 'info' | 'muted';\ninterface TimelineNode {\n label: string;\n date: string | null;\n tone: NodeTone;\n filled: boolean;\n}\n\nconst toneFill: Record<NodeTone, string> = {\n success: 'bg-status-success',\n warning: 'bg-status-warning',\n error: 'bg-status-error',\n info: 'bg-status-info',\n muted: 'bg-text-secondary',\n};\n\nfunction buildTimeline(offer: OfferRow): TimelineNode[] {\n const submitted: TimelineNode = { label: 'Submitted', date: offer.createdAt, tone: 'info', filled: true };\n const respondedAt = offer.respondedAt;\n switch (offer.status) {\n case 'accepted':\n return [\n { ...submitted, tone: 'success' },\n ...(offer.counterAmount != null\n ? [{ label: 'Countered', date: null, tone: 'success' as NodeTone, filled: true }]\n : []),\n { label: 'Accepted', date: respondedAt, tone: 'success', filled: true },\n ];\n case 'countered':\n return [\n { ...submitted, tone: 'warning' },\n { label: 'Countered', date: respondedAt, tone: 'warning', filled: true },\n { label: 'Accepted', date: null, tone: 'muted', filled: false },\n ];\n case 'rejected':\n return [{ ...submitted }, { label: 'Rejected', date: respondedAt, tone: 'error', filled: true }];\n case 'withdrawn':\n return [{ ...submitted }, { label: 'Withdrawn', date: offer.updatedAt, tone: 'muted', filled: true }];\n case 'expired':\n return [{ ...submitted }, { label: 'Expired', date: offer.expiresAt, tone: 'muted', filled: true }];\n default:\n // submitted\n return [{ ...submitted }, { label: 'Accepted', date: null, tone: 'muted', filled: false }];\n }\n}\n\nfunction OfferTimeline({ offer }: { offer: OfferRow }) {\n const nodes = buildTimeline(offer);\n return (\n <ol className=\"flex items-start\" aria-label=\"Offer status timeline\">\n {nodes.map((node, index) => {\n const isLast = index === nodes.length - 1;\n const nextFilled = !isLast && nodes[index + 1].filled;\n return (\n <li key={node.label} className={cn('flex flex-col items-center', !isLast && 'flex-1')}>\n <div className=\"flex w-full items-center\">\n <span\n className={cn(\n 'flex h-3.5 w-3.5 shrink-0 items-center justify-center rounded-full',\n node.filled ? toneFill[node.tone] : 'border-2 border-border-subtle bg-bg-surface'\n )}\n />\n {!isLast && (\n <span\n className={cn(\n 'mx-1 h-0.5 flex-1 rounded-full',\n node.filled && nextFilled ? toneFill[node.tone] : 'bg-border-subtle'\n )}\n />\n )}\n </div>\n <div className={cn('mt-1.5 text-center', isLast ? 'items-end' : '')}>\n <span className=\"block text-xs font-medium text-text-primary\">{node.label}</span>\n {node.date && <span className=\"block text-[0.65rem] text-text-secondary\">{formatDate(node.date)}</span>}\n </div>\n </li>\n );\n })}\n </ol>\n );\n}\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nexport function OffersPage() {\n useTrackPageView('housingvista.offer.viewed');\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n const [activeTab, setActiveTab] = useState('all');\n const { data: offers, loading } = useOffers({\n filter: activeTab === 'all' ? undefined : { status: activeTab },\n pagination: pagination.pagination,\n });\n // Unfiltered read powers the live tab counts + summary stats (real data).\n const { data: allOffers } = useOffers({ pagination: { limit: 100, offset: 0 } });\n const { respondOffer, loading: responding } = useRespondOffer();\n const { withdrawOffer, loading: withdrawing } = useWithdrawOffer();\n\n const [respondTarget, setRespondTarget] = useState<OfferRow | null>(null);\n const [messageTarget, setMessageTarget] = useState<OfferRow | null>(null);\n const [action, setAction] = useState<'accept' | 'reject' | 'counter'>('accept');\n const [counterAmount, setCounterAmount] = useState('');\n const [notes, setNotes] = useState('');\n\n const openRespond = (offer: OfferRow) => {\n setRespondTarget(offer);\n setAction('accept');\n setCounterAmount(String(offer.amount));\n setNotes('');\n };\n\n const handleRespond = async (event: FormEvent) => {\n event.preventDefault();\n if (!respondTarget) return;\n if (action === 'counter') {\n const amount = Number(counterAmount);\n if (!Number.isFinite(amount) || amount <= 0) {\n notify.warning('Enter a valid counter amount');\n return;\n }\n }\n try {\n await respondOffer(respondTarget.id, {\n action,\n counterAmount: action === 'counter' ? Number(counterAmount) : undefined,\n notes: notes.trim() || undefined,\n });\n notify.success(\n 'Response sent',\n `Offer ${action === 'accept' ? 'accepted' : action === 'reject' ? 'rejected' : 'countered'}.`\n );\n setRespondTarget(null);\n } catch (err) {\n notify.error('Could not respond to offer', (err as Error).message);\n }\n };\n\n const handleWithdraw = async (offer: OfferRow) => {\n try {\n await withdrawOffer(offer.id);\n notify.success('Offer withdrawn');\n } catch (err) {\n notify.error('Could not withdraw offer', (err as Error).message);\n }\n };\n\n const countFor = (value: string): number =>\n value === 'all' ? allOffers.length : allOffers.filter((o) => o.status === value).length;\n\n const activeCount = allOffers.filter((o) => o.status === 'submitted' || o.status === 'countered').length;\n const acceptedCount = allOffers.filter((o) => o.status === 'accepted').length;\n\n return (\n <PageLayout\n title=\"Offers\"\n description=\"Track the offers you have made and respond to offers on your listings\"\n purpose=\"Every offer in one place: watch its status move from submitted to countered, accepted, or rejected — withdraw one you no longer want, or respond to offers coming in on properties you own.\"\n >\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <StatCard label=\"Total offers\" value={allOffers.length} icon={<Tag className=\"h-4 w-4\" />} />\n <StatCard label=\"Awaiting action\" value={activeCount} icon={<Repeat className=\"h-4 w-4\" />} />\n <StatCard label=\"Accepted\" value={acceptedCount} icon={<Check className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n <div className=\"-mx-1 flex flex-nowrap items-center gap-2 overflow-x-auto px-1 pb-1 sm:flex-wrap sm:overflow-visible\">\n {statusTabs.map((tab) => {\n const count = countFor(tab.value);\n const isActive = activeTab === tab.value;\n return (\n <button\n key={tab.value}\n onClick={() => {\n setActiveTab(tab.value);\n pagination.setPage(1);\n }}\n className={cn(\n 'inline-flex shrink-0 items-center gap-1.5 rounded-full px-3 py-1.5 text-sm font-medium transition-colors',\n isActive\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.label}\n <span\n className={cn(\n 'inline-flex min-w-5 items-center justify-center rounded-full px-1.5 text-[0.65rem] font-semibold tabular-nums',\n isActive ? 'bg-action-primary-text/20 text-action-primary-text' : 'bg-bg-surface text-text-secondary'\n )}\n >\n {count}\n </span>\n </button>\n );\n })}\n </div>\n\n {offers.length === 0 && !loading ? (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Tag className=\"h-12 w-12\" />}\n title=\"No offers here\"\n description=\"Offers you submit on properties — and offers made on your listings — will appear here.\"\n action={<Button onClick={() => navigate('../properties')}>Browse properties</Button>}\n />\n ) : (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-1 gap-4 xl:grid-cols-2\">\n {offers.map((offer) => {\n const image = offer.property?.images.find((img) => img.isPrimary) ?? offer.property?.images[0];\n const canAct = offer.status === 'submitted' || offer.status === 'countered';\n return (\n <GlassCard\n key={offer.id}\n treatment={canAct ? 'insight' : 'plain'}\n glow={canAct}\n className=\"flex flex-col gap-4 p-5\"\n >\n <div className=\"flex items-start gap-3\">\n <button\n type=\"button\"\n onClick={() => offer.property && navigate(`../properties/${offer.property.id}`)}\n className=\"shrink-0\"\n aria-label={`Open ${offer.property?.title ?? 'property'}`}\n >\n {image ? (\n <img src={image.url} alt=\"\" className=\"h-16 w-16 rounded-lg object-cover\" />\n ) : (\n <div className=\"flex h-16 w-16 items-center justify-center rounded-lg bg-bg-sunken\">\n <Home className=\"h-6 w-6 text-text-secondary\" />\n </div>\n )}\n </button>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <button\n type=\"button\"\n onClick={() => offer.property && navigate(`../properties/${offer.property.id}`)}\n className=\"text-left\"\n >\n <h3 className=\"font-semibold text-text-primary hover:text-primary\">\n {offer.property?.title ?? 'Property'}\n </h3>\n {offer.property && (\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <MapPin className=\"h-3 w-3\" />\n {offer.property.location.city}, {offer.property.location.state}\n </p>\n )}\n </button>\n <StatusBadge label={offer.status} variant={statusVariant(offer.status)} dot />\n </div>\n <div className=\"mt-2 flex items-baseline gap-3\">\n <span className=\"text-xl font-bold tabular-nums text-text-primary\">\n {formatCurrency(offer.amount, offer.currency)}\n </span>\n {offer.counterAmount != null && (\n <span className=\"text-sm text-text-secondary\">\n Counter{' '}\n <span className=\"font-semibold text-status-warning-text\">\n {formatCurrency(offer.counterAmount, offer.currency)}\n </span>\n </span>\n )}\n </div>\n <p className=\"mt-0.5 text-xs text-text-secondary\">Submitted {formatDate(offer.createdAt)}</p>\n {(offer.status === 'submitted' || offer.status === 'countered') && offer.expiresAt && (\n <p className=\"mt-0.5 text-xs text-text-secondary\">Expires {formatDate(offer.expiresAt)}</p>\n )}\n </div>\n </div>\n\n <div className=\"rounded-lg bg-bg-sunken/50 p-3\">\n <OfferTimeline offer={offer} />\n </div>\n\n {(canAct || offer.property) && (\n <div className=\"flex flex-wrap gap-2\">\n {canAct && (\n <Button size=\"sm\" onClick={() => openRespond(offer)}>\n <Check className=\"h-4 w-4\" />\n <span className=\"ml-1\">Respond</span>\n </Button>\n )}\n {canAct && (\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled={withdrawing}\n onClick={() => handleWithdraw(offer)}\n >\n <Undo2 className=\"h-4 w-4\" />\n <span className=\"ml-1\">Withdraw</span>\n </Button>\n )}\n {offer.property && (\n <Button variant=\"ghost\" size=\"sm\" onClick={() => setMessageTarget(offer)}>\n <MessageSquare className=\"h-4 w-4\" />\n <span className=\"ml-1\">Message</span>\n </Button>\n )}\n {offer.property && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={() => navigate(`../properties/${offer.property?.id}`)}\n >\n <span>View property</span>\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n )}\n </div>\n )}\n </GlassCard>\n );\n })}\n </div>\n\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={offers.length >= pagination.pageSize}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </div>\n )}\n\n {/* Message the other party about this offer — the conversation thread is\n property-scoped (ContactOwnerDialog), the same thread both parties\n already reach from the property detail page; keyed by property id so\n switching offers never reuses a stale conversation (BOFF-8220). */}\n {messageTarget?.property && (\n <ContactOwnerDialog\n key={messageTarget.property.id}\n open={messageTarget !== null}\n onOpenChange={(open) => !open && setMessageTarget(null)}\n entityId={messageTarget.property.id}\n entityType=\"housingvista-property\"\n title={messageTarget.property.title}\n pagePath=\"/housingvista/offers\"\n heading=\"Message\"\n description={`Discuss ${messageTarget.property.title} with the other party. The thread also appears in Messages.`}\n />\n )}\n\n {/* Respond to offer */}\n <ResponsiveDialog open={respondTarget !== null} onOpenChange={(open) => !open && setRespondTarget(null)}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleRespond}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Respond to offer</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {respondTarget?.property?.title\n ? `Offer of ${formatCurrency(respondTarget.amount, respondTarget.currency)} on ${respondTarget.property.title}.`\n : 'Accept, counter, or reject this offer.'}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div className=\"flex flex-wrap gap-2\">\n {(['accept', 'counter', 'reject'] as const).map((value) => (\n <button\n key={value}\n type=\"button\"\n onClick={() => setAction(value)}\n className={cn(\n 'inline-flex items-center gap-1 rounded-md px-3 py-1.5 text-sm font-medium capitalize transition-colors',\n action === value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {value === 'accept' && <Check className=\"h-4 w-4\" />}\n {value === 'counter' && <Repeat className=\"h-4 w-4\" />}\n {value === 'reject' && <X className=\"h-4 w-4\" />}\n {value}\n </button>\n ))}\n </div>\n {action === 'counter' && (\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Counter amount *</label>\n <input\n type=\"number\"\n min={1}\n step=\"any\"\n value={counterAmount}\n onChange={(event) => setCounterAmount(event.target.value)}\n className={inputClass}\n />\n </div>\n )}\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Note (optional)</label>\n <textarea\n value={notes}\n onChange={(event) => setNotes(event.target.value)}\n rows={2}\n className=\"w-full 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 </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setRespondTarget(null)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={responding}>\n {responding ? 'Sending…' : 'Send response'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-housingvista",
3
- "version": "2026.930.2",
3
+ "version": "2026.1001.1",
4
4
  "description": "Burdenoff HousingVista Microfrontend - Comprehensive real estate platform for property management, investment, and transactions",
5
5
  "type": "module",
6
6
  "files": [