hazo_chat 2.1.0 → 3.0.0

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 (33) hide show
  1. package/README.md +182 -67
  2. package/SETUP_CHECKLIST.md +773 -67
  3. package/dist/api/index.d.ts +17 -2
  4. package/dist/api/index.d.ts.map +1 -1
  5. package/dist/api/index.js +16 -1
  6. package/dist/api/index.js.map +1 -1
  7. package/dist/api/messages.d.ts +34 -1
  8. package/dist/api/messages.d.ts.map +1 -1
  9. package/dist/api/messages.js +340 -47
  10. package/dist/api/messages.js.map +1 -1
  11. package/dist/api/types.d.ts +50 -2
  12. package/dist/api/types.d.ts.map +1 -1
  13. package/dist/api/unread_count.d.ts +19 -10
  14. package/dist/api/unread_count.d.ts.map +1 -1
  15. package/dist/api/unread_count.js +54 -30
  16. package/dist/api/unread_count.js.map +1 -1
  17. package/dist/components/hazo_chat/hazo_chat.d.ts.map +1 -1
  18. package/dist/components/hazo_chat/hazo_chat.js +23 -15
  19. package/dist/components/hazo_chat/hazo_chat.js.map +1 -1
  20. package/dist/components/hazo_chat/hazo_chat_header.d.ts.map +1 -1
  21. package/dist/components/hazo_chat/hazo_chat_header.js +17 -4
  22. package/dist/components/hazo_chat/hazo_chat_header.js.map +1 -1
  23. package/dist/components/hazo_chat/hazo_chat_messages.d.ts +5 -4
  24. package/dist/components/hazo_chat/hazo_chat_messages.d.ts.map +1 -1
  25. package/dist/components/hazo_chat/hazo_chat_messages.js +48 -8
  26. package/dist/components/hazo_chat/hazo_chat_messages.js.map +1 -1
  27. package/dist/hooks/use_chat_messages.d.ts +5 -5
  28. package/dist/hooks/use_chat_messages.d.ts.map +1 -1
  29. package/dist/hooks/use_chat_messages.js +247 -148
  30. package/dist/hooks/use_chat_messages.js.map +1 -1
  31. package/dist/types/index.d.ts +162 -7
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # hazo_chat
2
2
 
3
- A full-featured React chat component library for 1-1 communication with document sharing, file attachments, and real-time messaging capabilities.
3
+ A full-featured React chat component library for group-based communication with document sharing, file attachments, and real-time messaging capabilities.
4
4
 
5
- **Version 2.0** - Now with API-first architecture! No server-side dependencies in client components.
5
+ **Version 3.0** - Now with group-based chat! Multiple users can participate in a single chat group, perfect for support staff rotating on client sessions.
6
+
7
+ **Version 2.0** introduced API-first architecture with no server-side dependencies in client components.
6
8
 
7
9
  ## Features
8
10
 
11
+ - 👥 **Group-Based Chat** - Multiple users can participate in a single chat group
12
+ - 🔄 **Role-Based Access** - Support for 'client' and 'staff' roles within groups
9
13
  - 📱 **Responsive Design** - Works on desktop and mobile with adaptive layout
10
14
  - 💬 **Real-time Messaging** - Polling or manual refresh modes for message updates with optimistic UI
11
15
  - 📎 **File Attachments** - Support for documents and images with preview
