hazo_chat 1.1.0 → 2.0.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/README.md +161 -152
- package/SETUP_CHECKLIST.md +191 -587
- package/dist/api/index.d.ts +24 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +24 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/messages.d.ts +34 -0
- package/dist/api/messages.d.ts.map +1 -0
- package/dist/api/messages.js +210 -0
- package/dist/api/messages.js.map +1 -0
- package/dist/api/types.d.ts +69 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +8 -0
- package/dist/api/types.js.map +1 -0
- package/dist/components/hazo_chat/hazo_chat.d.ts +13 -1
- package/dist/components/hazo_chat/hazo_chat.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat.js +26 -14
- package/dist/components/hazo_chat/hazo_chat.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_context.d.ts +11 -5
- package/dist/components/hazo_chat/hazo_chat_context.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_context.js +22 -10
- package/dist/components/hazo_chat/hazo_chat_context.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.d.ts +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_header.js +3 -3
- package/dist/components/hazo_chat/hazo_chat_header.js.map +1 -1
- package/dist/hooks/use_chat_messages.d.ts +14 -9
- package/dist/hooks/use_chat_messages.d.ts.map +1 -1
- package/dist/hooks/use_chat_messages.js +117 -115
- package/dist/hooks/use_chat_messages.js.map +1 -1
- package/dist/types/index.d.ts +39 -28
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -1
- package/package.json +17 -7
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Provides centralized state management for:
|
|
5
5
|
* - Selected reference/document
|
|
6
|
-
* - Current user profile (
|
|
6
|
+
* - Current user profile (fetched via API)
|
|
7
7
|
* - Pending file attachments
|
|
8
8
|
* - Sidebar collapsed state (mobile)
|
|
9
9
|
* - Polling connection status
|
|
10
10
|
* - Error handling
|
|
11
|
+
*
|
|
12
|
+
* Uses API calls to fetch user data - no server-side dependencies.
|
|
11
13
|
*/
|
|
12
14
|
'use client';
|
|
13
15
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -94,26 +96,36 @@ const HazoChatContext = createContext(null);
|
|
|
94
96
|
/**
|
|
95
97
|
* HazoChatProvider - Context provider for HazoChat component tree
|
|
96
98
|
*
|
|
99
|
+
* Fetches current user via API on mount.
|
|
100
|
+
*
|
|
97
101
|
* @param children - Child components
|
|
98
|
-
* @param
|
|
102
|
+
* @param api_base_url - Base URL for API endpoints
|
|
99
103
|
* @param initial_references - Initial references from props
|
|
100
104
|
*/
|
|
101
|
-
export function HazoChatProvider({ children,
|
|
105
|
+
export function HazoChatProvider({ children, api_base_url = '/api/hazo_chat', initial_references = [] }) {
|
|
102
106
|
const [state, dispatch] = useReducer(hazo_chat_reducer, {
|
|
103
107
|
...initial_state,
|
|
104
108
|
all_references: initial_references
|
|
105
109
|
});
|
|
106
110
|
// -------------------------------------------------------------------------
|
|
107
|
-
// Load current user on mount
|
|
111
|
+
// Load current user on mount via API
|
|
108
112
|
// -------------------------------------------------------------------------
|
|
109
113
|
useEffect(() => {
|
|
110
114
|
async function load_current_user() {
|
|
111
115
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
// Try to get current user from hazo_auth me endpoint
|
|
117
|
+
const response = await fetch('/api/hazo_auth/me');
|
|
118
|
+
if (response.ok) {
|
|
119
|
+
const data = await response.json();
|
|
120
|
+
if (data.authenticated && data.user) {
|
|
121
|
+
// Build user profile from response
|
|
122
|
+
const user_profile = {
|
|
123
|
+
id: data.user.id,
|
|
124
|
+
name: data.user.name || data.user.email?.split('@')[0] || 'User',
|
|
125
|
+
email: data.user.email,
|
|
126
|
+
avatar_url: data.user.profile_picture_url
|
|
127
|
+
};
|
|
128
|
+
dispatch({ type: 'SET_CURRENT_USER', payload: user_profile });
|
|
117
129
|
}
|
|
118
130
|
}
|
|
119
131
|
}
|
|
@@ -126,7 +138,7 @@ export function HazoChatProvider({ children, hazo_auth, initial_references = []
|
|
|
126
138
|
}
|
|
127
139
|
}
|
|
128
140
|
load_current_user();
|
|
129
|
-
}, [
|
|
141
|
+
}, [api_base_url]);
|
|
130
142
|
// -------------------------------------------------------------------------
|
|
131
143
|
// Action creators
|
|
132
144
|
// -------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_chat_context.js","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_context.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hazo_chat_context.js","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_context.tsx"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* Uses shadcn/ui Button and Tooltip components.
|
|
10
10
|
*/
|
|
11
11
|
import type { HazoChatHeaderProps } from '../../types/index.js';
|
|
12
|
-
export declare function HazoChatHeader({ title, subtitle, on_close, on_toggle_sidebar, is_sidebar_open, className }: HazoChatHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function HazoChatHeader({ title, subtitle, on_close, on_refresh, is_refreshing, on_toggle_sidebar, is_sidebar_open, className }: HazoChatHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
13
13
|
export declare namespace HazoChatHeader {
|
|
14
14
|
var displayName: string;
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_chat_header.d.ts","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_header.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAYhE,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,eAAe,EACf,SAAS,EACV,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"hazo_chat_header.d.ts","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_header.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAYhE,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,SAAS,EACV,EAAE,mBAAmB,2CAiHrB;yBA1He,cAAc"}
|
|
@@ -10,15 +10,15 @@
|
|
|
10
10
|
*/
|
|
11
11
|
'use client';
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import { IoClose, IoMenuOutline } from 'react-icons/io5';
|
|
13
|
+
import { IoClose, IoMenuOutline, IoRefresh } from 'react-icons/io5';
|
|
14
14
|
import { cn } from '../../lib/utils.js';
|
|
15
15
|
import { Button } from '../ui/button.js';
|
|
16
16
|
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip.js';
|
|
17
17
|
// ============================================================================
|
|
18
18
|
// Component
|
|
19
19
|
// ============================================================================
|
|
20
|
-
export function HazoChatHeader({ title, subtitle, on_close, on_toggle_sidebar, is_sidebar_open, className }) {
|
|
21
|
-
return (_jsxs("header", { className: cn('cls_hazo_chat_header', 'flex items-center justify-between', 'h-14 px-4', 'border-b border-border/40', 'bg-card/80 backdrop-blur-md', 'shadow-sm', className), children: [_jsxs("div", { className: "cls_header_left flex items-center gap-3", children: [on_toggle_sidebar && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", onClick: on_toggle_sidebar, className: cn('cls_sidebar_toggle md:hidden', 'h-8 w-8 rounded-md', 'hover:bg-accent hover:text-accent-foreground', 'transition-colors'), "aria-label": is_sidebar_open ? 'Close sidebar' : 'Open sidebar', "aria-expanded": is_sidebar_open, children: _jsx(IoMenuOutline, { className: "h-5 w-5" }) }) }), _jsx(TooltipContent, { side: "bottom", className: "text-xs", children: is_sidebar_open ? 'Close sidebar' : 'Open sidebar' })] })), _jsxs("div", { className: "cls_header_titles flex flex-col gap-0.5", children: [title && (_jsx("h2", { className: "cls_header_title text-sm font-semibold tracking-tight text-foreground", children: title })), subtitle && (_jsx("p", { className: "cls_header_subtitle text-xs font-medium text-muted-foreground", children: subtitle }))] })] }), on_close && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", onClick: on_close, className: cn('cls_header_close', 'h-8 w-8 rounded-md', 'text-muted-foreground', 'hover:bg-destructive/10 hover:text-destructive', 'transition-colors'), "aria-label": "Close chat", children: _jsx(IoClose, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "bottom", className: "text-xs", children: "Close chat" })] }))] }));
|
|
20
|
+
export function HazoChatHeader({ title, subtitle, on_close, on_refresh, is_refreshing, on_toggle_sidebar, is_sidebar_open, className }) {
|
|
21
|
+
return (_jsxs("header", { className: cn('cls_hazo_chat_header', 'flex items-center justify-between', 'h-14 px-4', 'border-b border-border/40', 'bg-card/80 backdrop-blur-md', 'shadow-sm', className), children: [_jsxs("div", { className: "cls_header_left flex items-center gap-3", children: [on_toggle_sidebar && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", onClick: on_toggle_sidebar, className: cn('cls_sidebar_toggle md:hidden', 'h-8 w-8 rounded-md', 'hover:bg-accent hover:text-accent-foreground', 'transition-colors'), "aria-label": is_sidebar_open ? 'Close sidebar' : 'Open sidebar', "aria-expanded": is_sidebar_open, children: _jsx(IoMenuOutline, { className: "h-5 w-5" }) }) }), _jsx(TooltipContent, { side: "bottom", className: "text-xs", children: is_sidebar_open ? 'Close sidebar' : 'Open sidebar' })] })), _jsxs("div", { className: "cls_header_titles flex flex-col gap-0.5", children: [title && (_jsx("h2", { className: "cls_header_title text-sm font-semibold tracking-tight text-foreground", children: title })), subtitle && (_jsx("p", { className: "cls_header_subtitle text-xs font-medium text-muted-foreground", children: subtitle }))] })] }), _jsxs("div", { className: "cls_header_right flex items-center gap-1", children: [on_refresh && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", onClick: on_refresh, disabled: is_refreshing, className: cn('cls_header_refresh', 'h-8 w-8 rounded-md', 'text-muted-foreground', 'hover:bg-accent hover:text-accent-foreground', 'transition-colors'), "aria-label": "Refresh chat history", children: _jsx(IoRefresh, { className: cn('h-4 w-4', is_refreshing && 'animate-spin') }) }) }), _jsx(TooltipContent, { side: "bottom", className: "text-xs", children: "Refresh chat" })] })), on_close && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", onClick: on_close, className: cn('cls_header_close', 'h-8 w-8 rounded-md', 'text-muted-foreground', 'hover:bg-destructive/10 hover:text-destructive', 'transition-colors'), "aria-label": "Close chat", children: _jsx(IoClose, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "bottom", className: "text-xs", children: "Close chat" })] }))] })] }));
|
|
22
22
|
}
|
|
23
23
|
HazoChatHeader.displayName = 'HazoChatHeader';
|
|
24
24
|
//# sourceMappingURL=hazo_chat_header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_chat_header.js","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_header.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,YAAY,CAAC;;AAGb,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"hazo_chat_header.js","sourceRoot":"","sources":["../../../src/components/hazo_chat/hazo_chat_header.tsx"],"names":[],"mappings":"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"}
|
|
@@ -8,18 +8,23 @@
|
|
|
8
8
|
* - Soft delete functionality
|
|
9
9
|
* - Exponential backoff on errors
|
|
10
10
|
*
|
|
11
|
-
* Uses
|
|
11
|
+
* Uses fetch() to call API endpoints instead of direct database access.
|
|
12
|
+
* This allows the hook to work in client components without Node.js dependencies.
|
|
12
13
|
*/
|
|
13
|
-
import type {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
hazo_connect: HazoConnectAdapter;
|
|
17
|
-
hazo_auth: HazoAuthInstance;
|
|
18
|
-
reference_id?: string;
|
|
14
|
+
import type { UseChatMessagesReturn } from '../types/index.js';
|
|
15
|
+
export interface UseChatMessagesParams {
|
|
16
|
+
/** UUID of the chat recipient (required) */
|
|
19
17
|
receiver_user_id: string;
|
|
18
|
+
/** Reference ID for chat context grouping */
|
|
19
|
+
reference_id?: string;
|
|
20
|
+
/** Reference type (default: 'chat') */
|
|
21
|
+
reference_type?: string;
|
|
22
|
+
/** Base URL for API endpoints (default: '/api/hazo_chat') */
|
|
23
|
+
api_base_url?: string;
|
|
24
|
+
/** Polling interval in milliseconds (default: 3000) */
|
|
20
25
|
polling_interval?: number;
|
|
26
|
+
/** Number of messages per page for pagination (default: 20) */
|
|
21
27
|
messages_per_page?: number;
|
|
22
28
|
}
|
|
23
|
-
export declare function useChatMessages({
|
|
24
|
-
export {};
|
|
29
|
+
export declare function useChatMessages({ receiver_user_id, reference_id, reference_type, api_base_url, polling_interval, messages_per_page }: UseChatMessagesParams): UseChatMessagesReturn;
|
|
25
30
|
//# sourceMappingURL=use_chat_messages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use_chat_messages.d.ts","sourceRoot":"","sources":["../../src/hooks/use_chat_messages.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"use_chat_messages.d.ts","sourceRoot":"","sources":["../../src/hooks/use_chat_messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAKV,qBAAqB,EAEtB,MAAM,mBAAmB,CAAC;AAY3B,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA6BD,wBAAgB,eAAe,CAAC,EAC9B,gBAAgB,EAChB,YAAiB,EACjB,cAAuB,EACvB,YAA+B,EAC/B,gBAA2C,EAC3C,iBAA6C,EAC9C,EAAE,qBAAqB,GAAG,qBAAqB,CA2f/C"}
|
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
* - Soft delete functionality
|
|
9
9
|
* - Exponential backoff on errors
|
|
10
10
|
*
|
|
11
|
-
* Uses
|
|
11
|
+
* Uses fetch() to call API endpoints instead of direct database access.
|
|
12
|
+
* This allows the hook to work in client components without Node.js dependencies.
|
|
12
13
|
*/
|
|
13
14
|
'use client';
|
|
14
15
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
15
|
-
import { createTableQuery } from 'hazo_connect/server';
|
|
16
16
|
import { DEFAULT_POLLING_INTERVAL, DEFAULT_MESSAGES_PER_PAGE, MAX_RETRY_ATTEMPTS, RETRY_BASE_DELAY } from '../lib/constants.js';
|
|
17
17
|
// ============================================================================
|
|
18
18
|
// Hook Implementation
|
|
19
19
|
// ============================================================================
|
|
20
|
-
export function useChatMessages({
|
|
20
|
+
export function useChatMessages({ receiver_user_id, reference_id = '', reference_type = 'chat', api_base_url = '/api/hazo_chat', polling_interval = DEFAULT_POLLING_INTERVAL, messages_per_page = DEFAULT_MESSAGES_PER_PAGE }) {
|
|
21
21
|
// -------------------------------------------------------------------------
|
|
22
22
|
// State
|
|
23
23
|
// -------------------------------------------------------------------------
|
|
@@ -37,43 +37,45 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
37
37
|
const polling_timer_ref = useRef(null);
|
|
38
38
|
const is_mounted_ref = useRef(true);
|
|
39
39
|
// -------------------------------------------------------------------------
|
|
40
|
-
//
|
|
40
|
+
// Cleanup on unmount
|
|
41
41
|
// -------------------------------------------------------------------------
|
|
42
42
|
useEffect(() => {
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const auth_user = await hazo_auth.hazo_get_auth();
|
|
46
|
-
if (auth_user && is_mounted_ref.current) {
|
|
47
|
-
set_current_user_id(auth_user.id);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
console.error('[useChatMessages] Failed to get current user:', err);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
get_current_user();
|
|
43
|
+
is_mounted_ref.current = true;
|
|
55
44
|
return () => {
|
|
56
45
|
is_mounted_ref.current = false;
|
|
46
|
+
if (polling_timer_ref.current) {
|
|
47
|
+
clearInterval(polling_timer_ref.current);
|
|
48
|
+
}
|
|
57
49
|
};
|
|
58
|
-
}, [
|
|
50
|
+
}, []);
|
|
59
51
|
// -------------------------------------------------------------------------
|
|
60
|
-
// Fetch user profiles
|
|
52
|
+
// Fetch user profiles via API
|
|
61
53
|
// -------------------------------------------------------------------------
|
|
62
54
|
const fetch_user_profiles = useCallback(async (user_ids) => {
|
|
63
55
|
const uncached_ids = user_ids.filter((id) => !user_profiles_cache_ref.current.has(id));
|
|
64
56
|
if (uncached_ids.length > 0) {
|
|
65
57
|
try {
|
|
66
|
-
|
|
67
|
-
profiles
|
|
68
|
-
|
|
58
|
+
// Use the hazo_auth profiles endpoint
|
|
59
|
+
const response = await fetch('/api/hazo_auth/profiles', {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: { 'Content-Type': 'application/json' },
|
|
62
|
+
body: JSON.stringify({ user_ids: uncached_ids }),
|
|
69
63
|
});
|
|
64
|
+
if (response.ok) {
|
|
65
|
+
const data = await response.json();
|
|
66
|
+
if (data.success && data.profiles) {
|
|
67
|
+
data.profiles.forEach((profile) => {
|
|
68
|
+
user_profiles_cache_ref.current.set(profile.id, profile);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
70
72
|
}
|
|
71
73
|
catch (err) {
|
|
72
74
|
console.error('[useChatMessages] Failed to fetch user profiles:', err);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
return user_profiles_cache_ref.current;
|
|
76
|
-
}, [
|
|
78
|
+
}, []);
|
|
77
79
|
// -------------------------------------------------------------------------
|
|
78
80
|
// Transform DB messages to ChatMessage
|
|
79
81
|
// -------------------------------------------------------------------------
|
|
@@ -96,49 +98,59 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
96
98
|
}));
|
|
97
99
|
}, [fetch_user_profiles]);
|
|
98
100
|
// -------------------------------------------------------------------------
|
|
99
|
-
// Fetch messages
|
|
101
|
+
// Fetch messages via API
|
|
100
102
|
// -------------------------------------------------------------------------
|
|
101
|
-
const
|
|
102
|
-
if (!
|
|
103
|
-
return [];
|
|
103
|
+
const fetch_messages_from_api = useCallback(async () => {
|
|
104
|
+
if (!receiver_user_id) {
|
|
105
|
+
return { messages: [], user_id: null };
|
|
104
106
|
}
|
|
105
107
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
const params = new URLSearchParams({
|
|
109
|
+
receiver_user_id,
|
|
110
|
+
...(reference_id && { reference_id }),
|
|
111
|
+
...(reference_type && { reference_type }),
|
|
112
|
+
});
|
|
113
|
+
const response = await fetch(`${api_base_url}/messages?${params.toString()}`);
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
throw new Error(`HTTP ${response.status}`);
|
|
116
|
+
}
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
if (data.success) {
|
|
119
|
+
return {
|
|
120
|
+
messages: data.messages || [],
|
|
121
|
+
user_id: data.current_user_id || null
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new Error(data.error || 'Failed to fetch messages');
|
|
126
|
+
}
|
|
120
127
|
}
|
|
121
128
|
catch (err) {
|
|
122
129
|
console.error('[useChatMessages] Fetch error:', err);
|
|
123
130
|
throw err;
|
|
124
131
|
}
|
|
125
|
-
}, [
|
|
132
|
+
}, [receiver_user_id, reference_id, reference_type, api_base_url]);
|
|
126
133
|
// -------------------------------------------------------------------------
|
|
127
134
|
// Initial load
|
|
128
135
|
// -------------------------------------------------------------------------
|
|
129
136
|
const load_initial = useCallback(async () => {
|
|
130
|
-
if (!
|
|
137
|
+
if (!receiver_user_id) {
|
|
131
138
|
set_is_loading(false);
|
|
132
139
|
return;
|
|
133
140
|
}
|
|
134
141
|
set_is_loading(true);
|
|
135
142
|
set_error(null);
|
|
136
143
|
try {
|
|
137
|
-
const db_messages = await
|
|
138
|
-
|
|
144
|
+
const { messages: db_messages, user_id } = await fetch_messages_from_api();
|
|
145
|
+
if (user_id && is_mounted_ref.current) {
|
|
146
|
+
set_current_user_id(user_id);
|
|
147
|
+
}
|
|
139
148
|
if (is_mounted_ref.current) {
|
|
149
|
+
const transformed = user_id
|
|
150
|
+
? await transform_messages(db_messages, user_id)
|
|
151
|
+
: db_messages.map(msg => ({ ...msg, is_sender: false, send_status: 'sent' }));
|
|
140
152
|
set_messages(transformed);
|
|
141
|
-
set_has_more(db_messages.length
|
|
153
|
+
set_has_more(db_messages.length >= messages_per_page);
|
|
142
154
|
cursor_ref.current = db_messages.length;
|
|
143
155
|
retry_count_ref.current = 0;
|
|
144
156
|
set_polling_status('connected');
|
|
@@ -155,9 +167,9 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
155
167
|
set_is_loading(false);
|
|
156
168
|
}
|
|
157
169
|
}
|
|
158
|
-
}, [
|
|
170
|
+
}, [receiver_user_id, fetch_messages_from_api, transform_messages, messages_per_page]);
|
|
159
171
|
// -------------------------------------------------------------------------
|
|
160
|
-
// Load more (pagination)
|
|
172
|
+
// Load more (pagination) - Note: simplified, API should support pagination params
|
|
161
173
|
// -------------------------------------------------------------------------
|
|
162
174
|
const load_more = useCallback(async () => {
|
|
163
175
|
if (!current_user_id || !has_more || is_loading_more) {
|
|
@@ -165,12 +177,13 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
165
177
|
}
|
|
166
178
|
set_is_loading_more(true);
|
|
167
179
|
try {
|
|
168
|
-
|
|
180
|
+
// For now, reload all messages - pagination can be added to API later
|
|
181
|
+
const { messages: db_messages } = await fetch_messages_from_api();
|
|
169
182
|
const transformed = await transform_messages(db_messages, current_user_id);
|
|
170
183
|
if (is_mounted_ref.current) {
|
|
171
|
-
set_messages(
|
|
172
|
-
set_has_more(
|
|
173
|
-
cursor_ref.current
|
|
184
|
+
set_messages(transformed);
|
|
185
|
+
set_has_more(false); // Simplified - loaded all
|
|
186
|
+
cursor_ref.current = db_messages.length;
|
|
174
187
|
}
|
|
175
188
|
}
|
|
176
189
|
catch (err) {
|
|
@@ -181,41 +194,30 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
181
194
|
set_is_loading_more(false);
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
|
-
}, [current_user_id, has_more, is_loading_more,
|
|
197
|
+
}, [current_user_id, has_more, is_loading_more, fetch_messages_from_api, transform_messages]);
|
|
185
198
|
// -------------------------------------------------------------------------
|
|
186
199
|
// Poll for new messages
|
|
187
200
|
// -------------------------------------------------------------------------
|
|
188
201
|
const poll_for_new_messages = useCallback(async () => {
|
|
189
|
-
if (!current_user_id || !
|
|
202
|
+
if (!current_user_id || !receiver_user_id) {
|
|
190
203
|
return;
|
|
191
204
|
}
|
|
192
205
|
try {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
let query = createTableQuery(hazo_connect, 'hazo_chat')
|
|
197
|
-
.select('*')
|
|
198
|
-
.where('reference_id', 'eq', reference_id)
|
|
199
|
-
.whereOr([
|
|
200
|
-
{ field: 'sender_user_id', operator: 'eq', value: current_user_id },
|
|
201
|
-
{ field: 'receiver_user_id', operator: 'eq', value: current_user_id }
|
|
202
|
-
])
|
|
203
|
-
.order('created_at', 'desc');
|
|
204
|
-
// If we have messages, only fetch newer ones
|
|
205
|
-
if (newest_timestamp) {
|
|
206
|
-
query = query.where('created_at', 'gt', newest_timestamp);
|
|
207
|
-
}
|
|
208
|
-
// Execute with limit
|
|
209
|
-
const data = await query.limit(50).execute('GET');
|
|
210
|
-
const new_messages = data || [];
|
|
211
|
-
if (new_messages.length > 0 && is_mounted_ref.current) {
|
|
212
|
-
const transformed = await transform_messages(new_messages, current_user_id);
|
|
206
|
+
const { messages: db_messages } = await fetch_messages_from_api();
|
|
207
|
+
if (db_messages.length > 0 && is_mounted_ref.current) {
|
|
208
|
+
const transformed = await transform_messages(db_messages, current_user_id);
|
|
213
209
|
set_messages((prev) => {
|
|
214
|
-
//
|
|
215
|
-
const
|
|
216
|
-
|
|
210
|
+
// Merge new messages, avoiding duplicates
|
|
211
|
+
const existing_ids = new Set(prev.map(m => m.id));
|
|
212
|
+
const new_messages = transformed.filter(m => !existing_ids.has(m.id));
|
|
213
|
+
if (new_messages.length > 0) {
|
|
214
|
+
// Combine and sort by created_at
|
|
215
|
+
const combined = [...prev, ...new_messages];
|
|
216
|
+
combined.sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
217
|
+
return combined;
|
|
218
|
+
}
|
|
219
|
+
return prev;
|
|
217
220
|
});
|
|
218
|
-
cursor_ref.current += new_messages.length;
|
|
219
221
|
}
|
|
220
222
|
retry_count_ref.current = 0;
|
|
221
223
|
if (is_mounted_ref.current) {
|
|
@@ -234,12 +236,12 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
234
236
|
}
|
|
235
237
|
}
|
|
236
238
|
}
|
|
237
|
-
}, [current_user_id,
|
|
239
|
+
}, [current_user_id, receiver_user_id, fetch_messages_from_api, transform_messages]);
|
|
238
240
|
// -------------------------------------------------------------------------
|
|
239
241
|
// Start polling
|
|
240
242
|
// -------------------------------------------------------------------------
|
|
241
243
|
useEffect(() => {
|
|
242
|
-
if (!
|
|
244
|
+
if (!receiver_user_id) {
|
|
243
245
|
return;
|
|
244
246
|
}
|
|
245
247
|
// Clear any existing timer
|
|
@@ -265,7 +267,7 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
265
267
|
clearInterval(polling_timer_ref.current);
|
|
266
268
|
}
|
|
267
269
|
};
|
|
268
|
-
}, [
|
|
270
|
+
}, [receiver_user_id, polling_interval, poll_for_new_messages]);
|
|
269
271
|
// -------------------------------------------------------------------------
|
|
270
272
|
// Initial load effect
|
|
271
273
|
// -------------------------------------------------------------------------
|
|
@@ -273,7 +275,7 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
273
275
|
load_initial();
|
|
274
276
|
}, [load_initial]);
|
|
275
277
|
// -------------------------------------------------------------------------
|
|
276
|
-
// Send message
|
|
278
|
+
// Send message via API
|
|
277
279
|
// -------------------------------------------------------------------------
|
|
278
280
|
const send_message = useCallback(async (payload) => {
|
|
279
281
|
if (!current_user_id) {
|
|
@@ -300,32 +302,34 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
300
302
|
send_status: 'sending'
|
|
301
303
|
};
|
|
302
304
|
// Add optimistic message to state
|
|
303
|
-
set_messages((prev) => [
|
|
305
|
+
set_messages((prev) => [...prev, optimistic_message]);
|
|
304
306
|
try {
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const data = await
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
if (result && is_mounted_ref.current) {
|
|
307
|
+
const response = await fetch(`${api_base_url}/messages`, {
|
|
308
|
+
method: 'POST',
|
|
309
|
+
headers: { 'Content-Type': 'application/json' },
|
|
310
|
+
body: JSON.stringify({
|
|
311
|
+
receiver_user_id: payload.receiver_user_id,
|
|
312
|
+
message_text: payload.message_text,
|
|
313
|
+
reference_id: payload.reference_id,
|
|
314
|
+
reference_type: payload.reference_type,
|
|
315
|
+
}),
|
|
316
|
+
});
|
|
317
|
+
const data = await response.json();
|
|
318
|
+
if (data.success && data.message && is_mounted_ref.current) {
|
|
319
|
+
// Replace optimistic message with real one
|
|
319
320
|
const real_message = {
|
|
320
|
-
...
|
|
321
|
+
...data.message,
|
|
321
322
|
sender_profile: user_profiles_cache_ref.current.get(current_user_id),
|
|
322
323
|
receiver_profile: user_profiles_cache_ref.current.get(payload.receiver_user_id),
|
|
323
324
|
is_sender: true,
|
|
324
325
|
send_status: 'sent'
|
|
325
326
|
};
|
|
326
327
|
set_messages((prev) => prev.map((msg) => msg.id === optimistic_id ? real_message : msg));
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
throw new Error(data.error || 'Failed to send message');
|
|
327
332
|
}
|
|
328
|
-
return true;
|
|
329
333
|
}
|
|
330
334
|
catch (err) {
|
|
331
335
|
console.error('[useChatMessages] Send error:', err);
|
|
@@ -337,9 +341,9 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
337
341
|
}
|
|
338
342
|
return false;
|
|
339
343
|
}
|
|
340
|
-
}, [current_user_id,
|
|
344
|
+
}, [current_user_id, api_base_url]);
|
|
341
345
|
// -------------------------------------------------------------------------
|
|
342
|
-
// Delete message (soft delete)
|
|
346
|
+
// Delete message (soft delete) via API
|
|
343
347
|
// -------------------------------------------------------------------------
|
|
344
348
|
const delete_message = useCallback(async (message_id) => {
|
|
345
349
|
if (!current_user_id) {
|
|
@@ -356,11 +360,12 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
356
360
|
? { ...msg, deleted_at: new Date().toISOString(), message_text: null }
|
|
357
361
|
: msg));
|
|
358
362
|
try {
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
363
|
+
const response = await fetch(`${api_base_url}/messages/${message_id}`, {
|
|
364
|
+
method: 'DELETE',
|
|
365
|
+
});
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
throw new Error('Failed to delete message');
|
|
368
|
+
}
|
|
364
369
|
return true;
|
|
365
370
|
}
|
|
366
371
|
catch (err) {
|
|
@@ -373,9 +378,9 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
373
378
|
}
|
|
374
379
|
return false;
|
|
375
380
|
}
|
|
376
|
-
}, [current_user_id, messages,
|
|
381
|
+
}, [current_user_id, messages, api_base_url]);
|
|
377
382
|
// -------------------------------------------------------------------------
|
|
378
|
-
// Mark as read
|
|
383
|
+
// Mark as read via API
|
|
379
384
|
// -------------------------------------------------------------------------
|
|
380
385
|
const mark_as_read = useCallback(async (message_id) => {
|
|
381
386
|
if (!current_user_id) {
|
|
@@ -386,13 +391,10 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
386
391
|
return;
|
|
387
392
|
}
|
|
388
393
|
try {
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
await query.execute('PATCH', update_data);
|
|
394
|
-
// Update local state
|
|
395
|
-
if (is_mounted_ref.current) {
|
|
394
|
+
const response = await fetch(`${api_base_url}/messages/${message_id}/read`, {
|
|
395
|
+
method: 'PATCH',
|
|
396
|
+
});
|
|
397
|
+
if (response.ok && is_mounted_ref.current) {
|
|
396
398
|
set_messages((prev) => prev.map((msg) => msg.id === message_id
|
|
397
399
|
? { ...msg, read_at: new Date().toISOString() }
|
|
398
400
|
: msg));
|
|
@@ -401,7 +403,7 @@ export function useChatMessages({ hazo_connect, hazo_auth, reference_id, receive
|
|
|
401
403
|
catch (err) {
|
|
402
404
|
console.error('[useChatMessages] Mark as read error:', err);
|
|
403
405
|
}
|
|
404
|
-
}, [current_user_id, messages,
|
|
406
|
+
}, [current_user_id, messages, api_base_url]);
|
|
405
407
|
// -------------------------------------------------------------------------
|
|
406
408
|
// Refresh
|
|
407
409
|
// -------------------------------------------------------------------------
|