@burdenoff/microfe-housingvista 2026.703.6 → 2026.703.8

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.
@@ -8,64 +8,65 @@ 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
10
  //#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);
11
+ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, triggerContent: C, triggerVariant: w = "outline", triggerClassName: T, heading: E = "Contact", description: D }) => {
12
+ let { currentUser: O } = e(), { openConversation: k, loading: A } = n(), { sendMessage: j, loading: M } = i(), [N, P] = c(!1), [F, I] = c(), [L, R] = c(""), { data: z, loading: B } = r(F), V = s(null);
13
13
  o(() => {
14
- if (!j || N) return;
14
+ if (!N || F) return;
15
15
  let e = !1;
16
- return D({
16
+ return k({
17
17
  entityId: y,
18
18
  entityType: b,
19
19
  title: x,
20
20
  contextHref: S,
21
21
  pagePath: S
22
22
  }).then((t) => {
23
- e || P(t.id);
23
+ e || I(t.id);
24
24
  }).catch((e) => a.error("Could not open the conversation", e.message)), () => {
25
25
  e = !0;
26
26
  };
27
27
  }, [
28
- j,
29
28
  N,
30
- D,
29
+ F,
30
+ k,
31
31
  y,
32
32
  b,
33
33
  x,
34
34
  S
35
35
  ]), 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("");
36
+ V.current?.scrollTo({ top: V.current.scrollHeight });
37
+ }, [z]);
38
+ let H = async () => {
39
+ let e = L.trim();
40
+ if (!(!e || !F)) try {
41
+ await j(F, e), R("");
42
42
  } catch (e) {
43
43
  a.error("Message not sent", e.message);
44
44
  }
45
- }, V = E?.id ?? "";
46
- return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d("span", {
47
- className: "contents",
48
- role: "presentation",
49
- onClick: () => M(!0),
45
+ }, U = O?.id ?? "";
46
+ return /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ d(p, {
47
+ type: "button",
48
+ variant: w,
49
+ className: T,
50
+ onClick: () => P(!0),
50
51
  children: C
51
52
  }), /* @__PURE__ */ d(m, {
52
- open: j,
53
- onOpenChange: M,
53
+ open: N,
54
+ onOpenChange: P,
54
55
  children: /* @__PURE__ */ f(h, {
55
56
  className: "sm:max-w-lg",
56
57
  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.` })] }),
58
+ /* @__PURE__ */ f(_, { children: [/* @__PURE__ */ d(v, { children: E }), /* @__PURE__ */ d(g, { children: D ?? `Start a conversation about ${x}. Messages are saved and delivered in your inbox.` })] }),
58
59
  /* @__PURE__ */ d("div", {
59
- ref: z,
60
+ ref: V,
60
61
  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", {
62
+ children: A || B ? /* @__PURE__ */ d("p", {
62
63
  className: "py-8 text-center text-sm text-text-secondary",
63
64
  children: "Loading conversation…"
64
- }) : L.length === 0 ? /* @__PURE__ */ d("p", {
65
+ }) : z.length === 0 ? /* @__PURE__ */ d("p", {
65
66
  className: "py-8 text-center text-sm text-text-secondary",
66
67
  children: "No messages yet. Say hello to get the conversation started."
67
- }) : L.map((e) => {
68
- let n = e.authorId === V;
68
+ }) : z.map((e) => {
69
+ let n = e.authorId === U;
69
70
  return /* @__PURE__ */ d("div", {
70
71
  className: t("flex", n ? "justify-end" : "justify-start"),
71
72
  children: /* @__PURE__ */ d("div", {
@@ -78,18 +79,18 @@ var y = ({ entityId: y, entityType: b, title: x, pagePath: S, trigger: C, headin
78
79
  /* @__PURE__ */ f("div", {
79
80
  className: "mt-3 flex items-end gap-2",
80
81
  children: [/* @__PURE__ */ d("textarea", {
81
- value: F,
82
- onChange: (e) => I(e.target.value),
82
+ value: L,
83
+ onChange: (e) => R(e.target.value),
83
84
  onKeyDown: (e) => {
84
- e.key === "Enter" && !e.shiftKey && (e.preventDefault(), B());
85
+ e.key === "Enter" && !e.shiftKey && (e.preventDefault(), H());
85
86
  },
86
87
  rows: 2,
87
88
  placeholder: "Write a message…",
88
89
  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
90
  }), /* @__PURE__ */ f(p, {
90
91
  type: "button",
91
- onClick: B,
92
- disabled: !F.trim() || !N || A,
92
+ onClick: H,
93
+ disabled: !L.trim() || !F || M,
93
94
  children: [/* @__PURE__ */ d(l, { className: "h-4 w-4" }), /* @__PURE__ */ d("span", {
94
95
  className: "ml-1",
95
96
  children: "Send"
@@ -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 { Send } from 'lucide-react';\nimport {\n Button,\n type ButtonProps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n} from '@burdenoff/fe-libs/ui';\nimport { useContactConversation, useConversationMessages, useSendMessage } from '../hooks';\nimport { useHousingVista } from '../context/HousingVistaContext';\nimport { notify } from '../lib/toast';\nimport { cn } from '../utils/helpers';\n\ninterface ContactOwnerDialogProps {\n /** Stable id of the thing being discussed (property/service/listing id). */\n entityId: string;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string;\n /** Title used when the conversation is first created. */\n title: string;\n /** Router path back into this surface (deep link). */\n pagePath: string;\n /** Inner content of the trigger button (icon + label). */\n triggerContent: ReactNode;\n /** Trigger button variant (defaults to `outline`). */\n triggerVariant?: ButtonProps['variant'];\n /** Extra classes for the trigger button. */\n triggerClassName?: string;\n /** Dialog heading, defaults to \"Contact\". */\n heading?: string;\n description?: string;\n}\n\nexport const ContactOwnerDialog: FC<ContactOwnerDialogProps> = ({\n entityId,\n entityType,\n title,\n pagePath,\n triggerContent,\n triggerVariant = 'outline',\n triggerClassName,\n heading = 'Contact',\n description,\n}) => {\n const { currentUser } = useHousingVista();\n const { openConversation, loading: opening } = useContactConversation();\n const { sendMessage, loading: sending } = useSendMessage();\n const [open, setOpen] = useState(false);\n const [conversationId, setConversationId] = useState<string | undefined>();\n const [draft, setDraft] = useState('');\n const { data: messages, loading: loadingMessages } = useConversationMessages(conversationId);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Resolve the conversation the first time the dialog opens.\n useEffect(() => {\n if (!open || conversationId) return;\n let cancelled = false;\n openConversation({\n entityId,\n entityType,\n title,\n contextHref: pagePath,\n pagePath,\n })\n .then((res) => {\n if (!cancelled) setConversationId(res.id);\n })\n .catch((err: Error) => notify.error('Could not open the conversation', err.message));\n return () => {\n cancelled = true;\n };\n }, [open, conversationId, openConversation, entityId, entityType, title, pagePath]);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages]);\n\n const handleSend = async () => {\n const text = draft.trim();\n if (!text || !conversationId) return;\n try {\n await sendMessage(conversationId, text);\n setDraft('');\n } catch (err) {\n notify.error('Message not sent', (err as Error).message);\n }\n };\n\n const currentUserId = currentUser?.id ?? '';\n\n // Render the trigger as a real Button with a direct onClick — the exact\n // controlled-open pattern the in-page dialogs (e.g. Make Offer) use. Passing a\n // pre-built element through ResponsiveDialogTrigger asChild / cloneElement /\n // a display:contents wrapper all failed to forward the click in production.\n return (\n <>\n <Button\n type=\"button\"\n variant={triggerVariant}\n className={triggerClassName}\n onClick={() => setOpen(true)}\n >\n {triggerContent}\n </Button>\n <ResponsiveDialog open={open} onOpenChange={setOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>{heading}</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {description ?? `Start a conversation about ${title}. Messages are saved and delivered in your inbox.`}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n\n <div\n ref={scrollRef}\n className=\"max-h-72 min-h-40 space-y-2 overflow-y-auto rounded-md border border-border-subtle bg-bg-sunken p-3\"\n >\n {opening || loadingMessages ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">Loading conversation…</p>\n ) : messages.length === 0 ? (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n No messages yet. Say hello to get the conversation started.\n </p>\n ) : (\n messages.map((message) => {\n const mine = message.authorId === currentUserId;\n return (\n <div key={message.id} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>\n <div\n className={cn(\n 'max-w-[80%] rounded-lg px-3 py-2 text-sm',\n mine\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary border border-border-subtle'\n )}\n >\n {message.text}\n </div>\n </div>\n );\n })\n )}\n </div>\n\n <div className=\"mt-3 flex items-end gap-2\">\n <textarea\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n void handleSend();\n }\n }}\n rows={2}\n placeholder=\"Write a message…\"\n className=\"min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <Button type=\"button\" onClick={handleSend} disabled={!draft.trim() || !conversationId || sending}>\n <Send className=\"h-4 w-4\" />\n <span className=\"ml-1\">Send</span>\n </Button>\n </div>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </>\n );\n};\n"],"mappings":"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"}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"HomeLoanDetailPage.js","names":[],"sources":["../../../../src/housingvista/pages/finance/HomeLoanDetailPage.tsx"],"sourcesContent":["/**\n * HousingVista Home Loan Detail / Apply Page\n * Single loan offer backed by `housingvistaHomeLoanOffer(id)` — full terms plus\n * a live EMI summary for the offer's headline rate.\n *\n * \"Apply\" opens the real `ContactOwnerDialog` — a persisted conversation with\n * the bank. No fabricated approval; the EMI calculator stays for modelling.\n * @module housingvista\n */\n\nimport { useMemo, useState } from 'react';\nimport { useNavigate, useParams, useLocation } from 'react-router-dom';\nimport {\n ArrowLeft,\n Building2,\n Star,\n CheckCircle,\n Gift,\n Calculator,\n Percent,\n Wallet,\n CalendarClock,\n} from 'lucide-react';\nimport { Button, EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { Breadcrumbs, StatusBadge, EmptyState, LoadingSkeleton, ContactOwnerDialog } from '../../components';\nimport type { BreadcrumbItem } from '../../components';\nimport { useHomeLoanOffer } from '../../hooks';\nimport { cn, formatCurrency } from '../../utils/helpers';\n\nfunction calculateEMI(principal: number, annualRate: number, tenureYears: number): number {\n if (principal <= 0 || annualRate <= 0 || tenureYears <= 0) return 0;\n const monthlyRate = annualRate / 12 / 100;\n const months = tenureYears * 12;\n const emi = (principal * monthlyRate * Math.pow(1 + monthlyRate, months)) / (Math.pow(1 + monthlyRate, months) - 1);\n return Math.round(emi);\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn(\n 'h-4 w-4',\n i < Math.floor(rating) ? 'fill-status-warning text-status-warning' : 'text-text-secondary/30'\n )}\n />\n ))}\n </div>\n );\n}\n\nexport function HomeLoanDetailPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const { data: loan, loading } = useHomeLoanOffer(id);\n\n // Model a representative loan against the offer's headline rate so the borrower\n // can see the real monthly cost before enquiring.\n const [amount, setAmount] = useState(500000);\n const [tenure, setTenure] = useState(20);\n\n const rate = loan?.interestRate ?? 0;\n const emi = useMemo(() => calculateEMI(amount, rate, tenure), [amount, rate, tenure]);\n const totalPayment = emi * tenure * 12;\n const totalInterest = totalPayment - amount;\n\n if (loading) {\n return (\n <div className=\"p-6\">\n <LoadingSkeleton variant=\"detail\" />\n </div>\n );\n }\n\n if (!loan) {\n return (\n <div className=\"p-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Building2 className=\"h-12 w-12\" />}\n title=\"Loan Offer Not Found\"\n description=\"The loan offer you're looking for doesn't exist or is no longer available.\"\n action={\n <button\n onClick={() => navigate('../home-loans')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Home Loans\n </button>\n }\n />\n </div>\n );\n }\n\n const features = loan.features ?? [];\n const breadcrumbs: BreadcrumbItem[] = [{ label: 'Home Loans', href: '../' }, { label: loan.bankName }];\n\n return (\n <div className=\"flex flex-col gap-6 p-6\">\n <Breadcrumbs items={breadcrumbs} />\n\n {/* Header */}\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <Building2 className=\"h-6 w-6\" />\n </div>\n <div>\n <button\n onClick={() => navigate('../home-loans')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Home Loans\n </button>\n <h1 className=\"text-2xl font-semibold text-text-primary\">{loan.bankName}</h1>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n {loan.rating != null && (\n <span className=\"inline-flex items-center gap-1.5\">\n <RatingStars rating={loan.rating} />\n <span className=\"text-sm text-text-secondary\">{loan.rating}</span>\n </span>\n )}\n {loan.specialOffer && <StatusBadge label=\"Special Offer\" variant=\"warning\" />}\n </div>\n </div>\n </div>\n <ContactOwnerDialog\n entityId={loan.id}\n entityType=\"housingvista-home-loan\"\n title={loan.bankName}\n pagePath={location.pathname}\n heading={`Apply with ${loan.bankName}`}\n description={`Start your application with ${loan.bankName}. Messages are saved and delivered in your inbox.`}\n trigger={<Button type=\"button\">Apply Now</Button>}\n />\n </div>\n\n <PagePurpose className=\"max-w-3xl\">\n The full terms of this offer with a live EMI estimate at the bank's headline rate. Model your loan amount and\n tenure to see the real monthly cost, then apply to connect with {loan.bankName} through Messages.\n </PagePurpose>\n\n {loan.specialOffer && (\n <div className=\"flex items-center gap-2 rounded-lg bg-status-warning-bg-subtle p-3 text-sm text-status-warning-text\">\n <Gift className=\"h-4 w-4 shrink-0\" />\n {loan.specialOffer}\n </div>\n )}\n\n {/* EMI summary — primary emphasis zone (one per page) */}\n <EmphasisPanel className=\"p-5\">\n <div className=\"mb-4 flex items-center gap-2\">\n <Calculator className=\"h-5 w-5 text-text-secondary\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">EMI Estimate at {loan.interestRate}%</h2>\n </div>\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"space-y-5\">\n <div>\n <div className=\"mb-2 flex items-center justify-between\">\n <label className=\"text-sm font-medium text-text-primary\">Loan Amount</label>\n <span className=\"text-sm font-semibold text-text-primary\">{formatCurrency(amount)}</span>\n </div>\n <input\n type=\"range\"\n min={50000}\n max={Math.max(loan.maxAmount, 100000)}\n step={10000}\n value={Math.min(amount, loan.maxAmount)}\n onChange={(e) => setAmount(Number(e.target.value))}\n className=\"w-full accent-foreground\"\n />\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>$50K</span>\n <span>Max {formatCurrency(loan.maxAmount)}</span>\n </div>\n </div>\n <div>\n <div className=\"mb-2 flex items-center justify-between\">\n <label className=\"text-sm font-medium text-text-primary\">Tenure (years)</label>\n <span className=\"text-sm font-semibold text-text-primary\">{tenure} years</span>\n </div>\n <input\n type=\"range\"\n min={1}\n max={loan.maxTenure}\n step={1}\n value={Math.min(tenure, loan.maxTenure)}\n onChange={(e) => setTenure(Number(e.target.value))}\n className=\"w-full accent-foreground\"\n />\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>1 yr</span>\n <span>Max {loan.maxTenure} yrs</span>\n </div>\n </div>\n </div>\n <div className=\"flex flex-col items-center justify-center rounded-lg bg-bg-sunken/50 p-6\">\n <p className=\"text-sm text-text-secondary\">Monthly EMI</p>\n <p className=\"my-2 text-4xl font-bold text-text-primary\">{formatCurrency(emi)}</p>\n <div className=\"mt-4 grid w-full grid-cols-2 gap-4\">\n <div className=\"text-center\">\n <p className=\"text-xs text-text-secondary\">Total Payment</p>\n <p className=\"text-sm font-semibold text-text-primary\">{formatCurrency(totalPayment)}</p>\n </div>\n <div className=\"text-center\">\n <p className=\"text-xs text-text-secondary\">Total Interest</p>\n <p className=\"text-sm font-semibold text-status-error-text\">{formatCurrency(totalInterest)}</p>\n </div>\n </div>\n </div>\n </div>\n </EmphasisPanel>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Terms */}\n <div className=\"space-y-6 lg:col-span-2\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Loan Terms</h2>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Percent className=\"h-3.5 w-3.5\" />\n Interest Rate\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">{loan.interestRate}%</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Wallet className=\"h-3.5 w-3.5\" />\n EMI / Lakh\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">\n {loan.emiPerLakh != null ? `$${loan.emiPerLakh}` : '—'}\n </div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <CalendarClock className=\"h-3.5 w-3.5\" />\n Max Tenure\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">{loan.maxTenure} yrs</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Max Amount</div>\n <div className=\"mt-1 text-sm font-semibold text-text-primary\">{formatCurrency(loan.maxAmount)}</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Processing Fee</div>\n <div className=\"mt-1 text-sm font-semibold text-text-primary\">{loan.processingFee ?? '—'}</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Prepayment</div>\n <div\n className={cn(\n 'mt-1 text-sm font-semibold',\n loan.prepaymentCharges === 'None' ? 'text-status-success-text' : 'text-text-primary'\n )}\n >\n {loan.prepaymentCharges ?? '—'}\n </div>\n </div>\n </div>\n </GlassCard>\n\n {features.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Features</h2>\n <ul className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {features.map((feature, i) => (\n <li key={i} className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <CheckCircle className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n {feature}\n </li>\n ))}\n </ul>\n </GlassCard>\n )}\n </div>\n\n {/* Apply card */}\n <div className=\"space-y-6\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5\">\n <h3 className=\"mb-2 text-base font-semibold text-text-primary\">Ready to apply?</h3>\n <p className=\"mb-4 text-sm text-text-secondary\">\n Applications are handled directly with {loan.bankName} through HousingVista Messages. Start an enquiry and\n the bank will guide you through eligibility and paperwork.\n </p>\n <ContactOwnerDialog\n entityId={loan.id}\n entityType=\"housingvista-home-loan\"\n title={loan.bankName}\n pagePath={location.pathname}\n heading={`Apply with ${loan.bankName}`}\n description={`Start your application with ${loan.bankName}. Messages are saved and delivered in your inbox.`}\n trigger={\n <Button type=\"button\" className=\"w-full justify-center\">\n Apply Now\n </Button>\n }\n />\n </GlassCard>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"HomeLoanDetailPage.js","names":[],"sources":["../../../../src/housingvista/pages/finance/HomeLoanDetailPage.tsx"],"sourcesContent":["/**\n * HousingVista Home Loan Detail / Apply Page\n * Single loan offer backed by `housingvistaHomeLoanOffer(id)` — full terms plus\n * a live EMI summary for the offer's headline rate.\n *\n * \"Apply\" opens the real `ContactOwnerDialog` — a persisted conversation with\n * the bank. No fabricated approval; the EMI calculator stays for modelling.\n * @module housingvista\n */\n\nimport { useMemo, useState } from 'react';\nimport { useNavigate, useParams, useLocation } from 'react-router-dom';\nimport {\n ArrowLeft,\n Building2,\n Star,\n CheckCircle,\n Gift,\n Calculator,\n Percent,\n Wallet,\n CalendarClock,\n} from 'lucide-react';\nimport { EmphasisPanel, GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { Breadcrumbs, StatusBadge, EmptyState, LoadingSkeleton, ContactOwnerDialog } from '../../components';\nimport type { BreadcrumbItem } from '../../components';\nimport { useHomeLoanOffer } from '../../hooks';\nimport { cn, formatCurrency } from '../../utils/helpers';\n\nfunction calculateEMI(principal: number, annualRate: number, tenureYears: number): number {\n if (principal <= 0 || annualRate <= 0 || tenureYears <= 0) return 0;\n const monthlyRate = annualRate / 12 / 100;\n const months = tenureYears * 12;\n const emi = (principal * monthlyRate * Math.pow(1 + monthlyRate, months)) / (Math.pow(1 + monthlyRate, months) - 1);\n return Math.round(emi);\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn(\n 'h-4 w-4',\n i < Math.floor(rating) ? 'fill-status-warning text-status-warning' : 'text-text-secondary/30'\n )}\n />\n ))}\n </div>\n );\n}\n\nexport function HomeLoanDetailPage() {\n const { id } = useParams<{ id: string }>();\n const navigate = useNavigate();\n const location = useLocation();\n const { data: loan, loading } = useHomeLoanOffer(id);\n\n // Model a representative loan against the offer's headline rate so the borrower\n // can see the real monthly cost before enquiring.\n const [amount, setAmount] = useState(500000);\n const [tenure, setTenure] = useState(20);\n\n const rate = loan?.interestRate ?? 0;\n const emi = useMemo(() => calculateEMI(amount, rate, tenure), [amount, rate, tenure]);\n const totalPayment = emi * tenure * 12;\n const totalInterest = totalPayment - amount;\n\n if (loading) {\n return (\n <div className=\"p-6\">\n <LoadingSkeleton variant=\"detail\" />\n </div>\n );\n }\n\n if (!loan) {\n return (\n <div className=\"p-6\">\n <EmptyState\n illustration=\"empty-data\"\n icon={<Building2 className=\"h-12 w-12\" />}\n title=\"Loan Offer Not Found\"\n description=\"The loan offer you're looking for doesn't exist or is no longer available.\"\n action={\n <button\n onClick={() => navigate('../home-loans')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Home Loans\n </button>\n }\n />\n </div>\n );\n }\n\n const features = loan.features ?? [];\n const breadcrumbs: BreadcrumbItem[] = [{ label: 'Home Loans', href: '../' }, { label: loan.bankName }];\n\n return (\n <div className=\"flex flex-col gap-6 p-6\">\n <Breadcrumbs items={breadcrumbs} />\n\n {/* Header */}\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between\">\n <div className=\"flex items-start gap-4\">\n <div className=\"flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary\">\n <Building2 className=\"h-6 w-6\" />\n </div>\n <div>\n <button\n onClick={() => navigate('../home-loans')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Home Loans\n </button>\n <h1 className=\"text-2xl font-semibold text-text-primary\">{loan.bankName}</h1>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n {loan.rating != null && (\n <span className=\"inline-flex items-center gap-1.5\">\n <RatingStars rating={loan.rating} />\n <span className=\"text-sm text-text-secondary\">{loan.rating}</span>\n </span>\n )}\n {loan.specialOffer && <StatusBadge label=\"Special Offer\" variant=\"warning\" />}\n </div>\n </div>\n </div>\n <ContactOwnerDialog\n entityId={loan.id}\n entityType=\"housingvista-home-loan\"\n title={loan.bankName}\n pagePath={location.pathname}\n heading={`Apply with ${loan.bankName}`}\n description={`Start your application with ${loan.bankName}. Messages are saved and delivered in your inbox.`}\n triggerVariant=\"default\"\n triggerContent=\"Apply Now\"\n />\n </div>\n\n <PagePurpose className=\"max-w-3xl\">\n The full terms of this offer with a live EMI estimate at the bank's headline rate. Model your loan amount and\n tenure to see the real monthly cost, then apply to connect with {loan.bankName} through Messages.\n </PagePurpose>\n\n {loan.specialOffer && (\n <div className=\"flex items-center gap-2 rounded-lg bg-status-warning-bg-subtle p-3 text-sm text-status-warning-text\">\n <Gift className=\"h-4 w-4 shrink-0\" />\n {loan.specialOffer}\n </div>\n )}\n\n {/* EMI summary — primary emphasis zone (one per page) */}\n <EmphasisPanel className=\"p-5\">\n <div className=\"mb-4 flex items-center gap-2\">\n <Calculator className=\"h-5 w-5 text-text-secondary\" />\n <h2 className=\"text-lg font-semibold text-text-primary\">EMI Estimate at {loan.interestRate}%</h2>\n </div>\n <div className=\"grid gap-6 md:grid-cols-2\">\n <div className=\"space-y-5\">\n <div>\n <div className=\"mb-2 flex items-center justify-between\">\n <label className=\"text-sm font-medium text-text-primary\">Loan Amount</label>\n <span className=\"text-sm font-semibold text-text-primary\">{formatCurrency(amount)}</span>\n </div>\n <input\n type=\"range\"\n min={50000}\n max={Math.max(loan.maxAmount, 100000)}\n step={10000}\n value={Math.min(amount, loan.maxAmount)}\n onChange={(e) => setAmount(Number(e.target.value))}\n className=\"w-full accent-foreground\"\n />\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>$50K</span>\n <span>Max {formatCurrency(loan.maxAmount)}</span>\n </div>\n </div>\n <div>\n <div className=\"mb-2 flex items-center justify-between\">\n <label className=\"text-sm font-medium text-text-primary\">Tenure (years)</label>\n <span className=\"text-sm font-semibold text-text-primary\">{tenure} years</span>\n </div>\n <input\n type=\"range\"\n min={1}\n max={loan.maxTenure}\n step={1}\n value={Math.min(tenure, loan.maxTenure)}\n onChange={(e) => setTenure(Number(e.target.value))}\n className=\"w-full accent-foreground\"\n />\n <div className=\"mt-1 flex justify-between text-xs text-text-secondary\">\n <span>1 yr</span>\n <span>Max {loan.maxTenure} yrs</span>\n </div>\n </div>\n </div>\n <div className=\"flex flex-col items-center justify-center rounded-lg bg-bg-sunken/50 p-6\">\n <p className=\"text-sm text-text-secondary\">Monthly EMI</p>\n <p className=\"my-2 text-4xl font-bold text-text-primary\">{formatCurrency(emi)}</p>\n <div className=\"mt-4 grid w-full grid-cols-2 gap-4\">\n <div className=\"text-center\">\n <p className=\"text-xs text-text-secondary\">Total Payment</p>\n <p className=\"text-sm font-semibold text-text-primary\">{formatCurrency(totalPayment)}</p>\n </div>\n <div className=\"text-center\">\n <p className=\"text-xs text-text-secondary\">Total Interest</p>\n <p className=\"text-sm font-semibold text-status-error-text\">{formatCurrency(totalInterest)}</p>\n </div>\n </div>\n </div>\n </div>\n </EmphasisPanel>\n\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Terms */}\n <div className=\"space-y-6 lg:col-span-2\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Loan Terms</h2>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Percent className=\"h-3.5 w-3.5\" />\n Interest Rate\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">{loan.interestRate}%</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Wallet className=\"h-3.5 w-3.5\" />\n EMI / Lakh\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">\n {loan.emiPerLakh != null ? `$${loan.emiPerLakh}` : '—'}\n </div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <CalendarClock className=\"h-3.5 w-3.5\" />\n Max Tenure\n </div>\n <div className=\"mt-1 text-lg font-bold text-text-primary\">{loan.maxTenure} yrs</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Max Amount</div>\n <div className=\"mt-1 text-sm font-semibold text-text-primary\">{formatCurrency(loan.maxAmount)}</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Processing Fee</div>\n <div className=\"mt-1 text-sm font-semibold text-text-primary\">{loan.processingFee ?? '—'}</div>\n </div>\n <div className=\"rounded-lg bg-bg-sunken/50 p-4\">\n <div className=\"text-xs text-text-secondary\">Prepayment</div>\n <div\n className={cn(\n 'mt-1 text-sm font-semibold',\n loan.prepaymentCharges === 'None' ? 'text-status-success-text' : 'text-text-primary'\n )}\n >\n {loan.prepaymentCharges ?? '—'}\n </div>\n </div>\n </div>\n </GlassCard>\n\n {features.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-6\">\n <h2 className=\"mb-4 text-base font-semibold text-text-primary\">Features</h2>\n <ul className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n {features.map((feature, i) => (\n <li key={i} className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <CheckCircle className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n {feature}\n </li>\n ))}\n </ul>\n </GlassCard>\n )}\n </div>\n\n {/* Apply card */}\n <div className=\"space-y-6\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5\">\n <h3 className=\"mb-2 text-base font-semibold text-text-primary\">Ready to apply?</h3>\n <p className=\"mb-4 text-sm text-text-secondary\">\n Applications are handled directly with {loan.bankName} through HousingVista Messages. Start an enquiry and\n the bank will guide you through eligibility and paperwork.\n </p>\n <ContactOwnerDialog\n entityId={loan.id}\n entityType=\"housingvista-home-loan\"\n title={loan.bankName}\n pagePath={location.pathname}\n heading={`Apply with ${loan.bankName}`}\n description={`Start your application with ${loan.bankName}. Messages are saved and delivered in your inbox.`}\n triggerVariant=\"default\"\n triggerClassName=\"w-full justify-center\"\n triggerContent=\"Apply Now\"\n />\n </GlassCard>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}