hazo_chat 2.0.10 → 2.0.12
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 +379 -7
- package/SETUP_CHECKLIST.md +95 -0
- package/package.json +4 -2
- package/dist/api/index.d.ts +0 -24
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js +0 -24
- package/dist/api/index.js.map +0 -1
- package/dist/api/messages.d.ts +0 -34
- package/dist/api/messages.d.ts.map +0 -1
- package/dist/api/messages.js +0 -214
- package/dist/api/messages.js.map +0 -1
- package/dist/api/types.d.ts +0 -69
- package/dist/api/types.d.ts.map +0 -1
- package/dist/api/types.js +0 -8
- package/dist/api/types.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat.d.ts +0 -28
- package/dist/components/hazo_chat/hazo_chat.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat.js +0 -200
- package/dist/components/hazo_chat/hazo_chat.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts +0 -17
- package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_attachment_preview.js +0 -60
- package/dist/components/hazo_chat/hazo_chat_attachment_preview.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_context.d.ts +0 -42
- package/dist/components/hazo_chat/hazo_chat_context.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_context.js +0 -273
- package/dist/components/hazo_chat/hazo_chat_context.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts +0 -15
- package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_document_viewer.js +0 -111
- package/dist/components/hazo_chat/hazo_chat_document_viewer.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_header.d.ts +0 -16
- package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_header.js +0 -24
- package/dist/components/hazo_chat/hazo_chat_header.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_input.d.ts +0 -16
- package/dist/components/hazo_chat/hazo_chat_input.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_input.js +0 -75
- package/dist/components/hazo_chat/hazo_chat_input.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_messages.d.ts +0 -17
- package/dist/components/hazo_chat/hazo_chat_messages.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_messages.js +0 -109
- package/dist/components/hazo_chat/hazo_chat_messages.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts +0 -16
- package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_reference_list.js +0 -59
- package/dist/components/hazo_chat/hazo_chat_reference_list.js.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts +0 -18
- package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts.map +0 -1
- package/dist/components/hazo_chat/hazo_chat_sidebar.js +0 -72
- package/dist/components/hazo_chat/hazo_chat_sidebar.js.map +0 -1
- package/dist/components/hazo_chat/index.d.ts +0 -16
- package/dist/components/hazo_chat/index.d.ts.map +0 -1
- package/dist/components/hazo_chat/index.js +0 -19
- package/dist/components/hazo_chat/index.js.map +0 -1
- package/dist/components/index.d.ts +0 -9
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js +0 -11
- package/dist/components/index.js.map +0 -1
- package/dist/components/ui/avatar.d.ts +0 -13
- package/dist/components/ui/avatar.d.ts.map +0 -1
- package/dist/components/ui/avatar.js +0 -28
- package/dist/components/ui/avatar.js.map +0 -1
- package/dist/components/ui/badge.d.ts +0 -16
- package/dist/components/ui/badge.d.ts.map +0 -1
- package/dist/components/ui/badge.js +0 -36
- package/dist/components/ui/badge.js.map +0 -1
- package/dist/components/ui/button.d.ts +0 -18
- package/dist/components/ui/button.d.ts.map +0 -1
- package/dist/components/ui/button.js +0 -47
- package/dist/components/ui/button.js.map +0 -1
- package/dist/components/ui/chat_bubble.d.ts +0 -18
- package/dist/components/ui/chat_bubble.d.ts.map +0 -1
- package/dist/components/ui/chat_bubble.js +0 -88
- package/dist/components/ui/chat_bubble.js.map +0 -1
- package/dist/components/ui/index.d.ts +0 -18
- package/dist/components/ui/index.d.ts.map +0 -1
- package/dist/components/ui/index.js +0 -20
- package/dist/components/ui/index.js.map +0 -1
- package/dist/components/ui/input.d.ts +0 -11
- package/dist/components/ui/input.d.ts.map +0 -1
- package/dist/components/ui/input.js +0 -18
- package/dist/components/ui/input.js.map +0 -1
- package/dist/components/ui/loading_skeleton.d.ts +0 -19
- package/dist/components/ui/loading_skeleton.d.ts.map +0 -1
- package/dist/components/ui/loading_skeleton.js +0 -30
- package/dist/components/ui/loading_skeleton.js.map +0 -1
- package/dist/components/ui/scroll-area.d.ts +0 -12
- package/dist/components/ui/scroll-area.d.ts.map +0 -1
- package/dist/components/ui/scroll-area.js +0 -25
- package/dist/components/ui/scroll-area.js.map +0 -1
- package/dist/components/ui/separator.d.ts +0 -11
- package/dist/components/ui/separator.d.ts.map +0 -1
- package/dist/components/ui/separator.js +0 -18
- package/dist/components/ui/separator.js.map +0 -1
- package/dist/components/ui/skeleton.d.ts +0 -9
- package/dist/components/ui/skeleton.d.ts.map +0 -1
- package/dist/components/ui/skeleton.js +0 -16
- package/dist/components/ui/skeleton.js.map +0 -1
- package/dist/components/ui/textarea.d.ts +0 -11
- package/dist/components/ui/textarea.d.ts.map +0 -1
- package/dist/components/ui/textarea.js +0 -18
- package/dist/components/ui/textarea.js.map +0 -1
- package/dist/components/ui/tooltip.d.ts +0 -14
- package/dist/components/ui/tooltip.d.ts.map +0 -1
- package/dist/components/ui/tooltip.js +0 -30
- package/dist/components/ui/tooltip.js.map +0 -1
- package/dist/hooks/index.d.ts +0 -10
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -10
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/use_chat_messages.d.ts +0 -33
- package/dist/hooks/use_chat_messages.d.ts.map +0 -1
- package/dist/hooks/use_chat_messages.js +0 -466
- package/dist/hooks/use_chat_messages.js.map +0 -1
- package/dist/hooks/use_chat_references.d.ts +0 -17
- package/dist/hooks/use_chat_references.d.ts.map +0 -1
- package/dist/hooks/use_chat_references.js +0 -133
- package/dist/hooks/use_chat_references.js.map +0 -1
- package/dist/hooks/use_file_upload.d.ts +0 -23
- package/dist/hooks/use_file_upload.d.ts.map +0 -1
- package/dist/hooks/use_file_upload.js +0 -212
- package/dist/hooks/use_file_upload.js.map +0 -1
- package/dist/index.d.ts +0 -13
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -17
- package/dist/index.js.map +0 -1
- package/dist/lib/config.d.ts +0 -41
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js +0 -93
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/constants.d.ts +0 -41
- package/dist/lib/constants.d.ts.map +0 -1
- package/dist/lib/constants.js +0 -72
- package/dist/lib/constants.js.map +0 -1
- package/dist/lib/index.d.ts +0 -9
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js +0 -9
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/utils.d.ts +0 -17
- package/dist/lib/utils.d.ts.map +0 -1
- package/dist/lib/utils.js +0 -20
- package/dist/lib/utils.js.map +0 -1
- package/dist/types/index.d.ts +0 -388
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -11
- package/dist/types/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -83,19 +83,56 @@ export default function RootLayout({ children }) {
|
|
|
83
83
|
|
|
84
84
|
### Required Tailwind Configuration
|
|
85
85
|
|
|
86
|
-
Your `tailwind.config.ts` must include hazo_chat package paths in content
|
|
86
|
+
Your `tailwind.config.ts` must include hazo_chat package paths in the `content` array. This ensures that Tailwind CSS scans the component library files and includes all utility classes in your final CSS bundle.
|
|
87
|
+
|
|
88
|
+
**Complete Configuration Example:**
|
|
87
89
|
|
|
88
90
|
```typescript
|
|
89
|
-
|
|
91
|
+
import type { Config } from 'tailwindcss';
|
|
92
|
+
|
|
93
|
+
const config: Config = {
|
|
90
94
|
content: [
|
|
91
|
-
//
|
|
92
|
-
'./
|
|
95
|
+
// Your application's content paths
|
|
96
|
+
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
|
|
97
|
+
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
|
|
98
|
+
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
99
|
+
|
|
100
|
+
// Add this line to scan the hazo_chat package
|
|
101
|
+
'./node_modules/hazo_chat/dist/**/*.js',
|
|
93
102
|
],
|
|
94
|
-
|
|
103
|
+
theme: {
|
|
104
|
+
extend: {
|
|
105
|
+
// Your theme extensions
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
plugins: [],
|
|
95
109
|
};
|
|
110
|
+
|
|
111
|
+
export default config;
|
|
96
112
|
```
|
|
97
113
|
|
|
98
|
-
**
|
|
114
|
+
**Why This Is Required:**
|
|
115
|
+
|
|
116
|
+
The `hazo_chat` component library uses Tailwind CSS utility classes (e.g., `flex`, `h-full`, `bg-background`, `p-4`) for all styling. These classes are not compiled into CSS by default. By adding the package path to your Tailwind `content` array, Tailwind will:
|
|
117
|
+
|
|
118
|
+
1. Scan all JavaScript files in the `hazo_chat` package
|
|
119
|
+
2. Extract all Tailwind utility classes used in the components
|
|
120
|
+
3. Include them in your application's final CSS bundle
|
|
121
|
+
4. Ensure the component styles are correctly applied at runtime
|
|
122
|
+
|
|
123
|
+
**Important:** Without this configuration, Tailwind classes used by hazo_chat components will not be compiled, causing styling issues such as:
|
|
124
|
+
- Missing styles (components appear unstyled)
|
|
125
|
+
- Broken layouts
|
|
126
|
+
- Incorrect spacing and colors
|
|
127
|
+
- Non-functional responsive breakpoints
|
|
128
|
+
|
|
129
|
+
**Troubleshooting:**
|
|
130
|
+
|
|
131
|
+
If you're experiencing styling issues after adding the configuration:
|
|
132
|
+
1. Restart your development server
|
|
133
|
+
2. Clear your Next.js cache: `rm -rf .next`
|
|
134
|
+
3. Verify the path matches your `node_modules` location
|
|
135
|
+
4. Check that `tailwindcss` is installed: `npm list tailwindcss`
|
|
99
136
|
|
|
100
137
|
### Required CSS Variables
|
|
101
138
|
|
|
@@ -344,6 +381,7 @@ hazo_chat requires these API endpoints:
|
|
|
344
381
|
|----------|--------|-------------|
|
|
345
382
|
| `/api/hazo_chat/messages` | GET | Fetch chat messages |
|
|
346
383
|
| `/api/hazo_chat/messages` | POST | Send a new message |
|
|
384
|
+
| `/api/hazo_chat/unread_count` | GET | Get unread message counts by reference_id (optional) |
|
|
347
385
|
| `/api/hazo_auth/me` | GET | Get current authenticated user |
|
|
348
386
|
| `/api/hazo_auth/profiles` | POST | Fetch user profiles by IDs |
|
|
349
387
|
|
|
@@ -372,6 +410,157 @@ export { GET, POST };
|
|
|
372
410
|
|
|
373
411
|
If you need more control, implement the endpoints manually. See [SETUP_CHECKLIST.md](./SETUP_CHECKLIST.md) for detailed examples.
|
|
374
412
|
|
|
413
|
+
## Library Functions
|
|
414
|
+
|
|
415
|
+
hazo_chat provides server-side library functions that can be used in API routes, server components, or server actions.
|
|
416
|
+
|
|
417
|
+
### hazo_chat_get_unread_count
|
|
418
|
+
|
|
419
|
+
Get unread message counts grouped by reference_id for a receiver user.
|
|
420
|
+
|
|
421
|
+
**Purpose:** Returns an array of reference IDs with the count of unread messages (where `read_at` is `null`) for a given receiver user ID. Useful for displaying unread message badges or notifications.
|
|
422
|
+
|
|
423
|
+
**Usage:**
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
import { createUnreadCountFunction } from 'hazo_chat/api';
|
|
427
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
428
|
+
|
|
429
|
+
// Create the function using the factory
|
|
430
|
+
const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
431
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Use the function
|
|
435
|
+
const unreadCounts = await hazo_chat_get_unread_count('receiver-user-id-123');
|
|
436
|
+
// Returns: [
|
|
437
|
+
// { reference_id: 'ref-1', count: 5 },
|
|
438
|
+
// { reference_id: 'ref-2', count: 3 },
|
|
439
|
+
// { reference_id: '', count: 1 } // Empty reference_id for general messages
|
|
440
|
+
// ]
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Return Type:**
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
interface UnreadCountResult {
|
|
447
|
+
reference_id: string; // The reference ID (empty string for messages without reference)
|
|
448
|
+
count: number; // Number of unread messages for this reference
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Function Behavior:**
|
|
453
|
+
- Only counts messages where `read_at` is `null` and `deleted_at` is `null`
|
|
454
|
+
- Groups results by `reference_id`
|
|
455
|
+
- Sorts results by count (descending - most unread first)
|
|
456
|
+
- Returns empty array if no unread messages found
|
|
457
|
+
- Returns empty array on errors (doesn't throw)
|
|
458
|
+
|
|
459
|
+
**Example: API Route Implementation**
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
// app/api/hazo_chat/unread_count/route.ts
|
|
463
|
+
import { createUnreadCountFunction } from 'hazo_chat/api';
|
|
464
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
465
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
466
|
+
|
|
467
|
+
export const dynamic = 'force-dynamic';
|
|
468
|
+
|
|
469
|
+
const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
470
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
export async function GET(request: NextRequest) {
|
|
474
|
+
try {
|
|
475
|
+
const { searchParams } = new URL(request.url);
|
|
476
|
+
const receiver_user_id = searchParams.get('receiver_user_id');
|
|
477
|
+
|
|
478
|
+
if (!receiver_user_id) {
|
|
479
|
+
return NextResponse.json(
|
|
480
|
+
{
|
|
481
|
+
success: false,
|
|
482
|
+
error: 'receiver_user_id is required',
|
|
483
|
+
unread_counts: []
|
|
484
|
+
},
|
|
485
|
+
{ status: 400 }
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const unread_counts = await hazo_chat_get_unread_count(receiver_user_id);
|
|
490
|
+
|
|
491
|
+
return NextResponse.json({
|
|
492
|
+
success: true,
|
|
493
|
+
receiver_user_id,
|
|
494
|
+
unread_counts,
|
|
495
|
+
total_references: unread_counts.length,
|
|
496
|
+
total_unread: unread_counts.reduce((sum, item) => sum + item.count, 0)
|
|
497
|
+
});
|
|
498
|
+
} catch (error) {
|
|
499
|
+
const error_message = error instanceof Error ? error.message : 'Unknown error';
|
|
500
|
+
return NextResponse.json(
|
|
501
|
+
{
|
|
502
|
+
success: false,
|
|
503
|
+
error: error_message,
|
|
504
|
+
unread_counts: []
|
|
505
|
+
},
|
|
506
|
+
{ status: 500 }
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Example: Server Component Usage**
|
|
513
|
+
|
|
514
|
+
```typescript
|
|
515
|
+
// app/chat/unread-badge.tsx
|
|
516
|
+
import { createUnreadCountFunction } from 'hazo_chat/api';
|
|
517
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
518
|
+
|
|
519
|
+
const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
520
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
export default async function UnreadBadge({
|
|
524
|
+
receiver_user_id
|
|
525
|
+
}: {
|
|
526
|
+
receiver_user_id: string
|
|
527
|
+
}) {
|
|
528
|
+
const unread_counts = await hazo_chat_get_unread_count(receiver_user_id);
|
|
529
|
+
const total_unread = unread_counts.reduce((sum, item) => sum + item.count, 0);
|
|
530
|
+
|
|
531
|
+
if (total_unread === 0) return null;
|
|
532
|
+
|
|
533
|
+
return (
|
|
534
|
+
<div className="flex gap-2">
|
|
535
|
+
{unread_counts.map((item) => (
|
|
536
|
+
<div key={item.reference_id || 'general'}>
|
|
537
|
+
<span>{item.reference_id || 'General'}: {item.count}</span>
|
|
538
|
+
</div>
|
|
539
|
+
))}
|
|
540
|
+
<span>Total: {total_unread}</span>
|
|
541
|
+
</div>
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**Example: Server Action Usage**
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
// app/actions/chat.ts
|
|
550
|
+
'use server';
|
|
551
|
+
|
|
552
|
+
import { createUnreadCountFunction } from 'hazo_chat/api';
|
|
553
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
554
|
+
|
|
555
|
+
const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
556
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
export async function getUnreadCounts(receiver_user_id: string) {
|
|
560
|
+
return await hazo_chat_get_unread_count(receiver_user_id);
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
375
564
|
## Props Reference
|
|
376
565
|
|
|
377
566
|
### HazoChatProps
|
|
@@ -390,6 +579,9 @@ If you need more control, implement the endpoints manually. See [SETUP_CHECKLIST
|
|
|
390
579
|
| `title` | `string` | ❌ | - | Chat header title |
|
|
391
580
|
| `subtitle` | `string` | ❌ | - | Chat header subtitle |
|
|
392
581
|
| `on_close` | `() => void` | ❌ | - | Close button callback |
|
|
582
|
+
| `show_sidebar_toggle` | `boolean` | ❌ | `false` | Show sidebar toggle button (hamburger menu) |
|
|
583
|
+
| `show_delete_button` | `boolean` | ❌ | `true` | Show delete button on chat bubbles |
|
|
584
|
+
| `bubble_radius` | `'default' \| 'full'` | ❌ | `'default'` | Bubble border radius style: `'default'` (rounded with tail) or `'full'` (fully round) |
|
|
393
585
|
| `className` | `string` | ❌ | - | Additional CSS classes |
|
|
394
586
|
|
|
395
587
|
### Example with All Props
|
|
@@ -413,6 +605,186 @@ If you need more control, implement the endpoints manually. See [SETUP_CHECKLIST
|
|
|
413
605
|
/>
|
|
414
606
|
```
|
|
415
607
|
|
|
608
|
+
## Customization
|
|
609
|
+
|
|
610
|
+
hazo_chat provides props to customize component appearance and behavior without needing CSS overrides. This eliminates the need for extensive CSS customizations in consuming projects.
|
|
611
|
+
|
|
612
|
+
### Common Customizations
|
|
613
|
+
|
|
614
|
+
#### Hide Sidebar Toggle Button (Hamburger Menu)
|
|
615
|
+
|
|
616
|
+
By default, the sidebar toggle button is hidden (`show_sidebar_toggle={false}`). To show it:
|
|
617
|
+
|
|
618
|
+
```tsx
|
|
619
|
+
<HazoChat
|
|
620
|
+
receiver_user_id="user-123"
|
|
621
|
+
show_sidebar_toggle={true} // Show hamburger menu button
|
|
622
|
+
/>
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
#### Hide Delete Button on Chat Bubbles
|
|
626
|
+
|
|
627
|
+
To hide the delete button on chat bubbles:
|
|
628
|
+
|
|
629
|
+
```tsx
|
|
630
|
+
<HazoChat
|
|
631
|
+
receiver_user_id="user-123"
|
|
632
|
+
show_delete_button={false} // Hide delete button
|
|
633
|
+
/>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
#### Make Chat Bubbles Fully Round
|
|
637
|
+
|
|
638
|
+
To make all chat bubbles fully round (instead of the default style with a tail):
|
|
639
|
+
|
|
640
|
+
```tsx
|
|
641
|
+
<HazoChat
|
|
642
|
+
receiver_user_id="user-123"
|
|
643
|
+
bubble_radius="full" // Fully round all corners
|
|
644
|
+
/>
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Customization Props Summary
|
|
648
|
+
|
|
649
|
+
| Prop | Default | Options | Description |
|
|
650
|
+
|------|--------|---------|------------|
|
|
651
|
+
| `show_sidebar_toggle` | `false` | `boolean` | Show/hide the hamburger menu button |
|
|
652
|
+
| `show_delete_button` | `true` | `boolean` | Show/hide delete button on chat bubbles |
|
|
653
|
+
| `bubble_radius` | `'default'` | `'default' \| 'full'` | Bubble border radius style |
|
|
654
|
+
|
|
655
|
+
### Example: Full Customization
|
|
656
|
+
|
|
657
|
+
```tsx
|
|
658
|
+
<HazoChat
|
|
659
|
+
receiver_user_id="user-123"
|
|
660
|
+
reference_id="project-456"
|
|
661
|
+
show_sidebar_toggle={false} // Hide hamburger menu
|
|
662
|
+
show_delete_button={false} // Hide delete buttons
|
|
663
|
+
bubble_radius="full" // Fully round bubbles
|
|
664
|
+
title="Project Chat"
|
|
665
|
+
className="h-[600px]"
|
|
666
|
+
/>
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### Why Use Props Instead of CSS?
|
|
670
|
+
|
|
671
|
+
Using props instead of CSS overrides provides:
|
|
672
|
+
- **Type safety**: TypeScript will catch invalid values
|
|
673
|
+
- **Consistency**: Ensures all instances use the same styling
|
|
674
|
+
- **Maintainability**: Easier to update across the codebase
|
|
675
|
+
- **No CSS conflicts**: Avoids specificity issues with Tailwind utilities
|
|
676
|
+
|
|
677
|
+
If you need more advanced styling that isn't covered by props, you can still use CSS overrides, but props should cover most common customization needs.
|
|
678
|
+
|
|
679
|
+
## Checking for Messages
|
|
680
|
+
|
|
681
|
+
If you need to check whether messages exist for a given reference (without loading all messages), you can call the messages API endpoint directly. This is useful for showing indicators or badges.
|
|
682
|
+
|
|
683
|
+
**Important:** The API requires `receiver_user_id` as a query parameter and returns an object response, not a direct array.
|
|
684
|
+
|
|
685
|
+
### Correct API Usage Pattern
|
|
686
|
+
|
|
687
|
+
```typescript
|
|
688
|
+
// ✅ CORRECT: Include receiver_user_id and handle object response
|
|
689
|
+
async function checkMessagesExist(
|
|
690
|
+
recipient_user_id: string,
|
|
691
|
+
reference_id: string,
|
|
692
|
+
reference_type?: string
|
|
693
|
+
): Promise<boolean> {
|
|
694
|
+
const params = new URLSearchParams({
|
|
695
|
+
receiver_user_id: recipient_user_id, // ✅ Required parameter
|
|
696
|
+
reference_id,
|
|
697
|
+
...(reference_type && { reference_type }),
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
const response = await fetch(`/api/hazo_chat/messages?${params.toString()}`, {
|
|
701
|
+
credentials: 'include'
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
if (!response.ok) {
|
|
705
|
+
return false;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
const data = await response.json();
|
|
709
|
+
|
|
710
|
+
// ✅ Handle object response format: { success: true, messages: [], current_user_id }
|
|
711
|
+
const messages = data.messages || data; // Handle both object and array responses
|
|
712
|
+
const has_messages_result = Array.isArray(messages) && messages.length > 0;
|
|
713
|
+
|
|
714
|
+
return has_messages_result;
|
|
715
|
+
}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Common Mistakes to Avoid
|
|
719
|
+
|
|
720
|
+
```typescript
|
|
721
|
+
// ❌ WRONG: Missing receiver_user_id parameter
|
|
722
|
+
const params = new URLSearchParams({
|
|
723
|
+
reference_id,
|
|
724
|
+
...(reference_type && { reference_type }),
|
|
725
|
+
});
|
|
726
|
+
// This will return a 400 error: "receiver_user_id is required"
|
|
727
|
+
|
|
728
|
+
// ❌ WRONG: Expecting direct array response
|
|
729
|
+
const data = await response.json();
|
|
730
|
+
const has_messages_result = Array.isArray(data) && data.length > 0;
|
|
731
|
+
// This fails because API returns: { success: true, messages: [], current_user_id }
|
|
732
|
+
```
|
|
733
|
+
|
|
734
|
+
### Example: Custom Hook Implementation
|
|
735
|
+
|
|
736
|
+
```typescript
|
|
737
|
+
'use client';
|
|
738
|
+
|
|
739
|
+
import { useState, useEffect } from 'react';
|
|
740
|
+
|
|
741
|
+
function useChatMessagesCheck(
|
|
742
|
+
recipient_user_id: string,
|
|
743
|
+
reference_id: string,
|
|
744
|
+
reference_type?: string
|
|
745
|
+
) {
|
|
746
|
+
const [has_messages, set_has_messages] = useState(false);
|
|
747
|
+
const [is_checking, set_is_checking] = useState(true);
|
|
748
|
+
|
|
749
|
+
useEffect(() => {
|
|
750
|
+
async function check() {
|
|
751
|
+
if (!recipient_user_id || !reference_id) {
|
|
752
|
+
set_is_checking(false);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
try {
|
|
757
|
+
const params = new URLSearchParams({
|
|
758
|
+
receiver_user_id: recipient_user_id, // ✅ Required
|
|
759
|
+
reference_id,
|
|
760
|
+
...(reference_type && { reference_type }),
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const response = await fetch(
|
|
764
|
+
`/api/hazo_chat/messages?${params.toString()}`,
|
|
765
|
+
{ credentials: 'include' }
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
if (response.ok) {
|
|
769
|
+
const data = await response.json();
|
|
770
|
+
const messages = data.messages || data; // ✅ Handle object response
|
|
771
|
+
set_has_messages(Array.isArray(messages) && messages.length > 0);
|
|
772
|
+
}
|
|
773
|
+
} catch (error) {
|
|
774
|
+
console.error('[useChatMessagesCheck] Error:', error);
|
|
775
|
+
set_has_messages(false);
|
|
776
|
+
} finally {
|
|
777
|
+
set_is_checking(false);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
check();
|
|
782
|
+
}, [recipient_user_id, reference_id, reference_type]);
|
|
783
|
+
|
|
784
|
+
return { has_messages, is_checking };
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
416
788
|
## Hooks
|
|
417
789
|
|
|
418
790
|
### useChatMessages
|
|
@@ -707,7 +1079,7 @@ npm run build:test-app
|
|
|
707
1079
|
import { HazoChat, useChatMessages, useChatReferences, useFileUpload } from 'hazo_chat';
|
|
708
1080
|
|
|
709
1081
|
// API handlers (for server-side routes)
|
|
710
|
-
import { createMessagesHandler } from 'hazo_chat/api';
|
|
1082
|
+
import { createMessagesHandler, createUnreadCountFunction } from 'hazo_chat/api';
|
|
711
1083
|
|
|
712
1084
|
// Components only
|
|
713
1085
|
import { HazoChat, ChatBubble } from 'hazo_chat/components';
|
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -233,11 +233,101 @@ export async function POST(request: NextRequest) {
|
|
|
233
233
|
}
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
### Step 4.4: Unread Count API (Optional - For Unread Badges)
|
|
237
|
+
|
|
238
|
+
**File: `src/app/api/hazo_chat/unread_count/route.ts`**
|
|
239
|
+
|
|
240
|
+
This endpoint is optional but useful for displaying unread message counts or badges in your UI.
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
/**
|
|
244
|
+
* API route to get unread message counts grouped by reference_id
|
|
245
|
+
* Uses the exportable library function from hazo_chat
|
|
246
|
+
*/
|
|
247
|
+
|
|
248
|
+
export const dynamic = 'force-dynamic';
|
|
249
|
+
|
|
250
|
+
import { createUnreadCountFunction } from 'hazo_chat/api';
|
|
251
|
+
import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
252
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
253
|
+
|
|
254
|
+
// Create the unread count function using the factory
|
|
255
|
+
const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
256
|
+
getHazoConnect: () => getHazoConnectSingleton()
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
export async function GET(request: NextRequest) {
|
|
260
|
+
try {
|
|
261
|
+
const { searchParams } = new URL(request.url);
|
|
262
|
+
const receiver_user_id = searchParams.get('receiver_user_id');
|
|
263
|
+
|
|
264
|
+
if (!receiver_user_id) {
|
|
265
|
+
return NextResponse.json(
|
|
266
|
+
{
|
|
267
|
+
success: false,
|
|
268
|
+
error: 'receiver_user_id is required',
|
|
269
|
+
unread_counts: []
|
|
270
|
+
},
|
|
271
|
+
{ status: 400 }
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Call the library function
|
|
276
|
+
const unread_counts = await hazo_chat_get_unread_count(receiver_user_id);
|
|
277
|
+
|
|
278
|
+
return NextResponse.json({
|
|
279
|
+
success: true,
|
|
280
|
+
receiver_user_id,
|
|
281
|
+
unread_counts,
|
|
282
|
+
total_references: unread_counts.length,
|
|
283
|
+
total_unread: unread_counts.reduce((sum, item) => sum + item.count, 0)
|
|
284
|
+
});
|
|
285
|
+
} catch (error) {
|
|
286
|
+
const error_message = error instanceof Error ? error.message : 'Unknown error';
|
|
287
|
+
console.error('[hazo_chat/unread_count] Error:', error_message, error);
|
|
288
|
+
|
|
289
|
+
return NextResponse.json(
|
|
290
|
+
{
|
|
291
|
+
success: false,
|
|
292
|
+
error: error_message,
|
|
293
|
+
unread_counts: []
|
|
294
|
+
},
|
|
295
|
+
{ status: 500 }
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**What this endpoint does:**
|
|
302
|
+
- Takes `receiver_user_id` as a query parameter
|
|
303
|
+
- Returns an array of objects with `reference_id` and `count` of unread messages
|
|
304
|
+
- Only counts messages where `read_at` is `null` and `deleted_at` is `null`
|
|
305
|
+
- Groups results by `reference_id`
|
|
306
|
+
- Sorts by count (descending - most unread first)
|
|
307
|
+
|
|
308
|
+
**Response format:**
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"success": true,
|
|
312
|
+
"receiver_user_id": "user-123",
|
|
313
|
+
"unread_counts": [
|
|
314
|
+
{ "reference_id": "ref-1", "count": 5 },
|
|
315
|
+
{ "reference_id": "ref-2", "count": 3 },
|
|
316
|
+
{ "reference_id": "", "count": 1 }
|
|
317
|
+
],
|
|
318
|
+
"total_references": 3,
|
|
319
|
+
"total_unread": 9
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Note:** This endpoint is optional. Only create it if you need to display unread message counts in your UI.
|
|
324
|
+
|
|
236
325
|
### API Routes Summary
|
|
237
326
|
|
|
238
327
|
| Endpoint | Method | File | Purpose |
|
|
239
328
|
|----------|--------|------|---------|
|
|
240
329
|
| `/api/hazo_chat/messages` | GET, POST | `api/hazo_chat/messages/route.ts` | Message CRUD |
|
|
330
|
+
| `/api/hazo_chat/unread_count` | GET | `api/hazo_chat/unread_count/route.ts` | Get unread counts (optional) |
|
|
241
331
|
| `/api/hazo_auth/me` | GET | `api/hazo_auth/me/route.ts` | Get current user |
|
|
242
332
|
| `/api/hazo_auth/profiles` | POST | `api/hazo_auth/profiles/route.ts` | Get user profiles |
|
|
243
333
|
|
|
@@ -246,6 +336,7 @@ export async function POST(request: NextRequest) {
|
|
|
246
336
|
- [ ] `GET /api/hazo_auth/me` returns user data when logged in
|
|
247
337
|
- [ ] `POST /api/hazo_auth/profiles` returns profiles for given IDs
|
|
248
338
|
- [ ] `GET /api/hazo_chat/messages?receiver_user_id=xxx` works
|
|
339
|
+
- [ ] `GET /api/hazo_chat/unread_count?receiver_user_id=xxx` returns unread counts (if implemented)
|
|
249
340
|
|
|
250
341
|
---
|
|
251
342
|
|
|
@@ -735,6 +826,9 @@ curl -X POST http://localhost:3000/api/hazo_auth/profiles \
|
|
|
735
826
|
|
|
736
827
|
# Test messages endpoint
|
|
737
828
|
curl "http://localhost:3000/api/hazo_chat/messages?receiver_user_id=user-id"
|
|
829
|
+
|
|
830
|
+
# Test unread count endpoint (if implemented)
|
|
831
|
+
curl "http://localhost:3000/api/hazo_chat/unread_count?receiver_user_id=user-id"
|
|
738
832
|
```
|
|
739
833
|
|
|
740
834
|
### UI Verification & Responsive Behavior
|
|
@@ -912,6 +1006,7 @@ npm install hazo_chat hazo_connect
|
|
|
912
1006
|
|
|
913
1007
|
# 2. Create API routes
|
|
914
1008
|
mkdir -p src/app/api/hazo_chat/messages
|
|
1009
|
+
mkdir -p src/app/api/hazo_chat/unread_count # Optional: for unread counts
|
|
915
1010
|
mkdir -p src/app/api/hazo_auth/me
|
|
916
1011
|
mkdir -p src/app/api/hazo_auth/profiles
|
|
917
1012
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_chat",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.12",
|
|
4
4
|
"description": "Chat interface for 1-1 communication with API-first architecture",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"homepage": "https://github.com/pub12/hazo_chat#readme",
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@radix-ui/react-avatar": "^1.1.0",
|
|
67
|
+
"@radix-ui/react-hover-card": "^1.1.15",
|
|
67
68
|
"@radix-ui/react-scroll-area": "^1.1.0",
|
|
68
69
|
"@radix-ui/react-separator": "^1.1.0",
|
|
69
70
|
"@radix-ui/react-slot": "^1.1.0",
|
|
@@ -90,7 +91,8 @@
|
|
|
90
91
|
"hazo_connect": "^2.3.1",
|
|
91
92
|
"next": ">=14.0.0",
|
|
92
93
|
"react": "^18.0.0",
|
|
93
|
-
"react-dom": "^18.0.0"
|
|
94
|
+
"react-dom": "^18.0.0",
|
|
95
|
+
"tailwindcss": ">=3.0.0"
|
|
94
96
|
},
|
|
95
97
|
"peerDependenciesMeta": {
|
|
96
98
|
"hazo_connect": {
|
package/dist/api/index.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* hazo_chat API Module
|
|
3
|
-
*
|
|
4
|
-
* Provides exportable API route handlers for Next.js applications.
|
|
5
|
-
* These handlers can be imported and re-exported in your API routes.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* // app/api/hazo_chat/messages/route.ts
|
|
10
|
-
* import { createMessagesHandler } from 'hazo_chat/api';
|
|
11
|
-
* import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
12
|
-
*
|
|
13
|
-
* export const dynamic = 'force-dynamic';
|
|
14
|
-
*
|
|
15
|
-
* const { GET, POST } = createMessagesHandler({
|
|
16
|
-
* getHazoConnect: () => getHazoConnectSingleton()
|
|
17
|
-
* });
|
|
18
|
-
*
|
|
19
|
-
* export { GET, POST };
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export { createMessagesHandler } from './messages.js';
|
|
23
|
-
export type { MessagesHandlerOptions, ChatMessageInput, ChatMessageRecord } from './types.js';
|
|
24
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/api/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAGtD,YAAY,EACV,sBAAsB,EACtB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,YAAY,CAAC"}
|
package/dist/api/index.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* hazo_chat API Module
|
|
3
|
-
*
|
|
4
|
-
* Provides exportable API route handlers for Next.js applications.
|
|
5
|
-
* These handlers can be imported and re-exported in your API routes.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* // app/api/hazo_chat/messages/route.ts
|
|
10
|
-
* import { createMessagesHandler } from 'hazo_chat/api';
|
|
11
|
-
* import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
12
|
-
*
|
|
13
|
-
* export const dynamic = 'force-dynamic';
|
|
14
|
-
*
|
|
15
|
-
* const { GET, POST } = createMessagesHandler({
|
|
16
|
-
* getHazoConnect: () => getHazoConnectSingleton()
|
|
17
|
-
* });
|
|
18
|
-
*
|
|
19
|
-
* export { GET, POST };
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
// Export handler factories
|
|
23
|
-
export { createMessagesHandler } from './messages.js';
|
|
24
|
-
//# sourceMappingURL=index.js.map
|
package/dist/api/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/api/messages.d.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Messages API Handler Factory
|
|
3
|
-
*
|
|
4
|
-
* Creates GET and POST handlers for the /api/hazo_chat/messages endpoint.
|
|
5
|
-
* These handlers should be used in a Next.js API route.
|
|
6
|
-
*
|
|
7
|
-
* @example
|
|
8
|
-
* ```typescript
|
|
9
|
-
* // app/api/hazo_chat/messages/route.ts
|
|
10
|
-
* import { createMessagesHandler } from 'hazo_chat/api';
|
|
11
|
-
* import { getHazoConnectSingleton } from 'hazo_connect/nextjs/setup';
|
|
12
|
-
*
|
|
13
|
-
* export const dynamic = 'force-dynamic';
|
|
14
|
-
*
|
|
15
|
-
* const { GET, POST } = createMessagesHandler({
|
|
16
|
-
* getHazoConnect: () => getHazoConnectSingleton()
|
|
17
|
-
* });
|
|
18
|
-
*
|
|
19
|
-
* export { GET, POST };
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
23
|
-
import type { MessagesHandlerOptions } from './types.js';
|
|
24
|
-
/**
|
|
25
|
-
* Creates GET and POST handlers for chat messages
|
|
26
|
-
*
|
|
27
|
-
* @param options - Configuration options
|
|
28
|
-
* @returns Object with GET and POST handlers
|
|
29
|
-
*/
|
|
30
|
-
export declare function createMessagesHandler(options: MessagesHandlerOptions): {
|
|
31
|
-
GET: (request: NextRequest) => Promise<NextResponse>;
|
|
32
|
-
POST: (request: NextRequest) => Promise<NextResponse>;
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/api/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,KAAK,EAAE,sBAAsB,EAAuC,MAAM,YAAY,CAAC;AAmB9F;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB;mBAWvC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;oBA+FlC,WAAW,KAAG,OAAO,CAAC,YAAY,CAAC;EA0GjE"}
|