@burdenoff/microfe-housingvista 2026.802.1 → 2026.830.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/housingvista/hooks/index.d.ts +2 -2
- package/dist/housingvista/hooks/index.d.ts.map +1 -1
- package/dist/housingvista/hooks/index.js.map +1 -1
- package/dist/housingvista/hooks/messages.d.ts +18 -11
- package/dist/housingvista/hooks/messages.d.ts.map +1 -1
- package/dist/housingvista/hooks/messages.js +33 -13
- package/dist/housingvista/hooks/messages.js.map +1 -1
- package/dist/housingvista/hooks/platform.d.ts +54 -2
- package/dist/housingvista/hooks/platform.d.ts.map +1 -1
- package/dist/housingvista/hooks/platform.js +63 -18
- package/dist/housingvista/hooks/platform.js.map +1 -1
- package/dist/housingvista/pages/HomePage.js +140 -142
- package/dist/housingvista/pages/HomePage.js.map +1 -1
- package/dist/housingvista/pages/chat/ChatPage.d.ts +4 -2
- package/dist/housingvista/pages/chat/ChatPage.d.ts.map +1 -1
- package/dist/housingvista/pages/chat/ChatPage.js +305 -151
- package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.d.ts.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.js +427 -312
- package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.d.ts.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.js +491 -374
- package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
- package/dist/housingvista/pages/transactions/TransactionsPage.d.ts.map +1 -1
- package/dist/housingvista/pages/transactions/TransactionsPage.js +153 -155
- package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
- package/dist/shared/hooks/index.d.ts +2 -0
- package/dist/shared/hooks/index.d.ts.map +1 -0
- package/dist/shared/hooks/index.js +1 -0
- package/dist/shared/hooks/useTr.d.ts +17 -0
- package/dist/shared/hooks/useTr.d.ts.map +1 -0
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/package.json +2 -2
|
@@ -15,6 +15,7 @@ var n = e`
|
|
|
15
15
|
lastMessage {
|
|
16
16
|
id
|
|
17
17
|
authorId
|
|
18
|
+
type
|
|
18
19
|
content
|
|
19
20
|
createdAt
|
|
20
21
|
}
|
|
@@ -22,15 +23,31 @@ var n = e`
|
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
|
-
`, r = (e) => e && typeof e == "object" && !Array.isArray(e) ? e : null, i = (e) => typeof e == "string" && e.length > 0 ? e : null, a = (
|
|
26
|
-
|
|
26
|
+
`, r = (e) => e && typeof e == "object" && !Array.isArray(e) ? e : null, i = (e) => typeof e == "string" && e.length > 0 ? e : null, a = new Set([
|
|
27
|
+
"FILE",
|
|
28
|
+
"IMAGE",
|
|
29
|
+
"VIDEO",
|
|
30
|
+
"AUDIO"
|
|
31
|
+
]), o = (e) => {
|
|
32
|
+
let t = r(e?.metadata), n = r(t?.sourceContext), a = r(t?.channelLink), o = r(t?.jumpToContext), s = i(n?.product), c = i(a?.channelKey), l = s === "housingvista" || c === "housingvista-widget", u = i(o?.href) ?? i(n?.contextHref), d = i(n?.pagePath) ?? i(o?.pagePath), f = i(n?.threadKey) ?? i(a?.threadKey), p = i(n?.widgetKey) ?? i(a?.widgetKey), m = i(n?.entityType), h = i(n?.entityId);
|
|
27
33
|
return {
|
|
28
|
-
isHousingVista:
|
|
29
|
-
contextHref:
|
|
30
|
-
entityType:
|
|
34
|
+
isHousingVista: l,
|
|
35
|
+
contextHref: u,
|
|
36
|
+
entityType: m,
|
|
37
|
+
entityId: h,
|
|
38
|
+
sourceContext: s && f && p && u && d ? {
|
|
39
|
+
product: s,
|
|
40
|
+
threadKey: f,
|
|
41
|
+
widgetKey: p,
|
|
42
|
+
contextHref: u,
|
|
43
|
+
pagePath: d,
|
|
44
|
+
contextTitle: i(n?.contextTitle) ?? void 0,
|
|
45
|
+
entityId: h ?? void 0,
|
|
46
|
+
entityType: m ?? void 0
|
|
47
|
+
} : null
|
|
31
48
|
};
|
|
32
|
-
},
|
|
33
|
-
let { data: r, loading: i, error:
|
|
49
|
+
}, s = (e = 50) => {
|
|
50
|
+
let { data: r, loading: i, error: s, refetch: c } = t(n, {
|
|
34
51
|
variables: {
|
|
35
52
|
first: e,
|
|
36
53
|
sort: {
|
|
@@ -41,8 +58,8 @@ var n = e`
|
|
|
41
58
|
fetchPolicy: "cache-and-network"
|
|
42
59
|
});
|
|
43
60
|
return {
|
|
44
|
-
data: (r?.conversations.edges ?? []).map((e) => e.node).filter((e) =>
|
|
45
|
-
let t =
|
|
61
|
+
data: (r?.conversations.edges ?? []).map((e) => e.node).filter((e) => o(e.settings).isHousingVista).map((e) => {
|
|
62
|
+
let t = o(e.settings);
|
|
46
63
|
return {
|
|
47
64
|
id: e.id,
|
|
48
65
|
title: e.title ?? "Conversation",
|
|
@@ -51,16 +68,19 @@ var n = e`
|
|
|
51
68
|
updatedAt: e.updatedAt,
|
|
52
69
|
lastMessageText: e.lastMessage?.content?.text ?? "",
|
|
53
70
|
lastMessageAt: e.lastMessage?.createdAt ?? null,
|
|
71
|
+
lastMessageIsFile: a.has(e.lastMessage?.type ?? ""),
|
|
54
72
|
contextHref: t.contextHref,
|
|
55
|
-
entityType: t.entityType
|
|
73
|
+
entityType: t.entityType,
|
|
74
|
+
entityId: t.entityId,
|
|
75
|
+
sourceContext: t.sourceContext
|
|
56
76
|
};
|
|
57
77
|
}),
|
|
58
78
|
loading: i,
|
|
59
|
-
error:
|
|
60
|
-
refetch:
|
|
79
|
+
error: s,
|
|
80
|
+
refetch: c
|
|
61
81
|
};
|
|
62
82
|
};
|
|
63
83
|
//#endregion
|
|
64
|
-
export {
|
|
84
|
+
export { s as useHousingVistaConversations };
|
|
65
85
|
|
|
66
86
|
//# sourceMappingURL=messages.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.js","names":[],"sources":["../../../src/housingvista/hooks/messages.ts"],"sourcesContent":["/**\n * HousingVista inbox — the conversation list behind the `/housingvista/chat`\n * (Messages) surface. Reads the current user's workspace conversations from\n * `wspace-conversations-svc` and narrows them to the threads THIS product\n * created: `resolveContextConversation` stamps every HousingVista thread with a\n * `sourceContext.product = \"housingvista\"` (and `channelLink.channelKey =\n * \"housingvista-widget\"`) inside the conversation `settings`, so we filter on\n * that. Thread reads + sends reuse the shared platform hooks\n * (`useConversationMessages` / `useSendMessage`) — no stub, no mock data.\n * @module housingvista\n */\n\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\n\nconst GET_HV_CONVERSATIONS = gql`\n query HvConversations($first: Int, $sort: ConversationSort) {\n conversations(first: $first, sort: $sort) {\n edges {\n node {\n id\n title\n avatar\n unreadCount\n updatedAt\n settings\n lastMessage {\n id\n authorId\n content\n createdAt\n }\n }\n }\n }\n }\n`;\n\n/** A HousingVista thread as shown in the inbox list. */\nexport interface HvConversationSummary {\n id: string;\n title: string;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n lastMessageText: string;\n lastMessageAt: string | null;\n /** Deep link back to the property/service the thread is about, if any. */\n contextHref: string | null;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string | null;\n}\n\ninterface MessageContentJson {\n text?: string;\n}\n\ninterface ConversationNode {\n id: string;\n title: string | null;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n settings: Record<string, unknown> | null;\n lastMessage: {\n id: string;\n authorId: string;\n content: MessageContentJson | null;\n createdAt: string;\n } | null;\n}\n\ninterface HvConversationsResult {\n conversations: {\n edges: { node: ConversationNode }[];\n };\n}\n\n/** Safely read a nested object off an opaque JSON value. */\nconst asRecord = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n\nconst asString = (value: unknown): string | null => (typeof value === 'string' && value.length > 0 ? value : null);\n\n/**\n * A conversation belongs to HousingVista when its source context (or channel\n * link) was stamped by this product. Reads the shape written by\n * `buildContextConversationSettings` in wspace-conversations-svc.\n */\nconst readHousingVistaContext = (\n settings: Record<string, unknown> | null\n): {
|
|
1
|
+
{"version":3,"file":"messages.js","names":[],"sources":["../../../src/housingvista/hooks/messages.ts"],"sourcesContent":["/**\n * HousingVista inbox — the conversation list behind the `/housingvista/chat`\n * (Messages) surface. Reads the current user's workspace conversations from\n * `wspace-conversations-svc` and narrows them to the threads THIS product\n * created: `resolveContextConversation` stamps every HousingVista thread with a\n * `sourceContext.product = \"housingvista\"` (and `channelLink.channelKey =\n * \"housingvista-widget\"`) inside the conversation `settings`, so we filter on\n * that. Thread reads + sends reuse the shared platform hooks\n * (`useConversationMessages` / `useSendMessage`) — no stub, no mock data.\n * @module housingvista\n */\n\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport type { HvConversationSourceContext } from './platform';\n\nconst GET_HV_CONVERSATIONS = gql`\n query HvConversations($first: Int, $sort: ConversationSort) {\n conversations(first: $first, sort: $sort) {\n edges {\n node {\n id\n title\n avatar\n unreadCount\n updatedAt\n settings\n lastMessage {\n id\n authorId\n type\n content\n createdAt\n }\n }\n }\n }\n }\n`;\n\n/** A HousingVista thread as shown in the inbox list. */\nexport interface HvConversationSummary {\n id: string;\n title: string;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n lastMessageText: string;\n lastMessageAt: string | null;\n /**\n * The last message carries files rather than words (`Message.type` is one of\n * the file kinds and it has no text), so the list row can say so instead of\n * falling back to \"no messages yet\".\n */\n lastMessageIsFile: boolean;\n /** Deep link back to the property/service the thread is about, if any. */\n contextHref: string | null;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string | null;\n /** Id of the property/service the thread is about, if the thread carries one. */\n entityId: string | null;\n /**\n * The full sourceContext this thread was created with, when every field\n * `sendContextMessage` requires is present. `null` for a thread whose\n * settings predate (or are missing) one of them — the caller must then stay\n * on the plain `sendMessage` path.\n */\n sourceContext: HvConversationSourceContext | null;\n}\n\ninterface MessageContentJson {\n text?: string;\n}\n\ninterface ConversationNode {\n id: string;\n title: string | null;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n settings: Record<string, unknown> | null;\n lastMessage: {\n id: string;\n authorId: string;\n type: string;\n content: MessageContentJson | null;\n createdAt: string;\n } | null;\n}\n\ninterface HvConversationsResult {\n conversations: {\n edges: { node: ConversationNode }[];\n };\n}\n\n/** Safely read a nested object off an opaque JSON value. */\nconst asRecord = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n\nconst asString = (value: unknown): string | null => (typeof value === 'string' && value.length > 0 ? value : null);\n\n/** `MessageType` values that carry an attachment rather than prose. */\nconst FILE_MESSAGE_TYPES = new Set(['FILE', 'IMAGE', 'VIDEO', 'AUDIO']);\n\n/**\n * A conversation belongs to HousingVista when its source context (or channel\n * link) was stamped by this product. Reads the shape written by\n * `buildContextConversationSettings` in wspace-conversations-svc.\n */\nconst readHousingVistaContext = (\n settings: Record<string, unknown> | null\n): {\n isHousingVista: boolean;\n contextHref: string | null;\n entityType: string | null;\n entityId: string | null;\n sourceContext: HvConversationSourceContext | null;\n} => {\n const metadata = asRecord(settings?.metadata);\n const sourceContext = asRecord(metadata?.sourceContext);\n const channelLink = asRecord(metadata?.channelLink);\n const jumpToContext = asRecord(metadata?.jumpToContext);\n\n const product = asString(sourceContext?.product);\n const channelKey = asString(channelLink?.channelKey);\n const isHousingVista = product === 'housingvista' || channelKey === 'housingvista-widget';\n\n const contextHref = asString(jumpToContext?.href) ?? asString(sourceContext?.contextHref);\n const pagePath = asString(sourceContext?.pagePath) ?? asString(jumpToContext?.pagePath);\n const threadKey = asString(sourceContext?.threadKey) ?? asString(channelLink?.threadKey);\n const widgetKey = asString(sourceContext?.widgetKey) ?? asString(channelLink?.widgetKey);\n const entityType = asString(sourceContext?.entityType);\n const entityId = asString(sourceContext?.entityId);\n\n // `SendContextConversationMessageInput.sourceContext` marks product /\n // threadKey / widgetKey / contextHref / pagePath non-null — a thread missing\n // any of them cannot use that mutation, so surface null rather than a\n // half-built input the gateway would reject.\n const reusable: HvConversationSourceContext | null =\n product && threadKey && widgetKey && contextHref && pagePath\n ? {\n product,\n threadKey,\n widgetKey,\n contextHref,\n pagePath,\n contextTitle: asString(sourceContext?.contextTitle) ?? undefined,\n entityId: entityId ?? undefined,\n entityType: entityType ?? undefined,\n }\n : null;\n\n return { isHousingVista, contextHref, entityType, entityId, sourceContext: reusable };\n};\n\n/**\n * The user's HousingVista conversations, most-recent first. Filtered client-side\n * to product-owned threads (see {@link readHousingVistaContext}); everything\n * else is honestly empty rather than fabricated.\n */\nexport const useHousingVistaConversations = (first = 50) => {\n const { data, loading, error, refetch } = useQuery<HvConversationsResult>(GET_HV_CONVERSATIONS, {\n variables: { first, sort: { field: 'LAST_MESSAGE_AT', direction: 'DESC' } },\n fetchPolicy: 'cache-and-network',\n });\n\n const conversations: HvConversationSummary[] = (data?.conversations.edges ?? [])\n .map((edge) => edge.node)\n .filter((node) => readHousingVistaContext(node.settings).isHousingVista)\n .map((node) => {\n const context = readHousingVistaContext(node.settings);\n return {\n id: node.id,\n title: node.title ?? 'Conversation',\n avatar: node.avatar,\n unreadCount: node.unreadCount,\n updatedAt: node.updatedAt,\n lastMessageText: node.lastMessage?.content?.text ?? '',\n lastMessageAt: node.lastMessage?.createdAt ?? null,\n lastMessageIsFile: FILE_MESSAGE_TYPES.has(node.lastMessage?.type ?? ''),\n contextHref: context.contextHref,\n entityType: context.entityType,\n entityId: context.entityId,\n sourceContext: context.sourceContext,\n };\n });\n\n return { data: conversations, loading, error, refetch };\n};\n"],"mappings":";;;AAgBA,IAAM,IAAuB,CAAG;;;;;;;;;;;;;;;;;;;;;;GAiF1B,KAAY,MAChB,KAAS,OAAO,KAAU,YAAY,CAAC,MAAM,QAAQ,EAAM,GAAI,IAAoC,MAE/F,KAAY,MAAmC,OAAO,KAAU,YAAY,EAAM,SAAS,IAAI,IAAQ,MAGvG,IAAqB,IAAI,IAAI;CAAC;CAAQ;CAAS;CAAS;CAAQ,CAAC,EAOjE,KACJ,MAOG;CACH,IAAM,IAAW,EAAS,GAAU,SAAS,EACvC,IAAgB,EAAS,GAAU,cAAc,EACjD,IAAc,EAAS,GAAU,YAAY,EAC7C,IAAgB,EAAS,GAAU,cAAc,EAEjD,IAAU,EAAS,GAAe,QAAQ,EAC1C,IAAa,EAAS,GAAa,WAAW,EAC9C,IAAiB,MAAY,kBAAkB,MAAe,uBAE9D,IAAc,EAAS,GAAe,KAAK,IAAI,EAAS,GAAe,YAAY,EACnF,IAAW,EAAS,GAAe,SAAS,IAAI,EAAS,GAAe,SAAS,EACjF,IAAY,EAAS,GAAe,UAAU,IAAI,EAAS,GAAa,UAAU,EAClF,IAAY,EAAS,GAAe,UAAU,IAAI,EAAS,GAAa,UAAU,EAClF,IAAa,EAAS,GAAe,WAAW,EAChD,IAAW,EAAS,GAAe,SAAS;AAoBlD,QAAO;EAAE;EAAgB;EAAa;EAAY;EAAU,eAb1D,KAAW,KAAa,KAAa,KAAe,IAChD;GACE;GACA;GACA;GACA;GACA;GACA,cAAc,EAAS,GAAe,aAAa,IAAI,KAAA;GACvD,UAAU,KAAY,KAAA;GACtB,YAAY,KAAc,KAAA;GAC3B,GACD;EAE+E;GAQ1E,KAAgC,IAAQ,OAAO;CAC1D,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAgC,GAAsB;EAC9F,WAAW;GAAE;GAAO,MAAM;IAAE,OAAO;IAAmB,WAAW;IAAQ;GAAE;EAC3E,aAAa;EACd,CAAC;AAuBF,QAAO;EAAE,OArBuC,GAAM,cAAc,SAAS,EAAE,EAC5E,KAAK,MAAS,EAAK,KAAK,CACxB,QAAQ,MAAS,EAAwB,EAAK,SAAS,CAAC,eAAe,CACvE,KAAK,MAAS;GACb,IAAM,IAAU,EAAwB,EAAK,SAAS;AACtD,UAAO;IACL,IAAI,EAAK;IACT,OAAO,EAAK,SAAS;IACrB,QAAQ,EAAK;IACb,aAAa,EAAK;IAClB,WAAW,EAAK;IAChB,iBAAiB,EAAK,aAAa,SAAS,QAAQ;IACpD,eAAe,EAAK,aAAa,aAAa;IAC9C,mBAAmB,EAAmB,IAAI,EAAK,aAAa,QAAQ,GAAG;IACvE,aAAa,EAAQ;IACrB,YAAY,EAAQ;IACpB,UAAU,EAAQ;IAClB,eAAe,EAAQ;IACxB;IACD;EAE0B;EAAS;EAAO;EAAS"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* cross-MFE import (forbidden):
|
|
7
7
|
*
|
|
8
8
|
* - `wspace-conversations-svc` — direct messaging (Contact / Message / Apply
|
|
9
|
-
* CTAs) via `resolveContextConversation` + `sendMessage
|
|
10
|
-
*
|
|
9
|
+
* CTAs) via `resolveContextConversation` + `sendMessage` (and
|
|
10
|
+
* `sendContextMessage` when a message carries file attachments), and
|
|
11
|
+
* per-listing Q&A / reviews via `getEntityComments` + `createEntityComment`.
|
|
11
12
|
* - `wspace-files-svc` — real uploads via the presigned `initiateUpload` →
|
|
12
13
|
* PUT → `completeUpload` flow, returning a durable File id + download URL.
|
|
13
14
|
*
|
|
@@ -26,12 +27,41 @@ export interface HvContextTarget {
|
|
|
26
27
|
/** Router path portion of `contextHref`. */
|
|
27
28
|
pagePath: string;
|
|
28
29
|
}
|
|
30
|
+
/** A file attached to a message (`Message.attachments` on the conversations subgraph). */
|
|
31
|
+
export interface HvMessageAttachment {
|
|
32
|
+
id: string;
|
|
33
|
+
fileId: string;
|
|
34
|
+
fileName: string;
|
|
35
|
+
fileSize: number;
|
|
36
|
+
mimeType: string;
|
|
37
|
+
/** Null when the attachment row carries no resolvable download metadata. */
|
|
38
|
+
downloadUrl: string | null;
|
|
39
|
+
}
|
|
29
40
|
export interface HvConversationMessage {
|
|
30
41
|
id: string;
|
|
31
42
|
authorId: string;
|
|
43
|
+
/** Resolved display name of the sender (`Message.authorName`). */
|
|
44
|
+
authorName: string;
|
|
32
45
|
/** Conversations stores content as JSON; the plain text is under `.text`. */
|
|
33
46
|
text: string;
|
|
34
47
|
createdAt: string;
|
|
48
|
+
attachments: HvMessageAttachment[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The `sourceContext` a HousingVista thread was created with, read back off the
|
|
52
|
+
* conversation's persisted `settings.metadata`. Present only when every field
|
|
53
|
+
* `SendContextConversationMessageInput` requires survived; callers must treat a
|
|
54
|
+
* `null` as "this thread cannot take the context-message path".
|
|
55
|
+
*/
|
|
56
|
+
export interface HvConversationSourceContext {
|
|
57
|
+
product: string;
|
|
58
|
+
threadKey: string;
|
|
59
|
+
widgetKey: string;
|
|
60
|
+
contextHref: string;
|
|
61
|
+
pagePath: string;
|
|
62
|
+
contextTitle?: string;
|
|
63
|
+
entityId?: string;
|
|
64
|
+
entityType?: string;
|
|
35
65
|
}
|
|
36
66
|
interface MessageContentJson {
|
|
37
67
|
text?: string;
|
|
@@ -45,8 +75,10 @@ interface ConversationMessagesResult {
|
|
|
45
75
|
node: {
|
|
46
76
|
id: string;
|
|
47
77
|
authorId: string;
|
|
78
|
+
authorName: string;
|
|
48
79
|
content: MessageContentJson | null;
|
|
49
80
|
createdAt: string;
|
|
81
|
+
attachments: HvMessageAttachment[];
|
|
50
82
|
};
|
|
51
83
|
}[];
|
|
52
84
|
};
|
|
@@ -68,6 +100,26 @@ export declare const useSendMessage: () => {
|
|
|
68
100
|
sendMessage: (conversationId: string, text: string) => Promise<void>;
|
|
69
101
|
loading: boolean;
|
|
70
102
|
};
|
|
103
|
+
/**
|
|
104
|
+
* Send a message WITH file attachments.
|
|
105
|
+
*
|
|
106
|
+
* `sendMessage`'s `attachmentIds` only stores bare file ids — the subgraph's
|
|
107
|
+
* `Attachment.fileName`/`downloadUrl` resolvers read their values out of the
|
|
108
|
+
* attachment row's metadata, so an id-only attachment comes back rendering its
|
|
109
|
+
* own uuid with no download link. `sendContextMessage` is the mutation that
|
|
110
|
+
* accepts full `ContextMessageAttachmentInput` details, so it is the only path
|
|
111
|
+
* that yields a readable attachment. It resolves the conversation from the
|
|
112
|
+
* thread's `sourceContext` (idempotent on `threadKey`), which is why the caller
|
|
113
|
+
* must hand back the SAME sourceContext the thread was created with.
|
|
114
|
+
*/
|
|
115
|
+
export declare const useSendContextMessage: () => {
|
|
116
|
+
sendContextMessage: (args: {
|
|
117
|
+
sourceContext: HvConversationSourceContext;
|
|
118
|
+
text: string;
|
|
119
|
+
attachments: HvUploadedFile[];
|
|
120
|
+
}) => Promise<void>;
|
|
121
|
+
loading: boolean;
|
|
122
|
+
};
|
|
71
123
|
export declare const useConversationMessages: (conversationId: string | undefined, first?: number) => {
|
|
72
124
|
data: HvConversationMessage[];
|
|
73
125
|
title: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../../src/housingvista/hooks/platform.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../../src/housingvista/hooks/platform.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,16 @@ var a = n`
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
`, s = n`
|
|
27
|
+
mutation HvSendContextMessage($input: SendContextConversationMessageInput!) {
|
|
28
|
+
sendContextMessage(input: $input) {
|
|
29
|
+
success
|
|
30
|
+
message {
|
|
31
|
+
id
|
|
32
|
+
createdAt
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`, c = n`
|
|
27
37
|
query HvConversationMessages($id: ID!, $first: Int) {
|
|
28
38
|
conversation(id: $id) {
|
|
29
39
|
id
|
|
@@ -33,14 +43,23 @@ var a = n`
|
|
|
33
43
|
node {
|
|
34
44
|
id
|
|
35
45
|
authorId
|
|
46
|
+
authorName
|
|
36
47
|
content
|
|
37
48
|
createdAt
|
|
49
|
+
attachments {
|
|
50
|
+
id
|
|
51
|
+
fileId
|
|
52
|
+
fileName
|
|
53
|
+
fileSize
|
|
54
|
+
mimeType
|
|
55
|
+
downloadUrl
|
|
56
|
+
}
|
|
38
57
|
}
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
}
|
|
42
61
|
}
|
|
43
|
-
`,
|
|
62
|
+
`, l = () => {
|
|
44
63
|
let { workspaceId: n } = e(), [i, { loading: o }] = r(a);
|
|
45
64
|
return {
|
|
46
65
|
openConversation: t(async (e) => {
|
|
@@ -66,7 +85,7 @@ var a = n`
|
|
|
66
85
|
}, [i, n]),
|
|
67
86
|
loading: o
|
|
68
87
|
};
|
|
69
|
-
},
|
|
88
|
+
}, u = () => {
|
|
70
89
|
let [e, { loading: n }] = r(o);
|
|
71
90
|
return {
|
|
72
91
|
sendMessage: t(async (t, n) => {
|
|
@@ -81,8 +100,32 @@ var a = n`
|
|
|
81
100
|
}, [e]),
|
|
82
101
|
loading: n
|
|
83
102
|
};
|
|
84
|
-
},
|
|
85
|
-
let {
|
|
103
|
+
}, d = () => {
|
|
104
|
+
let { workspaceId: n } = e(), [i, { loading: a }] = r(s);
|
|
105
|
+
return {
|
|
106
|
+
sendContextMessage: t(async (e) => {
|
|
107
|
+
if (!(await i({
|
|
108
|
+
variables: { input: {
|
|
109
|
+
workspaceId: n,
|
|
110
|
+
sourceContext: e.sourceContext,
|
|
111
|
+
content: { text: e.text },
|
|
112
|
+
type: e.attachments.length > 0 ? "FILE" : "TEXT",
|
|
113
|
+
attachments: e.attachments.map((e) => ({
|
|
114
|
+
fileId: e.id,
|
|
115
|
+
fileName: e.name,
|
|
116
|
+
fileSize: e.size,
|
|
117
|
+
mimeType: e.mimeType,
|
|
118
|
+
downloadUrl: e.url || void 0
|
|
119
|
+
}))
|
|
120
|
+
} },
|
|
121
|
+
refetchQueries: ["HvConversationMessages"],
|
|
122
|
+
awaitRefetchQueries: !0
|
|
123
|
+
})).data?.sendContextMessage.success) throw Error("Message was not sent");
|
|
124
|
+
}, [i, n]),
|
|
125
|
+
loading: a
|
|
126
|
+
};
|
|
127
|
+
}, f = (e, t = 50) => {
|
|
128
|
+
let { data: n, loading: r, error: a, refetch: o } = i(c, {
|
|
86
129
|
variables: {
|
|
87
130
|
id: e ?? "",
|
|
88
131
|
first: t
|
|
@@ -93,15 +136,17 @@ var a = n`
|
|
|
93
136
|
data: (n?.conversation?.messages.edges ?? []).map((e) => ({
|
|
94
137
|
id: e.node.id,
|
|
95
138
|
authorId: e.node.authorId,
|
|
139
|
+
authorName: e.node.authorName,
|
|
96
140
|
text: e.node.content?.text ?? "",
|
|
97
|
-
createdAt: e.node.createdAt
|
|
141
|
+
createdAt: e.node.createdAt,
|
|
142
|
+
attachments: e.node.attachments ?? []
|
|
98
143
|
})),
|
|
99
144
|
title: n?.conversation?.title ?? null,
|
|
100
145
|
loading: r,
|
|
101
146
|
error: a,
|
|
102
147
|
refetch: o
|
|
103
148
|
};
|
|
104
|
-
},
|
|
149
|
+
}, p = n`
|
|
105
150
|
query HvEntityComments($input: GetCommentsInput!) {
|
|
106
151
|
getEntityComments(input: $input) {
|
|
107
152
|
total
|
|
@@ -118,15 +163,15 @@ var a = n`
|
|
|
118
163
|
}
|
|
119
164
|
}
|
|
120
165
|
}
|
|
121
|
-
`,
|
|
166
|
+
`, m = n`
|
|
122
167
|
mutation HvCreateEntityComment($input: CreateEntityCommentInput!) {
|
|
123
168
|
createEntityComment(input: $input) {
|
|
124
169
|
id
|
|
125
170
|
createdAt
|
|
126
171
|
}
|
|
127
172
|
}
|
|
128
|
-
`,
|
|
129
|
-
let { data: r, loading: a, error: o, refetch: s } = i(
|
|
173
|
+
`, h = (e, t, n = 50) => {
|
|
174
|
+
let { data: r, loading: a, error: o, refetch: s } = i(p, {
|
|
130
175
|
variables: { input: {
|
|
131
176
|
entityType: e,
|
|
132
177
|
entityId: t ?? "",
|
|
@@ -149,8 +194,8 @@ var a = n`
|
|
|
149
194
|
error: o,
|
|
150
195
|
refetch: s
|
|
151
196
|
};
|
|
152
|
-
},
|
|
153
|
-
let [e, { loading: n }] = r(
|
|
197
|
+
}, g = () => {
|
|
198
|
+
let [e, { loading: n }] = r(m);
|
|
154
199
|
return {
|
|
155
200
|
createComment: t(async (t) => {
|
|
156
201
|
await e({
|
|
@@ -166,7 +211,7 @@ var a = n`
|
|
|
166
211
|
}, [e]),
|
|
167
212
|
loading: n
|
|
168
213
|
};
|
|
169
|
-
},
|
|
214
|
+
}, _ = n`
|
|
170
215
|
mutation HvInitiateUpload($input: InitiateUploadInput!) {
|
|
171
216
|
initiateUpload(input: $input) {
|
|
172
217
|
uploadUrl
|
|
@@ -175,7 +220,7 @@ var a = n`
|
|
|
175
220
|
}
|
|
176
221
|
}
|
|
177
222
|
}
|
|
178
|
-
`,
|
|
223
|
+
`, v = n`
|
|
179
224
|
mutation HvCompleteUpload($input: CompleteUploadInput!) {
|
|
180
225
|
completeUpload(input: $input) {
|
|
181
226
|
fileId
|
|
@@ -188,13 +233,13 @@ var a = n`
|
|
|
188
233
|
}
|
|
189
234
|
}
|
|
190
235
|
}
|
|
191
|
-
`,
|
|
236
|
+
`, y = (e) => {
|
|
192
237
|
let t = e.lastIndexOf(".");
|
|
193
238
|
return t > 0 && t < e.length - 1 ? e.slice(t + 1).toLowerCase() : "bin";
|
|
194
|
-
},
|
|
195
|
-
let [e] = r(
|
|
239
|
+
}, b = () => {
|
|
240
|
+
let [e] = r(_), [n] = r(v);
|
|
196
241
|
return { uploadFile: t(async (t) => {
|
|
197
|
-
let r =
|
|
242
|
+
let r = y(t.name), i = t.type || "application/octet-stream", a = await e({ variables: { input: {
|
|
198
243
|
fileName: t.name,
|
|
199
244
|
extension: r,
|
|
200
245
|
fileSize: t.size,
|
|
@@ -223,6 +268,6 @@ var a = n`
|
|
|
223
268
|
}, [e, n]) };
|
|
224
269
|
};
|
|
225
270
|
//#endregion
|
|
226
|
-
export {
|
|
271
|
+
export { l as useContactConversation, f as useConversationMessages, g as useCreateEntityComment, h as useEntityComments, b as useFileUpload, d as useSendContextMessage, u as useSendMessage };
|
|
227
272
|
|
|
228
273
|
//# sourceMappingURL=platform.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.js","names":[],"sources":["../../../src/housingvista/hooks/platform.ts"],"sourcesContent":["/**\n * Platform-service reuse hooks for HousingVista.\n *\n * These call *other* wspace subgraphs through the SAME Apollo client / wspace\n * gateway the MFE already uses — cross-SERVICE GraphQL (allowed), never a\n * cross-MFE import (forbidden):\n *\n * - `wspace-conversations-svc` — direct messaging (Contact / Message / Apply\n * CTAs) via `resolveContextConversation` + `sendMessage`, and per-listing\n * Q&A / reviews via `getEntityComments` + `createEntityComment`.\n * - `wspace-files-svc` — real uploads via the presigned `initiateUpload` →\n * PUT → `completeUpload` flow, returning a durable File id + download URL.\n *\n * No `any`, no mock data. `workspaceId` is read from the HousingVista context.\n * @module housingvista\n */\n\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useCallback } from 'react';\nimport { useHousingVista } from '../context/HousingVistaContext';\n\n// ---------------------------------------------------------------------------\n// Conversations — direct messaging\n// ---------------------------------------------------------------------------\n\nconst RESOLVE_CONTEXT_CONVERSATION = gql`\n mutation HvResolveContextConversation($input: ResolveContextConversationInput!) {\n resolveContextConversation(input: $input) {\n created\n conversation {\n id\n title\n }\n }\n }\n`;\n\nconst SEND_MESSAGE = gql`\n mutation HvSendMessage($input: SendMessageInput!) {\n sendMessage(input: $input) {\n success\n message {\n id\n createdAt\n }\n }\n }\n`;\n\nconst GET_CONVERSATION_MESSAGES = gql`\n query HvConversationMessages($id: ID!, $first: Int) {\n conversation(id: $id) {\n id\n title\n messages(first: $first) {\n edges {\n node {\n id\n authorId\n content\n createdAt\n }\n }\n }\n }\n }\n`;\n\nexport interface HvContextTarget {\n /** Stable identity of the thing being discussed, e.g. a property id. */\n entityId: string;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string;\n /** Human title used when a conversation is first created. */\n title: string;\n /** Deep link back into the MFE surface, e.g. `/housingvista/properties/:id`. */\n contextHref: string;\n /** Router path portion of `contextHref`. */\n pagePath: string;\n}\n\nexport interface HvConversationMessage {\n id: string;\n authorId: string;\n /** Conversations stores content as JSON; the plain text is under `.text`. */\n text: string;\n createdAt: string;\n}\n\ninterface ResolveContextConversationResult {\n resolveContextConversation: {\n created: boolean;\n conversation: { id: string; title: string | null };\n };\n}\n\ninterface MessageContentJson {\n text?: string;\n}\n\ninterface ConversationMessagesResult {\n conversation: {\n id: string;\n title: string | null;\n messages: {\n edges: {\n node: { id: string; authorId: string; content: MessageContentJson | null; createdAt: string };\n }[];\n };\n } | null;\n}\n\n/**\n * Resolve (get-or-create) the conversation attached to a HousingVista entity,\n * then return its id. Idempotent per (workspace, entityType, entityId) via the\n * derived `threadKey`, so repeated \"Contact\" clicks reuse one thread.\n */\nexport const useContactConversation = () => {\n const { workspaceId } = useHousingVista();\n const [resolve, { loading }] = useMutation<ResolveContextConversationResult>(RESOLVE_CONTEXT_CONVERSATION);\n\n const openConversation = useCallback(\n async (target: HvContextTarget): Promise<{ id: string; created: boolean }> => {\n const threadKey = `housingvista:${target.entityType}:${target.entityId}`;\n const res = await resolve({\n variables: {\n input: {\n workspaceId,\n title: target.title,\n sourceContext: {\n product: 'housingvista',\n entityId: target.entityId,\n entityType: target.entityType,\n threadKey,\n widgetKey: 'housingvista-contact',\n contextHref: target.contextHref,\n pagePath: target.pagePath,\n contextTitle: target.title,\n },\n },\n },\n });\n const conversation = res.data?.resolveContextConversation.conversation;\n if (!conversation) throw new Error('Could not open the conversation');\n return { id: conversation.id, created: res.data?.resolveContextConversation.created ?? false };\n },\n [resolve, workspaceId]\n );\n\n return { openConversation, loading };\n};\n\nexport const useSendMessage = () => {\n const [send, { loading }] = useMutation<{ sendMessage: { success: boolean } }>(SEND_MESSAGE);\n const sendMessage = useCallback(\n async (conversationId: string, text: string): Promise<void> => {\n const res = await send({\n variables: { input: { conversationId, content: { text } } },\n refetchQueries: ['HvConversationMessages'],\n awaitRefetchQueries: true,\n });\n if (!res.data?.sendMessage.success) throw new Error('Message was not sent');\n },\n [send]\n );\n return { sendMessage, loading };\n};\n\nexport const useConversationMessages = (conversationId: string | undefined, first = 50) => {\n const { data, loading, error, refetch } = useQuery<ConversationMessagesResult>(GET_CONVERSATION_MESSAGES, {\n variables: { id: conversationId ?? '', first },\n skip: !conversationId,\n });\n const messages: HvConversationMessage[] = (data?.conversation?.messages.edges ?? []).map((edge) => ({\n id: edge.node.id,\n authorId: edge.node.authorId,\n text: edge.node.content?.text ?? '',\n createdAt: edge.node.createdAt,\n }));\n return { data: messages, title: data?.conversation?.title ?? null, loading, error, refetch };\n};\n\n// ---------------------------------------------------------------------------\n// Entity comments — per-listing Q&A + reviews\n// ---------------------------------------------------------------------------\n\nconst GET_ENTITY_COMMENTS = gql`\n query HvEntityComments($input: GetCommentsInput!) {\n getEntityComments(input: $input) {\n total\n items {\n id\n authorId\n authorType\n isAnonymous\n createdAt\n metadata\n content {\n text\n }\n }\n }\n }\n`;\n\nconst CREATE_ENTITY_COMMENT = gql`\n mutation HvCreateEntityComment($input: CreateEntityCommentInput!) {\n createEntityComment(input: $input) {\n id\n createdAt\n }\n }\n`;\n\nexport interface HvEntityComment {\n id: string;\n authorId: string;\n text: string;\n createdAt: string;\n /** Free-form; reviews carry `{ stars: number }`. */\n metadata: Record<string, unknown> | null;\n}\n\ninterface EntityCommentsResult {\n getEntityComments: {\n total: number;\n items: {\n id: string;\n authorId: string;\n authorType: string;\n isAnonymous: boolean;\n createdAt: string;\n metadata: Record<string, unknown> | null;\n content: { text: string | null } | null;\n }[];\n };\n}\n\nexport const useEntityComments = (entityType: string, entityId: string | undefined, take = 50) => {\n const { data, loading, error, refetch } = useQuery<EntityCommentsResult>(GET_ENTITY_COMMENTS, {\n variables: { input: { entityType, entityId: entityId ?? '', take, sortBy: 'createdAt', sortOrder: 'desc' } },\n skip: !entityId,\n });\n const comments: HvEntityComment[] = (data?.getEntityComments.items ?? []).map((item) => ({\n id: item.id,\n authorId: item.authorId,\n text: item.content?.text ?? '',\n createdAt: item.createdAt,\n metadata: item.metadata,\n }));\n return { data: comments, total: data?.getEntityComments.total ?? 0, loading, error, refetch };\n};\n\nexport const useCreateEntityComment = () => {\n const [mutate, { loading }] = useMutation<{ createEntityComment: { id: string } }>(CREATE_ENTITY_COMMENT);\n const createComment = useCallback(\n async (args: {\n entityType: string;\n entityId: string;\n text: string;\n metadata?: Record<string, unknown>;\n }): Promise<void> => {\n await mutate({\n variables: {\n input: {\n entityType: args.entityType,\n entityId: args.entityId,\n content: { text: args.text },\n metadata: args.metadata,\n },\n },\n refetchQueries: ['HvEntityComments'],\n awaitRefetchQueries: true,\n });\n },\n [mutate]\n );\n return { createComment, loading };\n};\n\n// ---------------------------------------------------------------------------\n// Files — presigned upload (initiateUpload → PUT → completeUpload)\n// ---------------------------------------------------------------------------\n\nconst INITIATE_UPLOAD = gql`\n mutation HvInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session {\n id\n }\n }\n }\n`;\n\nconst COMPLETE_UPLOAD = gql`\n mutation HvCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n fileId\n file {\n id\n name\n downloadUrl\n mimeType\n size\n }\n }\n }\n`;\n\nexport interface HvUploadedFile {\n id: string;\n name: string;\n url: string;\n mimeType: string;\n size: number;\n}\n\ninterface InitiateUploadResult {\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n}\n\ninterface CompleteUploadResult {\n completeUpload: {\n fileId: string;\n file: { id: string; name: string; downloadUrl: string | null; mimeType: string; size: number };\n };\n}\n\nconst splitExtension = (fileName: string): string => {\n const dot = fileName.lastIndexOf('.');\n return dot > 0 && dot < fileName.length - 1 ? fileName.slice(dot + 1).toLowerCase() : 'bin';\n};\n\n/**\n * Upload a real browser `File` through wspace-files-svc and return the durable\n * File id + download URL. Single-PUT presigned flow (fine for the image /\n * document sizes HousingVista deals with).\n */\nexport const useFileUpload = () => {\n const [initiate] = useMutation<InitiateUploadResult>(INITIATE_UPLOAD);\n const [complete] = useMutation<CompleteUploadResult>(COMPLETE_UPLOAD);\n\n const uploadFile = useCallback(\n async (file: File): Promise<HvUploadedFile> => {\n const extension = splitExtension(file.name);\n const mimeType = file.type || 'application/octet-stream';\n const initiated = await initiate({\n variables: {\n input: {\n fileName: file.name,\n extension,\n fileSize: file.size,\n mimeType,\n visibility: 'WORKSPACE',\n },\n },\n });\n const uploadUrl = initiated.data?.initiateUpload.uploadUrl;\n const sessionId = initiated.data?.initiateUpload.session.id;\n if (!uploadUrl || !sessionId) throw new Error('Upload could not be started');\n\n const putRes = await fetch(uploadUrl, {\n method: 'PUT',\n body: file,\n headers: { 'Content-Type': mimeType },\n });\n if (!putRes.ok) throw new Error(`Upload failed (${putRes.status})`);\n\n const completed = await complete({\n variables: { input: { sessionId, fileSize: file.size } },\n });\n const uploaded = completed.data?.completeUpload.file;\n if (!uploaded) throw new Error('Upload could not be finalized');\n return {\n id: uploaded.id,\n name: uploaded.name,\n url: uploaded.downloadUrl ?? '',\n mimeType: uploaded.mimeType,\n size: Number(uploaded.size),\n };\n },\n [initiate, complete]\n );\n\n return { uploadFile };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"platform.js","names":[],"sources":["../../../src/housingvista/hooks/platform.ts"],"sourcesContent":["/**\n * Platform-service reuse hooks for HousingVista.\n *\n * These call *other* wspace subgraphs through the SAME Apollo client / wspace\n * gateway the MFE already uses — cross-SERVICE GraphQL (allowed), never a\n * cross-MFE import (forbidden):\n *\n * - `wspace-conversations-svc` — direct messaging (Contact / Message / Apply\n * CTAs) via `resolveContextConversation` + `sendMessage` (and\n * `sendContextMessage` when a message carries file attachments), and\n * per-listing Q&A / reviews via `getEntityComments` + `createEntityComment`.\n * - `wspace-files-svc` — real uploads via the presigned `initiateUpload` →\n * PUT → `completeUpload` flow, returning a durable File id + download URL.\n *\n * No `any`, no mock data. `workspaceId` is read from the HousingVista context.\n * @module housingvista\n */\n\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useCallback } from 'react';\nimport { useHousingVista } from '../context/HousingVistaContext';\n\n// ---------------------------------------------------------------------------\n// Conversations — direct messaging\n// ---------------------------------------------------------------------------\n\nconst RESOLVE_CONTEXT_CONVERSATION = gql`\n mutation HvResolveContextConversation($input: ResolveContextConversationInput!) {\n resolveContextConversation(input: $input) {\n created\n conversation {\n id\n title\n }\n }\n }\n`;\n\nconst SEND_MESSAGE = gql`\n mutation HvSendMessage($input: SendMessageInput!) {\n sendMessage(input: $input) {\n success\n message {\n id\n createdAt\n }\n }\n }\n`;\n\nconst SEND_CONTEXT_MESSAGE = gql`\n mutation HvSendContextMessage($input: SendContextConversationMessageInput!) {\n sendContextMessage(input: $input) {\n success\n message {\n id\n createdAt\n }\n }\n }\n`;\n\nconst GET_CONVERSATION_MESSAGES = gql`\n query HvConversationMessages($id: ID!, $first: Int) {\n conversation(id: $id) {\n id\n title\n messages(first: $first) {\n edges {\n node {\n id\n authorId\n authorName\n content\n createdAt\n attachments {\n id\n fileId\n fileName\n fileSize\n mimeType\n downloadUrl\n }\n }\n }\n }\n }\n }\n`;\n\nexport interface HvContextTarget {\n /** Stable identity of the thing being discussed, e.g. a property id. */\n entityId: string;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string;\n /** Human title used when a conversation is first created. */\n title: string;\n /** Deep link back into the MFE surface, e.g. `/housingvista/properties/:id`. */\n contextHref: string;\n /** Router path portion of `contextHref`. */\n pagePath: string;\n}\n\n/** A file attached to a message (`Message.attachments` on the conversations subgraph). */\nexport interface HvMessageAttachment {\n id: string;\n fileId: string;\n fileName: string;\n fileSize: number;\n mimeType: string;\n /** Null when the attachment row carries no resolvable download metadata. */\n downloadUrl: string | null;\n}\n\nexport interface HvConversationMessage {\n id: string;\n authorId: string;\n /** Resolved display name of the sender (`Message.authorName`). */\n authorName: string;\n /** Conversations stores content as JSON; the plain text is under `.text`. */\n text: string;\n createdAt: string;\n attachments: HvMessageAttachment[];\n}\n\n/**\n * The `sourceContext` a HousingVista thread was created with, read back off the\n * conversation's persisted `settings.metadata`. Present only when every field\n * `SendContextConversationMessageInput` requires survived; callers must treat a\n * `null` as \"this thread cannot take the context-message path\".\n */\nexport interface HvConversationSourceContext {\n product: string;\n threadKey: string;\n widgetKey: string;\n contextHref: string;\n pagePath: string;\n contextTitle?: string;\n entityId?: string;\n entityType?: string;\n}\n\ninterface ResolveContextConversationResult {\n resolveContextConversation: {\n created: boolean;\n conversation: { id: string; title: string | null };\n };\n}\n\ninterface MessageContentJson {\n text?: string;\n}\n\ninterface ConversationMessagesResult {\n conversation: {\n id: string;\n title: string | null;\n messages: {\n edges: {\n node: {\n id: string;\n authorId: string;\n authorName: string;\n content: MessageContentJson | null;\n createdAt: string;\n attachments: HvMessageAttachment[];\n };\n }[];\n };\n } | null;\n}\n\n/**\n * Resolve (get-or-create) the conversation attached to a HousingVista entity,\n * then return its id. Idempotent per (workspace, entityType, entityId) via the\n * derived `threadKey`, so repeated \"Contact\" clicks reuse one thread.\n */\nexport const useContactConversation = () => {\n const { workspaceId } = useHousingVista();\n const [resolve, { loading }] = useMutation<ResolveContextConversationResult>(RESOLVE_CONTEXT_CONVERSATION);\n\n const openConversation = useCallback(\n async (target: HvContextTarget): Promise<{ id: string; created: boolean }> => {\n const threadKey = `housingvista:${target.entityType}:${target.entityId}`;\n const res = await resolve({\n variables: {\n input: {\n workspaceId,\n title: target.title,\n sourceContext: {\n product: 'housingvista',\n entityId: target.entityId,\n entityType: target.entityType,\n threadKey,\n widgetKey: 'housingvista-contact',\n contextHref: target.contextHref,\n pagePath: target.pagePath,\n contextTitle: target.title,\n },\n },\n },\n });\n const conversation = res.data?.resolveContextConversation.conversation;\n if (!conversation) throw new Error('Could not open the conversation');\n return { id: conversation.id, created: res.data?.resolveContextConversation.created ?? false };\n },\n [resolve, workspaceId]\n );\n\n return { openConversation, loading };\n};\n\nexport const useSendMessage = () => {\n const [send, { loading }] = useMutation<{ sendMessage: { success: boolean } }>(SEND_MESSAGE);\n const sendMessage = useCallback(\n async (conversationId: string, text: string): Promise<void> => {\n const res = await send({\n variables: { input: { conversationId, content: { text } } },\n refetchQueries: ['HvConversationMessages'],\n awaitRefetchQueries: true,\n });\n if (!res.data?.sendMessage.success) throw new Error('Message was not sent');\n },\n [send]\n );\n return { sendMessage, loading };\n};\n\n/**\n * Send a message WITH file attachments.\n *\n * `sendMessage`'s `attachmentIds` only stores bare file ids — the subgraph's\n * `Attachment.fileName`/`downloadUrl` resolvers read their values out of the\n * attachment row's metadata, so an id-only attachment comes back rendering its\n * own uuid with no download link. `sendContextMessage` is the mutation that\n * accepts full `ContextMessageAttachmentInput` details, so it is the only path\n * that yields a readable attachment. It resolves the conversation from the\n * thread's `sourceContext` (idempotent on `threadKey`), which is why the caller\n * must hand back the SAME sourceContext the thread was created with.\n */\nexport const useSendContextMessage = () => {\n const { workspaceId } = useHousingVista();\n const [send, { loading }] = useMutation<{ sendContextMessage: { success: boolean } }>(SEND_CONTEXT_MESSAGE);\n\n const sendContextMessage = useCallback(\n async (args: {\n sourceContext: HvConversationSourceContext;\n text: string;\n attachments: HvUploadedFile[];\n }): Promise<void> => {\n const res = await send({\n variables: {\n input: {\n workspaceId,\n sourceContext: args.sourceContext,\n content: { text: args.text },\n type: args.attachments.length > 0 ? 'FILE' : 'TEXT',\n attachments: args.attachments.map((file) => ({\n fileId: file.id,\n fileName: file.name,\n fileSize: file.size,\n mimeType: file.mimeType,\n downloadUrl: file.url || undefined,\n })),\n },\n },\n refetchQueries: ['HvConversationMessages'],\n awaitRefetchQueries: true,\n });\n if (!res.data?.sendContextMessage.success) throw new Error('Message was not sent');\n },\n [send, workspaceId]\n );\n\n return { sendContextMessage, loading };\n};\n\nexport const useConversationMessages = (conversationId: string | undefined, first = 50) => {\n const { data, loading, error, refetch } = useQuery<ConversationMessagesResult>(GET_CONVERSATION_MESSAGES, {\n variables: { id: conversationId ?? '', first },\n skip: !conversationId,\n });\n const messages: HvConversationMessage[] = (data?.conversation?.messages.edges ?? []).map((edge) => ({\n id: edge.node.id,\n authorId: edge.node.authorId,\n authorName: edge.node.authorName,\n text: edge.node.content?.text ?? '',\n createdAt: edge.node.createdAt,\n attachments: edge.node.attachments ?? [],\n }));\n return { data: messages, title: data?.conversation?.title ?? null, loading, error, refetch };\n};\n\n// ---------------------------------------------------------------------------\n// Entity comments — per-listing Q&A + reviews\n// ---------------------------------------------------------------------------\n\nconst GET_ENTITY_COMMENTS = gql`\n query HvEntityComments($input: GetCommentsInput!) {\n getEntityComments(input: $input) {\n total\n items {\n id\n authorId\n authorType\n isAnonymous\n createdAt\n metadata\n content {\n text\n }\n }\n }\n }\n`;\n\nconst CREATE_ENTITY_COMMENT = gql`\n mutation HvCreateEntityComment($input: CreateEntityCommentInput!) {\n createEntityComment(input: $input) {\n id\n createdAt\n }\n }\n`;\n\nexport interface HvEntityComment {\n id: string;\n authorId: string;\n text: string;\n createdAt: string;\n /** Free-form; reviews carry `{ stars: number }`. */\n metadata: Record<string, unknown> | null;\n}\n\ninterface EntityCommentsResult {\n getEntityComments: {\n total: number;\n items: {\n id: string;\n authorId: string;\n authorType: string;\n isAnonymous: boolean;\n createdAt: string;\n metadata: Record<string, unknown> | null;\n content: { text: string | null } | null;\n }[];\n };\n}\n\nexport const useEntityComments = (entityType: string, entityId: string | undefined, take = 50) => {\n const { data, loading, error, refetch } = useQuery<EntityCommentsResult>(GET_ENTITY_COMMENTS, {\n variables: { input: { entityType, entityId: entityId ?? '', take, sortBy: 'createdAt', sortOrder: 'desc' } },\n skip: !entityId,\n });\n const comments: HvEntityComment[] = (data?.getEntityComments.items ?? []).map((item) => ({\n id: item.id,\n authorId: item.authorId,\n text: item.content?.text ?? '',\n createdAt: item.createdAt,\n metadata: item.metadata,\n }));\n return { data: comments, total: data?.getEntityComments.total ?? 0, loading, error, refetch };\n};\n\nexport const useCreateEntityComment = () => {\n const [mutate, { loading }] = useMutation<{ createEntityComment: { id: string } }>(CREATE_ENTITY_COMMENT);\n const createComment = useCallback(\n async (args: {\n entityType: string;\n entityId: string;\n text: string;\n metadata?: Record<string, unknown>;\n }): Promise<void> => {\n await mutate({\n variables: {\n input: {\n entityType: args.entityType,\n entityId: args.entityId,\n content: { text: args.text },\n metadata: args.metadata,\n },\n },\n refetchQueries: ['HvEntityComments'],\n awaitRefetchQueries: true,\n });\n },\n [mutate]\n );\n return { createComment, loading };\n};\n\n// ---------------------------------------------------------------------------\n// Files — presigned upload (initiateUpload → PUT → completeUpload)\n// ---------------------------------------------------------------------------\n\nconst INITIATE_UPLOAD = gql`\n mutation HvInitiateUpload($input: InitiateUploadInput!) {\n initiateUpload(input: $input) {\n uploadUrl\n session {\n id\n }\n }\n }\n`;\n\nconst COMPLETE_UPLOAD = gql`\n mutation HvCompleteUpload($input: CompleteUploadInput!) {\n completeUpload(input: $input) {\n fileId\n file {\n id\n name\n downloadUrl\n mimeType\n size\n }\n }\n }\n`;\n\nexport interface HvUploadedFile {\n id: string;\n name: string;\n url: string;\n mimeType: string;\n size: number;\n}\n\ninterface InitiateUploadResult {\n initiateUpload: { uploadUrl: string | null; session: { id: string } };\n}\n\ninterface CompleteUploadResult {\n completeUpload: {\n fileId: string;\n file: { id: string; name: string; downloadUrl: string | null; mimeType: string; size: number };\n };\n}\n\nconst splitExtension = (fileName: string): string => {\n const dot = fileName.lastIndexOf('.');\n return dot > 0 && dot < fileName.length - 1 ? fileName.slice(dot + 1).toLowerCase() : 'bin';\n};\n\n/**\n * Upload a real browser `File` through wspace-files-svc and return the durable\n * File id + download URL. Single-PUT presigned flow (fine for the image /\n * document sizes HousingVista deals with).\n */\nexport const useFileUpload = () => {\n const [initiate] = useMutation<InitiateUploadResult>(INITIATE_UPLOAD);\n const [complete] = useMutation<CompleteUploadResult>(COMPLETE_UPLOAD);\n\n const uploadFile = useCallback(\n async (file: File): Promise<HvUploadedFile> => {\n const extension = splitExtension(file.name);\n const mimeType = file.type || 'application/octet-stream';\n const initiated = await initiate({\n variables: {\n input: {\n fileName: file.name,\n extension,\n fileSize: file.size,\n mimeType,\n visibility: 'WORKSPACE',\n },\n },\n });\n const uploadUrl = initiated.data?.initiateUpload.uploadUrl;\n const sessionId = initiated.data?.initiateUpload.session.id;\n if (!uploadUrl || !sessionId) throw new Error('Upload could not be started');\n\n const putRes = await fetch(uploadUrl, {\n method: 'PUT',\n body: file,\n headers: { 'Content-Type': mimeType },\n });\n if (!putRes.ok) throw new Error(`Upload failed (${putRes.status})`);\n\n const completed = await complete({\n variables: { input: { sessionId, fileSize: file.size } },\n });\n const uploaded = completed.data?.completeUpload.file;\n if (!uploaded) throw new Error('Upload could not be finalized');\n return {\n id: uploaded.id,\n name: uploaded.name,\n url: uploaded.downloadUrl ?? '',\n mimeType: uploaded.mimeType,\n size: Number(uploaded.size),\n };\n },\n [initiate, complete]\n );\n\n return { uploadFile };\n};\n"],"mappings":"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"}
|