@burdenoff/microfe-housingvista 2026.703.7 → 2026.703.9

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,65 +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, trigger: C, heading: w = "Contact", description: T }) => {
12
- let { currentUser: E } = e(), { openConversation: D, loading: O } = n(), { sendMessage: k, loading: A } = i(), [j, M] = c(!1), [N, P] = c(), [F, I] = c(""), { data: L, loading: R } = r(N), z = 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 }) => {
13
+ let { currentUser: k } = e(), { openConversation: A, loading: j } = n(), { sendMessage: M, loading: N } = i(), [P, F] = c(!1), [I, L] = c(), [R, z] = c(""), { data: B, loading: V } = r(I), H = s(null);
13
14
  o(() => {
14
- if (!j || N) return;
15
+ if (!P || I) return;
15
16
  let e = !1;
16
- return D({
17
- entityId: y,
18
- entityType: b,
19
- title: x,
20
- contextHref: S,
21
- pagePath: S
17
+ return A({
18
+ entityId: b,
19
+ entityType: x,
20
+ title: S,
21
+ contextHref: C,
22
+ pagePath: C
22
23
  }).then((t) => {
23
- e || P(t.id);
24
+ e || L(t.id);
24
25
  }).catch((e) => a.error("Could not open the conversation", e.message)), () => {
25
26
  e = !0;
26
27
  };
27
28
  }, [
28
- j,
29
- N,
30
- D,
31
- y,
29
+ P,
30
+ I,
31
+ A,
32
32
  b,
33
33
  x,
34
- S
34
+ S,
35
+ C
35
36
  ]), o(() => {
36
- z.current?.scrollTo({ top: z.current.scrollHeight });
37
- }, [L]);
38
- let B = async () => {
39
- let e = F.trim();
40
- if (!(!e || !N)) try {
41
- await k(N, e), I("");
37
+ H.current?.scrollTo({ top: H.current.scrollHeight });
38
+ }, [B]);
39
+ let U = async () => {
40
+ let e = R.trim();
41
+ if (!(!e || !I)) try {
42
+ await M(I, e), z("");
42
43
  } catch (e) {
43
44
  a.error("Message not sent", e.message);
44
45
  }
45
- }, V = E?.id ?? "";
46
- return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("span", {
47
- className: "contents",
48
- role: "presentation",
49
- onClick: () => M(!0),
50
- children: C
51
- }), /* @__PURE__ */ d(m, {
52
- open: j,
53
- onOpenChange: M,
46
+ }, W = k?.id ?? "";
47
+ return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(p, {
48
+ type: "button",
49
+ variant: T,
50
+ className: E,
51
+ onClick: () => F(!0),
52
+ children: w
53
+ }), y(/* @__PURE__ */ d(m, {
54
+ open: P,
55
+ onOpenChange: F,
54
56
  children: /* @__PURE__ */ f(h, {
55
57
  className: "sm:max-w-lg",
56
58
  children: [
57
- /* @__PURE__ */ f(_, { children: [/* @__PURE__ */ d(v, { children: w }), /* @__PURE__ */ d(g, { children: T ?? `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.` })] }),
58
60
  /* @__PURE__ */ d("div", {
59
- ref: z,
61
+ ref: H,
60
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",
61
- children: O || R ? /* @__PURE__ */ d("p", {
63
+ children: j || V ? /* @__PURE__ */ d("p", {
62
64
  className: "py-8 text-center text-sm text-text-secondary",
63
65
  children: "Loading conversation…"
64
- }) : L.length === 0 ? /* @__PURE__ */ d("p", {
66
+ }) : B.length === 0 ? /* @__PURE__ */ d("p", {
65
67
  className: "py-8 text-center text-sm text-text-secondary",
66
68
  children: "No messages yet. Say hello to get the conversation started."
67
- }) : L.map((e) => {
68
- let n = e.authorId === V;
69
+ }) : B.map((e) => {
70
+ let n = e.authorId === W;
69
71
  return /* @__PURE__ */ d("div", {
70
72
  className: t("flex", n ? "justify-end" : "justify-start"),
71
73
  children: /* @__PURE__ */ d("div", {
@@ -78,18 +80,18 @@ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, trigger: C, headin
78
80
  /* @__PURE__ */ f("div", {
79
81
  className: "mt-3 flex items-end gap-2",
80
82
  children: [/* @__PURE__ */ d("textarea", {
81
- value: F,
82
- onChange: (e) => I(e.target.value),
83
+ value: R,
84
+ onChange: (e) => z(e.target.value),
83
85
  onKeyDown: (e) => {
84
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), B());
86
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), U());
85
87
  },
86
88
  rows: 2,
87
89
  placeholder: "Write a message…",
88
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)]"
89
91
  }), /* @__PURE__ */ f(p, {
90
92
  type: "button",
91
- onClick: B,
92
- disabled: !F.trim() || !N || A,
93
+ onClick: U,
94
+ disabled: !R.trim() || !I || N,
93
95
  children: [/* @__PURE__ */ d(l, { className: "h-4 w-4" }), /* @__PURE__ */ d("span", {
94
96
  className: "ml-1",
95
97
  children: "Send"
@@ -98,9 +100,9 @@ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, trigger: C, headin
98
100
  })
99
101
  ]
100
102
  })
101
- })] });
103
+ }), document.body)] });
102
104
  };
103
105
  //#endregion
104
- export { y as ContactOwnerDialog };
106
+ export { b as ContactOwnerDialog };
105
107
 
106
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 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 /** Clickable trigger element (button/link). */\n trigger: ReactNode;\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 trigger,\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 caller's trigger inside a display:contents wrapper that opens the\n // dialog on click. A DOM-level onClick on the wrapper reliably catches the\n // bubbled click from the inner button — neither ResponsiveDialogTrigger's\n // asChild slot nor cloneElement forwarded the click through the fe-libs Button\n // in production.\n const openTrigger = (\n <span className=\"contents\" role=\"presentation\" onClick={() => setOpen(true)}>\n {trigger}\n </span>\n );\n\n return (\n <>\n {openTrigger}\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":";;;;;;;;;;AAuCA,IAAa,KAAmD,EAC9D,aACA,eACA,UACA,aACA,YACA,aAAU,WACV,qBACI;CACJ,IAAM,EAAE,mBAAgB,GAAiB,EACnC,EAAE,qBAAkB,SAAS,MAAY,GAAwB,EACjE,EAAE,gBAAa,SAAS,MAAY,GAAgB,EACpD,CAAC,GAAM,KAAW,EAAS,GAAM,EACjC,CAAC,GAAgB,KAAqB,GAA8B,EACpE,CAAC,GAAO,KAAY,EAAS,GAAG,EAChC,EAAE,MAAM,GAAU,SAAS,MAAoB,EAAwB,EAAe,EACtF,IAAY,EAAuB,KAAK;AAsB9C,CAnBA,QAAgB;AACd,MAAI,CAAC,KAAQ,EAAgB;EAC7B,IAAI,IAAY;AAYhB,SAXA,EAAiB;GACf;GACA;GACA;GACA,aAAa;GACb;GACD,CAAC,CACC,MAAM,MAAQ;AACb,GAAK,KAAW,EAAkB,EAAI,GAAG;IACzC,CACD,OAAO,MAAe,EAAO,MAAM,mCAAmC,EAAI,QAAQ,CAAC,QACzE;AACX,OAAY;;IAEb;EAAC;EAAM;EAAgB;EAAkB;EAAU;EAAY;EAAO;EAAS,CAAC,EAEnF,QAAgB;AACd,IAAU,SAAS,SAAS,EAAE,KAAK,EAAU,QAAQ,cAAc,CAAC;IACnE,CAAC,EAAS,CAAC;CAEd,IAAM,IAAa,YAAY;EAC7B,IAAM,IAAO,EAAM,MAAM;AACrB,SAAC,KAAQ,CAAC,GACd,KAAI;AAEF,GADA,MAAM,EAAY,GAAgB,EAAK,EACvC,EAAS,GAAG;WACL,GAAK;AACZ,KAAO,MAAM,oBAAqB,EAAc,QAAQ;;IAItD,IAAgB,GAAa,MAAM;AAazC,QACE,kBAAA,GAAA,EAAA,UAAA,CANA,kBAAC,QAAD;EAAM,WAAU;EAAW,MAAK;EAAe,eAAe,EAAQ,GAAK;YACxE;EACI,CAAA,EAML,kBAAC,GAAD;EAAwB;EAAM,cAAc;YAC1C,kBAAC,GAAD;GAAyB,WAAU;aAAnC;IACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAwB,GAAgC,CAAA,EACxD,kBAAC,GAAD,EAAA,UACG,KAAe,8BAA8B,EAAM,oDACxB,CAAA,CACP,EAAA,CAAA;IAEzB,kBAAC,OAAD;KACE,KAAK;KACL,WAAU;eAET,KAAW,IACV,kBAAC,KAAD;MAAG,WAAU;gBAA+C;MAAyB,CAAA,GACnF,EAAS,WAAW,IACtB,kBAAC,KAAD;MAAG,WAAU;gBAA+C;MAExD,CAAA,GAEJ,EAAS,KAAK,MAAY;MACxB,IAAM,IAAO,EAAQ,aAAa;AAClC,aACE,kBAAC,OAAD;OAAsB,WAAW,EAAG,QAAQ,IAAO,gBAAgB,gBAAgB;iBACjF,kBAAC,OAAD;QACE,WAAW,EACT,4CACA,IACI,kDACA,8DACL;kBAEA,EAAQ;QACL,CAAA;OACF,EAXI,EAAQ,GAWZ;OAER;KAEA,CAAA;IAEN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,YAAD;MACE,OAAO;MACP,WAAW,MAAU,EAAS,EAAM,OAAO,MAAM;MACjD,YAAY,MAAU;AACpB,OAAI,EAAM,QAAQ,WAAW,CAAC,EAAM,aAClC,EAAM,gBAAgB,EACjB,GAAY;;MAGrB,MAAM;MACN,aAAY;MACZ,WAAU;MACV,CAAA,EACF,kBAAC,GAAD;MAAQ,MAAK;MAAS,SAAS;MAAY,UAAU,CAAC,EAAM,MAAM,IAAI,CAAC,KAAkB;gBAAzF,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC5B,kBAAC,QAAD;OAAM,WAAU;iBAAO;OAAW,CAAA,CAC3B;QACL;;IACkB;;EACT,CAAA,CAClB,EAAA,CAAA"}
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). */\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 type=\"button\" variant={triggerVariant} className={triggerClassName} onClick={() => setOpen(true)}>\n {triggerContent}\n </Button>\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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"}
@@ -10,30 +10,30 @@ import { useMemo as c, useState as l } from "react";
10
10
  import { ArrowLeft as u, Building2 as d, Calculator as f, CalendarClock as p, CheckCircle as m, Gift as h, Percent as g, Star as _, Wallet as v } from "lucide-react";
11
11
  import { useLocation as y, useNavigate as b, useParams as x } from "react-router-dom";
12
12
  import { jsx as S, jsxs as C } from "react/jsx-runtime";
13
- import { Button as w, EmphasisPanel as T, GlassCard as E, PagePurpose as D } from "@burdenoff/fe-libs/ui";
13
+ import { EmphasisPanel as w, GlassCard as T, PagePurpose as E } from "@burdenoff/fe-libs/ui";
14
14
  //#region src/housingvista/pages/finance/HomeLoanDetailPage.tsx
15
- function O(e, t, n) {
15
+ function D(e, t, n) {
16
16
  if (e <= 0 || t <= 0 || n <= 0) return 0;
17
17
  let r = t / 12 / 100, i = n * 12, a = e * r * (1 + r) ** +i / ((1 + r) ** +i - 1);
18
18
  return Math.round(a);
19
19
  }
20
- function k({ rating: t }) {
20
+ function O({ rating: t }) {
21
21
  return /* @__PURE__ */ S("div", {
22
22
  className: "flex items-center gap-0.5",
23
23
  children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ S(_, { className: e("h-4 w-4", r < Math.floor(t) ? "fill-status-warning text-status-warning" : "text-text-secondary/30") }, r))
24
24
  });
25
25
  }
26
- function A() {
27
- let { id: _ } = x(), A = b(), j = y(), { data: M, loading: N } = o(_), [P, F] = l(5e5), [I, L] = l(20), R = M?.interestRate ?? 0, z = c(() => O(P, R, I), [
28
- P,
29
- R,
30
- I
31
- ]), B = z * I * 12, V = B - P;
32
- if (N) return /* @__PURE__ */ S("div", {
26
+ function k() {
27
+ let { id: _ } = x(), k = b(), A = y(), { data: j, loading: M } = o(_), [N, P] = l(5e5), [F, I] = l(20), L = j?.interestRate ?? 0, R = c(() => D(N, L, F), [
28
+ N,
29
+ L,
30
+ F
31
+ ]), z = R * F * 12, B = z - N;
32
+ if (M) return /* @__PURE__ */ S("div", {
33
33
  className: "p-6",
34
34
  children: /* @__PURE__ */ S(a, { variant: "detail" })
35
35
  });
36
- if (!M) return /* @__PURE__ */ S("div", {
36
+ if (!j) return /* @__PURE__ */ S("div", {
37
37
  className: "p-6",
38
38
  children: /* @__PURE__ */ S(r, {
39
39
  illustration: "empty-data",
@@ -41,20 +41,20 @@ function A() {
41
41
  title: "Loan Offer Not Found",
42
42
  description: "The loan offer you're looking for doesn't exist or is no longer available.",
43
43
  action: /* @__PURE__ */ C("button", {
44
- onClick: () => A("../home-loans"),
44
+ onClick: () => k("../home-loans"),
45
45
  className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover",
46
46
  children: [/* @__PURE__ */ S(u, { className: "h-4 w-4" }), "Back to Home Loans"]
47
47
  })
48
48
  })
49
49
  });
50
- let H = M.features ?? [];
50
+ let V = j.features ?? [];
51
51
  return /* @__PURE__ */ C("div", {
52
52
  className: "flex flex-col gap-6 p-6",
53
53
  children: [
54
54
  /* @__PURE__ */ S(i, { items: [{
55
55
  label: "Home Loans",
56
56
  href: "../"
57
- }, { label: M.bankName }] }),
57
+ }, { label: j.bankName }] }),
58
58
  /* @__PURE__ */ C("div", {
59
59
  className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",
60
60
  children: [/* @__PURE__ */ C("div", {
@@ -64,54 +64,52 @@ function A() {
64
64
  children: /* @__PURE__ */ S(d, { className: "h-6 w-6" })
65
65
  }), /* @__PURE__ */ C("div", { children: [
66
66
  /* @__PURE__ */ C("button", {
67
- onClick: () => A("../home-loans"),
67
+ onClick: () => k("../home-loans"),
68
68
  className: "mb-2 inline-flex items-center gap-2 rounded-md px-2 py-1 text-sm text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary",
69
69
  children: [/* @__PURE__ */ S(u, { className: "h-4 w-4" }), "Back to Home Loans"]
70
70
  }),
71
71
  /* @__PURE__ */ S("h1", {
72
72
  className: "text-2xl font-semibold text-text-primary",
73
- children: M.bankName
73
+ children: j.bankName
74
74
  }),
75
75
  /* @__PURE__ */ C("div", {
76
76
  className: "mt-2 flex flex-wrap items-center gap-2",
77
- children: [M.rating != null && /* @__PURE__ */ C("span", {
77
+ children: [j.rating != null && /* @__PURE__ */ C("span", {
78
78
  className: "inline-flex items-center gap-1.5",
79
- children: [/* @__PURE__ */ S(k, { rating: M.rating }), /* @__PURE__ */ S("span", {
79
+ children: [/* @__PURE__ */ S(O, { rating: j.rating }), /* @__PURE__ */ S("span", {
80
80
  className: "text-sm text-text-secondary",
81
- children: M.rating
81
+ children: j.rating
82
82
  })]
83
- }), M.specialOffer && /* @__PURE__ */ S(n, {
83
+ }), j.specialOffer && /* @__PURE__ */ S(n, {
84
84
  label: "Special Offer",
85
85
  variant: "warning"
86
86
  })]
87
87
  })
88
88
  ] })]
89
89
  }), /* @__PURE__ */ S(s, {
90
- entityId: M.id,
90
+ entityId: j.id,
91
91
  entityType: "housingvista-home-loan",
92
- title: M.bankName,
93
- pagePath: j.pathname,
94
- heading: `Apply with ${M.bankName}`,
95
- description: `Start your application with ${M.bankName}. Messages are saved and delivered in your inbox.`,
96
- trigger: /* @__PURE__ */ S(w, {
97
- type: "button",
98
- children: "Apply Now"
99
- })
92
+ title: j.bankName,
93
+ pagePath: A.pathname,
94
+ heading: `Apply with ${j.bankName}`,
95
+ description: `Start your application with ${j.bankName}. Messages are saved and delivered in your inbox.`,
96
+ triggerVariant: "default",
97
+ triggerContent: "Apply Now"
100
98
  })]
101
99
  }),
102
- /* @__PURE__ */ C(D, {
100
+ /* @__PURE__ */ C(E, {
103
101
  className: "max-w-3xl",
104
102
  children: [
105
103
  "The full terms of this offer with a live EMI estimate at the bank's headline rate. Model your loan amount and tenure to see the real monthly cost, then apply to connect with ",
106
- M.bankName,
104
+ j.bankName,
107
105
  " through Messages."
108
106
  ]
109
107
  }),
110
- M.specialOffer && /* @__PURE__ */ C("div", {
108
+ j.specialOffer && /* @__PURE__ */ C("div", {
111
109
  className: "flex items-center gap-2 rounded-lg bg-status-warning-bg-subtle p-3 text-sm text-status-warning-text",
112
- children: [/* @__PURE__ */ S(h, { className: "h-4 w-4 shrink-0" }), M.specialOffer]
110
+ children: [/* @__PURE__ */ S(h, { className: "h-4 w-4 shrink-0" }), j.specialOffer]
113
111
  }),
114
- /* @__PURE__ */ C(T, {
112
+ /* @__PURE__ */ C(w, {
115
113
  className: "p-5",
116
114
  children: [/* @__PURE__ */ C("div", {
117
115
  className: "mb-4 flex items-center gap-2",
@@ -119,7 +117,7 @@ function A() {
119
117
  className: "text-lg font-semibold text-text-primary",
120
118
  children: [
121
119
  "EMI Estimate at ",
122
- M.interestRate,
120
+ j.interestRate,
123
121
  "%"
124
122
  ]
125
123
  })]
@@ -135,21 +133,21 @@ function A() {
135
133
  children: "Loan Amount"
136
134
  }), /* @__PURE__ */ S("span", {
137
135
  className: "text-sm font-semibold text-text-primary",
138
- children: t(P)
136
+ children: t(N)
139
137
  })]
140
138
  }),
141
139
  /* @__PURE__ */ S("input", {
142
140
  type: "range",
143
141
  min: 5e4,
144
- max: Math.max(M.maxAmount, 1e5),
142
+ max: Math.max(j.maxAmount, 1e5),
145
143
  step: 1e4,
146
- value: Math.min(P, M.maxAmount),
147
- onChange: (e) => F(Number(e.target.value)),
144
+ value: Math.min(N, j.maxAmount),
145
+ onChange: (e) => P(Number(e.target.value)),
148
146
  className: "w-full accent-foreground"
149
147
  }),
150
148
  /* @__PURE__ */ C("div", {
151
149
  className: "mt-1 flex justify-between text-xs text-text-secondary",
152
- children: [/* @__PURE__ */ S("span", { children: "$50K" }), /* @__PURE__ */ C("span", { children: ["Max ", t(M.maxAmount)] })]
150
+ children: [/* @__PURE__ */ S("span", { children: "$50K" }), /* @__PURE__ */ C("span", { children: ["Max ", t(j.maxAmount)] })]
153
151
  })
154
152
  ] }), /* @__PURE__ */ C("div", { children: [
155
153
  /* @__PURE__ */ C("div", {
@@ -159,23 +157,23 @@ function A() {
159
157
  children: "Tenure (years)"
160
158
  }), /* @__PURE__ */ C("span", {
161
159
  className: "text-sm font-semibold text-text-primary",
162
- children: [I, " years"]
160
+ children: [F, " years"]
163
161
  })]
164
162
  }),
165
163
  /* @__PURE__ */ S("input", {
166
164
  type: "range",
167
165
  min: 1,
168
- max: M.maxTenure,
166
+ max: j.maxTenure,
169
167
  step: 1,
170
- value: Math.min(I, M.maxTenure),
171
- onChange: (e) => L(Number(e.target.value)),
168
+ value: Math.min(F, j.maxTenure),
169
+ onChange: (e) => I(Number(e.target.value)),
172
170
  className: "w-full accent-foreground"
173
171
  }),
174
172
  /* @__PURE__ */ C("div", {
175
173
  className: "mt-1 flex justify-between text-xs text-text-secondary",
176
174
  children: [/* @__PURE__ */ S("span", { children: "1 yr" }), /* @__PURE__ */ C("span", { children: [
177
175
  "Max ",
178
- M.maxTenure,
176
+ j.maxTenure,
179
177
  " yrs"
180
178
  ] })]
181
179
  })
@@ -189,7 +187,7 @@ function A() {
189
187
  }),
190
188
  /* @__PURE__ */ S("p", {
191
189
  className: "my-2 text-4xl font-bold text-text-primary",
192
- children: t(z)
190
+ children: t(R)
193
191
  }),
194
192
  /* @__PURE__ */ C("div", {
195
193
  className: "mt-4 grid w-full grid-cols-2 gap-4",
@@ -200,7 +198,7 @@ function A() {
200
198
  children: "Total Payment"
201
199
  }), /* @__PURE__ */ S("p", {
202
200
  className: "text-sm font-semibold text-text-primary",
203
- children: t(B)
201
+ children: t(z)
204
202
  })]
205
203
  }), /* @__PURE__ */ C("div", {
206
204
  className: "text-center",
@@ -209,7 +207,7 @@ function A() {
209
207
  children: "Total Interest"
210
208
  }), /* @__PURE__ */ S("p", {
211
209
  className: "text-sm font-semibold text-status-error-text",
212
- children: t(V)
210
+ children: t(B)
213
211
  })]
214
212
  })]
215
213
  })
@@ -221,7 +219,7 @@ function A() {
221
219
  className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
222
220
  children: [/* @__PURE__ */ C("div", {
223
221
  className: "space-y-6 lg:col-span-2",
224
- children: [/* @__PURE__ */ C(E, {
222
+ children: [/* @__PURE__ */ C(T, {
225
223
  treatment: "plain",
226
224
  className: "border-border-seam p-6",
227
225
  children: [/* @__PURE__ */ S("h2", {
@@ -237,7 +235,7 @@ function A() {
237
235
  children: [/* @__PURE__ */ S(g, { className: "h-3.5 w-3.5" }), "Interest Rate"]
238
236
  }), /* @__PURE__ */ C("div", {
239
237
  className: "mt-1 text-lg font-bold text-text-primary",
240
- children: [M.interestRate, "%"]
238
+ children: [j.interestRate, "%"]
241
239
  })]
242
240
  }),
243
241
  /* @__PURE__ */ C("div", {
@@ -247,7 +245,7 @@ function A() {
247
245
  children: [/* @__PURE__ */ S(v, { className: "h-3.5 w-3.5" }), "EMI / Lakh"]
248
246
  }), /* @__PURE__ */ S("div", {
249
247
  className: "mt-1 text-lg font-bold text-text-primary",
250
- children: M.emiPerLakh == null ? "—" : `$${M.emiPerLakh}`
248
+ children: j.emiPerLakh == null ? "—" : `$${j.emiPerLakh}`
251
249
  })]
252
250
  }),
253
251
  /* @__PURE__ */ C("div", {
@@ -257,7 +255,7 @@ function A() {
257
255
  children: [/* @__PURE__ */ S(p, { className: "h-3.5 w-3.5" }), "Max Tenure"]
258
256
  }), /* @__PURE__ */ C("div", {
259
257
  className: "mt-1 text-lg font-bold text-text-primary",
260
- children: [M.maxTenure, " yrs"]
258
+ children: [j.maxTenure, " yrs"]
261
259
  })]
262
260
  }),
263
261
  /* @__PURE__ */ C("div", {
@@ -267,7 +265,7 @@ function A() {
267
265
  children: "Max Amount"
268
266
  }), /* @__PURE__ */ S("div", {
269
267
  className: "mt-1 text-sm font-semibold text-text-primary",
270
- children: t(M.maxAmount)
268
+ children: t(j.maxAmount)
271
269
  })]
272
270
  }),
273
271
  /* @__PURE__ */ C("div", {
@@ -277,7 +275,7 @@ function A() {
277
275
  children: "Processing Fee"
278
276
  }), /* @__PURE__ */ S("div", {
279
277
  className: "mt-1 text-sm font-semibold text-text-primary",
280
- children: M.processingFee ?? "—"
278
+ children: j.processingFee ?? "—"
281
279
  })]
282
280
  }),
283
281
  /* @__PURE__ */ C("div", {
@@ -286,13 +284,13 @@ function A() {
286
284
  className: "text-xs text-text-secondary",
287
285
  children: "Prepayment"
288
286
  }), /* @__PURE__ */ S("div", {
289
- className: e("mt-1 text-sm font-semibold", M.prepaymentCharges === "None" ? "text-status-success-text" : "text-text-primary"),
290
- children: M.prepaymentCharges ?? "—"
287
+ className: e("mt-1 text-sm font-semibold", j.prepaymentCharges === "None" ? "text-status-success-text" : "text-text-primary"),
288
+ children: j.prepaymentCharges ?? "—"
291
289
  })]
292
290
  })
293
291
  ]
294
292
  })]
295
- }), H.length > 0 && /* @__PURE__ */ C(E, {
293
+ }), V.length > 0 && /* @__PURE__ */ C(T, {
296
294
  treatment: "plain",
297
295
  className: "border-border-seam p-6",
298
296
  children: [/* @__PURE__ */ S("h2", {
@@ -300,7 +298,7 @@ function A() {
300
298
  children: "Features"
301
299
  }), /* @__PURE__ */ S("ul", {
302
300
  className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
303
- children: H.map((e, t) => /* @__PURE__ */ C("li", {
301
+ children: V.map((e, t) => /* @__PURE__ */ C("li", {
304
302
  className: "flex items-center gap-2 text-sm text-text-secondary",
305
303
  children: [/* @__PURE__ */ S(m, { className: "h-4 w-4 shrink-0 text-status-success-text" }), e]
306
304
  }, t))
@@ -308,7 +306,7 @@ function A() {
308
306
  })]
309
307
  }), /* @__PURE__ */ S("div", {
310
308
  className: "space-y-6",
311
- children: /* @__PURE__ */ C(E, {
309
+ children: /* @__PURE__ */ C(T, {
312
310
  treatment: "plain",
313
311
  className: "border-border-seam p-5",
314
312
  children: [
@@ -320,22 +318,20 @@ function A() {
320
318
  className: "mb-4 text-sm text-text-secondary",
321
319
  children: [
322
320
  "Applications are handled directly with ",
323
- M.bankName,
321
+ j.bankName,
324
322
  " through HousingVista Messages. Start an enquiry and the bank will guide you through eligibility and paperwork."
325
323
  ]
326
324
  }),
327
325
  /* @__PURE__ */ S(s, {
328
- entityId: M.id,
326
+ entityId: j.id,
329
327
  entityType: "housingvista-home-loan",
330
- title: M.bankName,
331
- pagePath: j.pathname,
332
- heading: `Apply with ${M.bankName}`,
333
- description: `Start your application with ${M.bankName}. Messages are saved and delivered in your inbox.`,
334
- trigger: /* @__PURE__ */ S(w, {
335
- type: "button",
336
- className: "w-full justify-center",
337
- children: "Apply Now"
338
- })
328
+ title: j.bankName,
329
+ pagePath: A.pathname,
330
+ heading: `Apply with ${j.bankName}`,
331
+ description: `Start your application with ${j.bankName}. Messages are saved and delivered in your inbox.`,
332
+ triggerVariant: "default",
333
+ triggerClassName: "w-full justify-center",
334
+ triggerContent: "Apply Now"
339
335
  })
340
336
  ]
341
337
  })
@@ -345,6 +341,6 @@ function A() {
345
341
  });
346
342
  }
347
343
  //#endregion
348
- export { A as HomeLoanDetailPage };
344
+ export { k as HomeLoanDetailPage };
349
345
 
350
346
  //# sourceMappingURL=HomeLoanDetailPage.js.map