@@ -478,7 +482,7 @@ export default function ChatPage() {
478
482
  return (
479
483
  <div className="h-screen">
480
484
  <HazoChat
481
- receiver_user_id="recipient-uuid"
485
+ chat_group_id="group-uuid"
482
486
  reference_id="conversation-123"
483
487
  reference_type="support"
484
488
  title="Chat with Support"
@@ -497,13 +501,15 @@ hazo_chat requires these API endpoints:
497
501
 
498
502
  | Endpoint | Method | Description |
499
503
  |----------|--------|-------------|
500
- | `/api/hazo_chat/messages` | GET | Fetch chat messages |
501
- | `/api/hazo_chat/messages` | POST | Send a new message |
504
+ | `/api/hazo_chat/messages` | GET | Fetch chat messages (requires `chat_group_id` param) |
505
+ | `/api/hazo_chat/messages` | POST | Send a new message (requires `chat_group_id` in body) |
502
506
  | `/api/hazo_chat/messages/[id]/read` | PATCH | Mark a message as read (automatic) |
503
- | `/api/hazo_chat/unread_count` | GET | Get unread message counts by reference_id (optional) |
507
+ | `/api/hazo_chat/unread_count` | GET | Get unread message counts by chat_group_id (optional) |
504
508
  | `/api/hazo_auth/me` | GET | Get current authenticated user |
505
509
  | `/api/hazo_auth/profiles` | POST | Fetch user profiles by IDs |
506
510
 
511
+ **Breaking Change (v3.0):** Messages API now uses `chat_group_id` instead of `receiver_user_id`. All group members can see and send messages.
512
+
507
513
  ### Using Exportable Handlers (Recommended)
508
514
 
509
515
  ```typescript
@@ -563,9 +569,11 @@ hazo_chat provides server-side library functions that can be used in API routes,
563
569
 
564
570
  ### hazo_chat_get_unread_count
565
571
 
566
- Get unread message counts grouped by reference_id for a receiver user.
572
+ Get unread message counts grouped by chat_group_id for a user.
573
+
574
+ **Purpose:** Returns an array of chat group IDs with the count of unread messages (where `read_at` is `null`) for a given user ID. Useful for displaying unread message badges or notifications.
567
575
 
568
- **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.
576
+ **Breaking Change (v3.0):** Now groups by `chat_group_id` instead of `reference_id`. Accepts optional `chat_group_ids` filter.
569
577
 
570
578
  **Usage:**
571
579
 
@@ -579,11 +587,13 @@ const hazo_chat_get_unread_count = createUnreadCountFunction({
579
587
  });
580
588
 
581
589
  // Use the function
582
- const unreadCounts = await hazo_chat_get_unread_count('receiver-user-id-123');
590
+ const unreadCounts = await hazo_chat_get_unread_count({
591
+ user_id: 'user-id-123',
592
+ chat_group_ids: ['group-1', 'group-2'] // Optional: filter by specific groups
593
+ });
583
594
  // Returns: [
584
- // { reference_id: 'ref-1', count: 5 },
585
- // { reference_id: 'ref-2', count: 3 },
586
- // { reference_id: '', count: 1 } // Empty reference_id for general messages
595
+ // { chat_group_id: 'group-1', count: 5 },
596
+ // { chat_group_id: 'group-2', count: 3 }
587
597
  // ]
588
598
  ```
589
599
 
@@ -591,14 +601,16 @@ const unreadCounts = await hazo_chat_get_unread_count('receiver-user-id-123');
591
601
 
592
602
  ```typescript
593
603
  interface UnreadCountResult {
594
- reference_id: string; // The reference ID (empty string for messages without reference)
595
- count: number; // Number of unread messages for this reference
604
+ chat_group_id: string; // The chat group ID
605
+ count: number; // Number of unread messages in this group
596
606
  }
597
607
  ```
598
608
 
599
609
  **Function Behavior:**
600
610
  - Only counts messages where `read_at` is `null` and `deleted_at` is `null`
601
- - Groups results by `reference_id`
611
+ - Only counts messages in groups where the user is a member
612
+ - Groups results by `chat_group_id`
613
+ - Optionally filters by specific `chat_group_ids` if provided
602
614
  - Sorts results by count (descending - most unread first)
603
615
  - Returns empty array if no unread messages found
604
616
  - Returns empty array on errors (doesn't throw)
@@ -620,33 +632,41 @@ const hazo_chat_get_unread_count = createUnreadCountFunction({
620
632
  export async function GET(request: NextRequest) {
621
633
  try {
622
634
  const { searchParams } = new URL(request.url);
623
- const receiver_user_id = searchParams.get('receiver_user_id');
635
+ const user_id = searchParams.get('user_id');
636
+ const chat_group_ids_param = searchParams.get('chat_group_ids');
624
637
 
625
- if (!receiver_user_id) {
638
+ if (!user_id) {
626
639
  return NextResponse.json(
627
- {
628
- success: false,
629
- error: 'receiver_user_id is required',
640
+ {
641
+ success: false,
642
+ error: 'user_id is required',
630
643
  unread_counts: []
631
644
  },
632
645
  { status: 400 }
633
646
  );
634
647
  }
635
648
 
636
- const unread_counts = await hazo_chat_get_unread_count(receiver_user_id);
649
+ const chat_group_ids = chat_group_ids_param
650
+ ? chat_group_ids_param.split(',')
651
+ : undefined;
652
+
653
+ const unread_counts = await hazo_chat_get_unread_count({
654
+ user_id,
655
+ chat_group_ids
656
+ });
637
657
 
638
658
  return NextResponse.json({
639
659
  success: true,
640
- receiver_user_id,
660
+ user_id,
641
661
  unread_counts,
642
- total_references: unread_counts.length,
662
+ total_groups: unread_counts.length,
643
663
  total_unread: unread_counts.reduce((sum, item) => sum + item.count, 0)
644
664
  });
645
665
  } catch (error) {
646
666
  const error_message = error instanceof Error ? error.message : 'Unknown error';
647
667
  return NextResponse.json(
648
- {
649
- success: false,
668
+ {
669
+ success: false,
650
670
  error: error_message,
651
671
  unread_counts: []
652
672
  },
@@ -714,7 +734,7 @@ export async function getUnreadCounts(receiver_user_id: string) {
714
734
 
715
735
  | Prop | Type | Required | Default | Description |
716
736
  |------|------|----------|---------|-------------|
717
- | `receiver_user_id` | `string` | ✅ | - | UUID of the chat recipient |
737
+ | `chat_group_id` | `string` | ✅ | - | UUID of the chat group (CHANGED from `receiver_user_id` in v3.0) |
718
738
  | `reference_id` | `string` | ❌ | - | Reference ID for chat context grouping |
719
739
  | `reference_type` | `string` | ❌ | `'chat'` | Type of reference |
720
740
  | `api_base_url` | `string` | ❌ | `'/api/hazo_chat'` | Base URL for API endpoints |
@@ -735,7 +755,7 @@ export async function getUnreadCounts(receiver_user_id: string) {
735
755
 
736
756
  ```tsx
737
757
  <HazoChat
738
- receiver_user_id="user-123"
758
+ chat_group_id="group-123"
739
759
  reference_id="project-456"
740
760
  reference_type="project_chat"
741
761
  api_base_url="/api/hazo_chat"
@@ -803,7 +823,7 @@ To make all chat bubbles fully round (instead of the default style with a tail):
803
823
 
804
824
  ```tsx
805
825
  <HazoChat
806
- receiver_user_id="user-123"
826
+ chat_group_id="group-123"
807
827
  reference_id="project-456"
808
828
  show_sidebar_toggle={false} // Hide hamburger menu
809
829
  show_delete_button={false} // Hide delete buttons
@@ -954,7 +974,7 @@ const {
954
974
  mark_as_read, // (message_id) => Promise<void>
955
975
  refresh, // () => void - Reload messages
956
976
  } = useChatMessages({
957
- receiver_user_id: 'user-456',
977
+ chat_group_id: 'group-456', // CHANGED from receiver_user_id in v3.0
958
978
  reference_id: 'chat-123',
959
979
  reference_type: 'direct',
960
980
  api_base_url: '/api/hazo_chat',
@@ -1017,7 +1037,7 @@ interface ChatMessage {
1017
1037
  reference_id: string;
1018
1038
  reference_type: string;
1019
1039
  sender_user_id: string;
1020
- receiver_user_id: string;
1040
+ chat_group_id: string; // CHANGED from receiver_user_id in v3.0
1021
1041
  message_text: string | null;
1022
1042
  reference_list: ChatReferenceItem[] | null;
1023
1043
  read_at: string | null;
@@ -1025,7 +1045,7 @@ interface ChatMessage {
1025
1045
  created_at: string;
1026
1046
  changed_at: string;
1027
1047
  sender_profile?: HazoUserProfile;
1028
- receiver_profile?: HazoUserProfile;
1048
+ // receiver_profile removed in v3.0
1029
1049
  is_sender: boolean;
1030
1050
  send_status?: 'sending' | 'sent' | 'failed';
1031
1051
  }
@@ -1061,30 +1081,71 @@ interface ChatReferenceItem {
1061
1081
 
1062
1082
  ## Database Schema
1063
1083
 
1064
- ### hazo_chat Table
1084
+ **Breaking Changes in v3.0:** The database schema has been updated to support group-based chat. Migration required.
1085
+
1086
+ ### hazo_chat_group Table (NEW in v3.0)
1087
+
1088
+ ```sql
1089
+ -- PostgreSQL
1090
+ CREATE TABLE hazo_chat_group (
1091
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
1092
+ client_user_id UUID NOT NULL REFERENCES hazo_users(id),
1093
+ name VARCHAR(255),
1094
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
1095
+ changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
1096
+ );
1097
+
1098
+ CREATE INDEX idx_hazo_chat_group_client ON hazo_chat_group(client_user_id);
1099
+ ```
1100
+
1101
+ ### hazo_chat_group_users Table (NEW in v3.0)
1065
1102
 
1066
1103
  ```sql
1104
+ -- PostgreSQL
1105
+ CREATE TABLE hazo_chat_group_users (
1106
+ chat_group_id UUID NOT NULL REFERENCES hazo_chat_group(id) ON DELETE CASCADE,
1107
+ user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
1108
+ role VARCHAR(20) NOT NULL CHECK (role IN ('client', 'staff')),
1109
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
1110
+ changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
1111
+ PRIMARY KEY (chat_group_id, user_id)
1112
+ );
1113
+
1114
+ CREATE INDEX idx_hazo_chat_group_users_user ON hazo_chat_group_users(user_id);
1115
+ CREATE INDEX idx_hazo_chat_group_users_group ON hazo_chat_group_users(chat_group_id);
1116
+ ```
1117
+
1118
+ ### hazo_chat Table (MODIFIED in v3.0)
1119
+
1120
+ ```sql
1121
+ -- PostgreSQL
1067
1122
  CREATE TABLE hazo_chat (
1068
- id TEXT PRIMARY KEY,
1069
- reference_id TEXT NOT NULL,
1123
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
1124
+ reference_id UUID NOT NULL,
1070
1125
  reference_type TEXT DEFAULT 'chat',
1071
- sender_user_id TEXT NOT NULL,
1072
- receiver_user_id TEXT NOT NULL,
1126
+ sender_user_id UUID NOT NULL REFERENCES hazo_users(id),
1127
+ chat_group_id UUID NOT NULL REFERENCES hazo_chat_group(id), -- CHANGED from receiver_user_id
1073
1128
  message_text TEXT,
1074
- reference_list TEXT, -- JSON array of ChatReferenceItem
1075
- read_at TEXT,
1076
- deleted_at TEXT,
1077
- created_at TEXT NOT NULL,
1078
- changed_at TEXT NOT NULL
1129
+ reference_list JSONB, -- JSON array of ChatReferenceItem
1130
+ read_at TIMESTAMPTZ,
1131
+ deleted_at TIMESTAMPTZ,
1132
+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
1133
+ changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
1079
1134
  );
1080
1135
 
1081
1136
  -- Indexes for performance
1082
1137
  CREATE INDEX idx_hazo_chat_reference_id ON hazo_chat(reference_id);
1083
1138
  CREATE INDEX idx_hazo_chat_sender ON hazo_chat(sender_user_id);
1084
- CREATE INDEX idx_hazo_chat_receiver ON hazo_chat(receiver_user_id);
1085
- CREATE INDEX idx_hazo_chat_created ON hazo_chat(created_at);
1139
+ CREATE INDEX idx_hazo_chat_group ON hazo_chat(chat_group_id); -- CHANGED from receiver index
1140
+ CREATE INDEX idx_hazo_chat_created ON hazo_chat(created_at DESC);
1086
1141
  ```
1087
1142
 
1143
+ **Migration Notes:**
1144
+ - Rename column: `receiver_user_id` → `chat_group_id`
1145
+ - Create new tables: `hazo_chat_group`, `hazo_chat_group_users`
1146
+ - Migrate existing 1-1 chats to groups with both users as members
1147
+ - Update foreign key constraints
1148
+
1088
1149
  ## UI Behavior & Responsive Design
1089
1150
 
1090
1151
  ### Hamburger Menu Button
@@ -1148,56 +1209,110 @@ max_file_size_mb = 10
1148
1209
  allowed_types = pdf,png,jpg,jpeg,gif,txt,doc,docx
1149
1210
  ```
1150
1211
 
1151
- ## Migration from v1.x
1212
+ ## Migration from v2.x to v3.0
1152
1213
 
1153
- Version 2.0 introduces breaking changes for a simpler, more reliable architecture.
1214
+ **Version 3.0** introduces breaking changes to support group-based chat architecture.
1154
1215
 
1155
1216
  ### What Changed
1156
1217
 
1157
- | v1.x | v2.x |
1218
+ | v2.x | v3.0 |
1158
1219
  |------|------|
1159
- | Pass `hazo_connect` prop | Not needed - uses API calls |
1160
- | Pass `hazo_auth` prop | Not needed - uses API calls |
1161
- | Pass `document_save_location` prop | Not needed |
1162
- | Direct database access | API-based data access |
1220
+ | `receiver_user_id` prop | `chat_group_id` prop |
1221
+ | 1-1 chat only | Group-based chat with multiple participants |
1222
+ | `receiver_user_id` in API calls | `chat_group_id` in API calls |
1223
+ | Single `hazo_chat` table | Three tables: `hazo_chat_group`, `hazo_chat_group_users`, `hazo_chat` (modified) |
1224
+ | Unread count by `reference_id` | Unread count by `chat_group_id` |
1225
+ | `ChatMessage.receiver_profile` field | Field removed |
1163
1226
 
1164
1227
  ### Migration Steps
1165
1228
 
1166
- 1. **Remove adapter props:**
1229
+ 1. **Database Migration:**
1230
+
1231
+ ```sql
1232
+ -- Step 1: Create new tables
1233
+ CREATE TABLE hazo_chat_group (...); -- See Database Schema section
1234
+ CREATE TABLE hazo_chat_group_users (...);
1235
+
1236
+ -- Step 2: Migrate existing data (example)
1237
+ -- For each unique sender-receiver pair, create a chat group
1238
+ INSERT INTO hazo_chat_group (id, client_user_id, name)
1239
+ SELECT
1240
+ gen_random_uuid(),
1241
+ receiver_user_id,
1242
+ 'Migrated Chat ' || sender_user_id
1243
+ FROM hazo_chat
1244
+ GROUP BY sender_user_id, receiver_user_id;
1245
+
1246
+ -- Step 3: Rename column
1247
+ ALTER TABLE hazo_chat RENAME COLUMN receiver_user_id TO chat_group_id;
1248
+
1249
+ -- Step 4: Update foreign keys
1250
+ ALTER TABLE hazo_chat
1251
+ ADD CONSTRAINT fk_chat_group
1252
+ FOREIGN KEY (chat_group_id)
1253
+ REFERENCES hazo_chat_group(id);
1254
+ ```
1255
+
1256
+ 2. **Update Component Props:**
1167
1257
 
1168
1258
  ```tsx
1169
- // Before (v1.x)
1259
+ // Before (v2.x)
1170
1260
  <HazoChat
1171
- hazo_connect={adapter}
1172
- hazo_auth={authService}
1173
- document_save_location="/uploads"
1174
- receiver_user_id="..."
1261
+ receiver_user_id="user-123"
1262
+ reference_id="chat-456"
1175
1263
  />
1176
1264
 
1177
- // After (v2.x)
1265
+ // After (v3.0)
1178
1266
  <HazoChat
1179
- receiver_user_id="..."
1267
+ chat_group_id="group-123"
1268
+ reference_id="chat-456"
1180
1269
  />
1181
1270
  ```
1182
1271
 
1183
- 2. **Create API routes** (see [API Routes Setup](#api-routes-setup))
1272
+ 3. **Update API Calls:**
1184
1273
 
1185
- 3. **Update imports:**
1274
+ ```typescript
1275
+ // Before (v2.x)
1276
+ const response = await fetch(
1277
+ `/api/hazo_chat/messages?receiver_user_id=${userId}`
1278
+ );
1279
+
1280
+ // After (v3.0)
1281
+ const response = await fetch(
1282
+ `/api/hazo_chat/messages?chat_group_id=${groupId}`
1283
+ );
1284
+ ```
1285
+
1286
+ 4. **Update Type References:**
1186
1287
 
1187
1288
  ```typescript
1188
- // The API handler factory is new
1189
- import { createMessagesHandler } from 'hazo_chat/api';
1289
+ // Remove receiver_profile usage
1290
+ // message.receiver_profile removed
1291
+
1292
+ // Update CreateMessagePayload
1293
+ // receiver_user_id → chat_group_id
1190
1294
  ```
1191
1295
 
1192
1296
  ### Why the Change?
1193
1297
 
1194
- The v1.x architecture required passing server-side adapters (`hazo_connect`, `hazo_auth`) to client components. This caused issues:
1298
+ The v2.x architecture supported only 1-1 communication. This was limiting for scenarios where:
1299
+
1300
+ - Multiple support staff need to rotate on a single client chat
1301
+ - Team collaboration is required within a chat context
1302
+ - Client needs to see all staff responses in one unified thread
1303
+
1304
+ The v3.0 group-based architecture solves these by:
1305
+
1306
+ - Supporting multiple users in a single chat group
1307
+ - Role-based access (client vs staff)
1308
+ - Unified message history for all group members
1309
+ - Better scalability for team-based support scenarios
1310
+
1311
+ ## Migration from v1.x to v2.0
1195
1312
 
1196
- - "Module not found: Can't resolve 'fs'" errors
1197
- - Hydration mismatches
1198
- - Complex webpack configuration
1313
+ Version 2.0 introduced API-first architecture (no server-side dependencies in client components).
1199
1314
 
1200
- The v2.x API-first architecture solves these by keeping all server code in API routes.
1315
+ See [v2.0 release notes](https://github.com/pub12/hazo_chat/releases/tag/v2.0.0) for details.
1201
1316
 
1202
1317
  ## Development
1203
1318