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.
Files changed (147) hide show
  1. package/README.md +379 -7
  2. package/SETUP_CHECKLIST.md +95 -0
  3. package/package.json +4 -2
  4. package/dist/api/index.d.ts +0 -24
  5. package/dist/api/index.d.ts.map +0 -1
  6. package/dist/api/index.js +0 -24
  7. package/dist/api/index.js.map +0 -1
  8. package/dist/api/messages.d.ts +0 -34
  9. package/dist/api/messages.d.ts.map +0 -1
  10. package/dist/api/messages.js +0 -214
  11. package/dist/api/messages.js.map +0 -1
  12. package/dist/api/types.d.ts +0 -69
  13. package/dist/api/types.d.ts.map +0 -1
  14. package/dist/api/types.js +0 -8
  15. package/dist/api/types.js.map +0 -1
  16. package/dist/components/hazo_chat/hazo_chat.d.ts +0 -28
  17. package/dist/components/hazo_chat/hazo_chat.d.ts.map +0 -1
  18. package/dist/components/hazo_chat/hazo_chat.js +0 -200
  19. package/dist/components/hazo_chat/hazo_chat.js.map +0 -1
  20. package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts +0 -17
  21. package/dist/components/hazo_chat/hazo_chat_attachment_preview.d.ts.map +0 -1
  22. package/dist/components/hazo_chat/hazo_chat_attachment_preview.js +0 -60
  23. package/dist/components/hazo_chat/hazo_chat_attachment_preview.js.map +0 -1
  24. package/dist/components/hazo_chat/hazo_chat_context.d.ts +0 -42
  25. package/dist/components/hazo_chat/hazo_chat_context.d.ts.map +0 -1
  26. package/dist/components/hazo_chat/hazo_chat_context.js +0 -273
  27. package/dist/components/hazo_chat/hazo_chat_context.js.map +0 -1
  28. package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts +0 -15
  29. package/dist/components/hazo_chat/hazo_chat_document_viewer.d.ts.map +0 -1
  30. package/dist/components/hazo_chat/hazo_chat_document_viewer.js +0 -111
  31. package/dist/components/hazo_chat/hazo_chat_document_viewer.js.map +0 -1
  32. package/dist/components/hazo_chat/hazo_chat_header.d.ts +0 -16
  33. package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +0 -1
  34. package/dist/components/hazo_chat/hazo_chat_header.js +0 -24
  35. package/dist/components/hazo_chat/hazo_chat_header.js.map +0 -1
  36. package/dist/components/hazo_chat/hazo_chat_input.d.ts +0 -16
  37. package/dist/components/hazo_chat/hazo_chat_input.d.ts.map +0 -1
  38. package/dist/components/hazo_chat/hazo_chat_input.js +0 -75
  39. package/dist/components/hazo_chat/hazo_chat_input.js.map +0 -1
  40. package/dist/components/hazo_chat/hazo_chat_messages.d.ts +0 -17
  41. package/dist/components/hazo_chat/hazo_chat_messages.d.ts.map +0 -1
  42. package/dist/components/hazo_chat/hazo_chat_messages.js +0 -109
  43. package/dist/components/hazo_chat/hazo_chat_messages.js.map +0 -1
  44. package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts +0 -16
  45. package/dist/components/hazo_chat/hazo_chat_reference_list.d.ts.map +0 -1
  46. package/dist/components/hazo_chat/hazo_chat_reference_list.js +0 -59
  47. package/dist/components/hazo_chat/hazo_chat_reference_list.js.map +0 -1
  48. package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts +0 -18
  49. package/dist/components/hazo_chat/hazo_chat_sidebar.d.ts.map +0 -1
  50. package/dist/components/hazo_chat/hazo_chat_sidebar.js +0 -72
  51. package/dist/components/hazo_chat/hazo_chat_sidebar.js.map +0 -1
  52. package/dist/components/hazo_chat/index.d.ts +0 -16
  53. package/dist/components/hazo_chat/index.d.ts.map +0 -1
  54. package/dist/components/hazo_chat/index.js +0 -19
  55. package/dist/components/hazo_chat/index.js.map +0 -1
  56. package/dist/components/index.d.ts +0 -9
  57. package/dist/components/index.d.ts.map +0 -1
  58. package/dist/components/index.js +0 -11
  59. package/dist/components/index.js.map +0 -1
  60. package/dist/components/ui/avatar.d.ts +0 -13
  61. package/dist/components/ui/avatar.d.ts.map +0 -1
  62. package/dist/components/ui/avatar.js +0 -28
  63. package/dist/components/ui/avatar.js.map +0 -1
  64. package/dist/components/ui/badge.d.ts +0 -16
  65. package/dist/components/ui/badge.d.ts.map +0 -1
  66. package/dist/components/ui/badge.js +0 -36
  67. package/dist/components/ui/badge.js.map +0 -1
  68. package/dist/components/ui/button.d.ts +0 -18
  69. package/dist/components/ui/button.d.ts.map +0 -1
  70. package/dist/components/ui/button.js +0 -47
  71. package/dist/components/ui/button.js.map +0 -1
  72. package/dist/components/ui/chat_bubble.d.ts +0 -18
  73. package/dist/components/ui/chat_bubble.d.ts.map +0 -1
  74. package/dist/components/ui/chat_bubble.js +0 -88
  75. package/dist/components/ui/chat_bubble.js.map +0 -1
  76. package/dist/components/ui/index.d.ts +0 -18
  77. package/dist/components/ui/index.d.ts.map +0 -1
  78. package/dist/components/ui/index.js +0 -20
  79. package/dist/components/ui/index.js.map +0 -1
  80. package/dist/components/ui/input.d.ts +0 -11
  81. package/dist/components/ui/input.d.ts.map +0 -1
  82. package/dist/components/ui/input.js +0 -18
  83. package/dist/components/ui/input.js.map +0 -1
  84. package/dist/components/ui/loading_skeleton.d.ts +0 -19
  85. package/dist/components/ui/loading_skeleton.d.ts.map +0 -1
  86. package/dist/components/ui/loading_skeleton.js +0 -30
  87. package/dist/components/ui/loading_skeleton.js.map +0 -1
  88. package/dist/components/ui/scroll-area.d.ts +0 -12
  89. package/dist/components/ui/scroll-area.d.ts.map +0 -1
  90. package/dist/components/ui/scroll-area.js +0 -25
  91. package/dist/components/ui/scroll-area.js.map +0 -1
  92. package/dist/components/ui/separator.d.ts +0 -11
  93. package/dist/components/ui/separator.d.ts.map +0 -1
  94. package/dist/components/ui/separator.js +0 -18
  95. package/dist/components/ui/separator.js.map +0 -1
  96. package/dist/components/ui/skeleton.d.ts +0 -9
  97. package/dist/components/ui/skeleton.d.ts.map +0 -1
  98. package/dist/components/ui/skeleton.js +0 -16
  99. package/dist/components/ui/skeleton.js.map +0 -1
  100. package/dist/components/ui/textarea.d.ts +0 -11
  101. package/dist/components/ui/textarea.d.ts.map +0 -1
  102. package/dist/components/ui/textarea.js +0 -18
  103. package/dist/components/ui/textarea.js.map +0 -1
  104. package/dist/components/ui/tooltip.d.ts +0 -14
  105. package/dist/components/ui/tooltip.d.ts.map +0 -1
  106. package/dist/components/ui/tooltip.js +0 -30
  107. package/dist/components/ui/tooltip.js.map +0 -1
  108. package/dist/hooks/index.d.ts +0 -10
  109. package/dist/hooks/index.d.ts.map +0 -1
  110. package/dist/hooks/index.js +0 -10
  111. package/dist/hooks/index.js.map +0 -1
  112. package/dist/hooks/use_chat_messages.d.ts +0 -33
  113. package/dist/hooks/use_chat_messages.d.ts.map +0 -1
  114. package/dist/hooks/use_chat_messages.js +0 -466
  115. package/dist/hooks/use_chat_messages.js.map +0 -1
  116. package/dist/hooks/use_chat_references.d.ts +0 -17
  117. package/dist/hooks/use_chat_references.d.ts.map +0 -1
  118. package/dist/hooks/use_chat_references.js +0 -133
  119. package/dist/hooks/use_chat_references.js.map +0 -1
  120. package/dist/hooks/use_file_upload.d.ts +0 -23
  121. package/dist/hooks/use_file_upload.d.ts.map +0 -1
  122. package/dist/hooks/use_file_upload.js +0 -212
  123. package/dist/hooks/use_file_upload.js.map +0 -1
  124. package/dist/index.d.ts +0 -13
  125. package/dist/index.d.ts.map +0 -1
  126. package/dist/index.js +0 -17
  127. package/dist/index.js.map +0 -1
  128. package/dist/lib/config.d.ts +0 -41
  129. package/dist/lib/config.d.ts.map +0 -1
  130. package/dist/lib/config.js +0 -93
  131. package/dist/lib/config.js.map +0 -1
  132. package/dist/lib/constants.d.ts +0 -41
  133. package/dist/lib/constants.d.ts.map +0 -1
  134. package/dist/lib/constants.js +0 -72
  135. package/dist/lib/constants.js.map +0 -1
  136. package/dist/lib/index.d.ts +0 -9
  137. package/dist/lib/index.d.ts.map +0 -1
  138. package/dist/lib/index.js +0 -9
  139. package/dist/lib/index.js.map +0 -1
  140. package/dist/lib/utils.d.ts +0 -17
  141. package/dist/lib/utils.d.ts.map +0 -1
  142. package/dist/lib/utils.js +0 -20
  143. package/dist/lib/utils.js.map +0 -1
  144. package/dist/types/index.d.ts +0 -388
  145. package/dist/types/index.d.ts.map +0 -1
  146. package/dist/types/index.js +0 -11
  147. 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
- export default {
91
+ import type { Config } from 'tailwindcss';
92
+
93
+ const config: Config = {
90
94
  content: [
91
- // ... your existing paths
92
- './node_modules/hazo_chat/dist/**/*.{js,ts,jsx,tsx}',
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
- // ... rest of config
103
+ theme: {
104
+ extend: {
105
+ // Your theme extensions
106
+ },
107
+ },
108
+ plugins: [],
95
109
  };
110
+
111
+ export default config;
96
112
  ```
97
113
 
98
- **Important:** Without this configuration, Tailwind classes used by hazo_chat components may not be compiled, causing styling issues.
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';
@@ -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.10",
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": {
@@ -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
@@ -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
@@ -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"}
@@ -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"}