hazo_chat 2.1.1 → 3.2.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.
- package/README.md +467 -67
- package/SETUP_CHECKLIST.md +585 -98
- package/dist/api/messages.d.ts.map +1 -1
- package/dist/api/messages.js +83 -32
- package/dist/api/messages.js.map +1 -1
- package/dist/api/types.d.ts +25 -2
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/unread_count.d.ts +19 -10
- package/dist/api/unread_count.d.ts.map +1 -1
- package/dist/api/unread_count.js +54 -30
- package/dist/api/unread_count.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat.js +6 -6
- package/dist/components/hazo_chat/hazo_chat.js.map +1 -1
- package/dist/components/hazo_chat/hazo_chat_messages.js +3 -3
- package/dist/components/hazo_chat/hazo_chat_messages.js.map +1 -1
- package/dist/hooks/use_chat_messages.d.ts +3 -3
- package/dist/hooks/use_chat_messages.d.ts.map +1 -1
- package/dist/hooks/use_chat_messages.js +15 -20
- package/dist/hooks/use_chat_messages.js.map +1 -1
- package/dist/types/index.d.ts +57 -7
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# hazo_chat
|
|
2
2
|
|
|
3
|
-
A full-featured React chat component library for
|
|
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
|
|
5
|
+
**Version 3.1** - Generic schema supporting multiple chat patterns: support (client-to-staff), peer (1:1), and group conversations.
|
|
6
|
+
|
|
7
|
+
**Version 3.0** - Introduced group-based chat architecture. Multiple users can participate in a single chat group, perfect for support staff rotating on client sessions.
|
|
8
|
+
|
|
9
|
+
**Version 2.0** introduced API-first architecture with no server-side dependencies in client components.
|
|
6
10
|
|
|
7
11
|
## Features
|
|
8
12
|
|
|
13
|
+
- 👥 **Group-Based Chat** - Multiple users can participate in a single chat group
|
|
14
|
+
- 🏗️ **Multiple Chat Patterns** - Support for support (client-to-staff), peer (1:1), and group conversations
|
|
15
|
+
- 🔄 **Role-Based Access** - Support for 'client', 'staff', 'owner', 'admin', and 'member' roles within groups
|
|
9
16
|
- 📱 **Responsive Design** - Works on desktop and mobile with adaptive layout
|
|
10
17
|
- 💬 **Real-time Messaging** - Polling or manual refresh modes for message updates with optimistic UI
|
|
11
18
|
- 📎 **File Attachments** - Support for documents and images with preview
|
|
@@ -478,7 +485,7 @@ export default function ChatPage() {
|
|
|
478
485
|
return (
|
|
479
486
|
<div className="h-screen">
|
|
480
487
|
<HazoChat
|
|
481
|
-
|
|
488
|
+
chat_group_id="group-uuid"
|
|
482
489
|
reference_id="conversation-123"
|
|
483
490
|
reference_type="support"
|
|
484
491
|
title="Chat with Support"
|
|
@@ -497,13 +504,15 @@ hazo_chat requires these API endpoints:
|
|
|
497
504
|
|
|
498
505
|
| Endpoint | Method | Description |
|
|
499
506
|
|----------|--------|-------------|
|
|
500
|
-
| `/api/hazo_chat/messages` | GET | Fetch chat messages |
|
|
501
|
-
| `/api/hazo_chat/messages` | POST | Send a new message |
|
|
507
|
+
| `/api/hazo_chat/messages` | GET | Fetch chat messages (requires `chat_group_id` param) |
|
|
508
|
+
| `/api/hazo_chat/messages` | POST | Send a new message (requires `chat_group_id` in body) |
|
|
502
509
|
| `/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
|
|
510
|
+
| `/api/hazo_chat/unread_count` | GET | Get unread message counts by chat_group_id (optional) |
|
|
504
511
|
| `/api/hazo_auth/me` | GET | Get current authenticated user |
|
|
505
512
|
| `/api/hazo_auth/profiles` | POST | Fetch user profiles by IDs |
|
|
506
513
|
|
|
514
|
+
**Breaking Change (v3.0):** Messages API now uses `chat_group_id` instead of `receiver_user_id`. All group members can see and send messages.
|
|
515
|
+
|
|
507
516
|
### Using Exportable Handlers (Recommended)
|
|
508
517
|
|
|
509
518
|
```typescript
|
|
@@ -563,9 +572,11 @@ hazo_chat provides server-side library functions that can be used in API routes,
|
|
|
563
572
|
|
|
564
573
|
### hazo_chat_get_unread_count
|
|
565
574
|
|
|
566
|
-
Get unread message counts grouped by
|
|
575
|
+
Get unread message counts grouped by chat_group_id for a user.
|
|
567
576
|
|
|
568
|
-
**Purpose:** Returns an array of
|
|
577
|
+
**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.
|
|
578
|
+
|
|
579
|
+
**Breaking Change (v3.0):** Now groups by `chat_group_id` instead of `reference_id`. Accepts optional `chat_group_ids` filter.
|
|
569
580
|
|
|
570
581
|
**Usage:**
|
|
571
582
|
|
|
@@ -579,11 +590,13 @@ const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
|
579
590
|
});
|
|
580
591
|
|
|
581
592
|
// Use the function
|
|
582
|
-
const unreadCounts = await hazo_chat_get_unread_count(
|
|
593
|
+
const unreadCounts = await hazo_chat_get_unread_count({
|
|
594
|
+
user_id: 'user-id-123',
|
|
595
|
+
chat_group_ids: ['group-1', 'group-2'] // Optional: filter by specific groups
|
|
596
|
+
});
|
|
583
597
|
// Returns: [
|
|
584
|
-
// {
|
|
585
|
-
// {
|
|
586
|
-
// { reference_id: '', count: 1 } // Empty reference_id for general messages
|
|
598
|
+
// { chat_group_id: 'group-1', count: 5 },
|
|
599
|
+
// { chat_group_id: 'group-2', count: 3 }
|
|
587
600
|
// ]
|
|
588
601
|
```
|
|
589
602
|
|
|
@@ -591,14 +604,16 @@ const unreadCounts = await hazo_chat_get_unread_count('receiver-user-id-123');
|
|
|
591
604
|
|
|
592
605
|
```typescript
|
|
593
606
|
interface UnreadCountResult {
|
|
594
|
-
|
|
595
|
-
count: number; // Number of unread messages
|
|
607
|
+
chat_group_id: string; // The chat group ID
|
|
608
|
+
count: number; // Number of unread messages in this group
|
|
596
609
|
}
|
|
597
610
|
```
|
|
598
611
|
|
|
599
612
|
**Function Behavior:**
|
|
600
613
|
- Only counts messages where `read_at` is `null` and `deleted_at` is `null`
|
|
601
|
-
-
|
|
614
|
+
- Only counts messages in groups where the user is a member
|
|
615
|
+
- Groups results by `chat_group_id`
|
|
616
|
+
- Optionally filters by specific `chat_group_ids` if provided
|
|
602
617
|
- Sorts results by count (descending - most unread first)
|
|
603
618
|
- Returns empty array if no unread messages found
|
|
604
619
|
- Returns empty array on errors (doesn't throw)
|
|
@@ -620,33 +635,41 @@ const hazo_chat_get_unread_count = createUnreadCountFunction({
|
|
|
620
635
|
export async function GET(request: NextRequest) {
|
|
621
636
|
try {
|
|
622
637
|
const { searchParams } = new URL(request.url);
|
|
623
|
-
const
|
|
638
|
+
const user_id = searchParams.get('user_id');
|
|
639
|
+
const chat_group_ids_param = searchParams.get('chat_group_ids');
|
|
624
640
|
|
|
625
|
-
if (!
|
|
641
|
+
if (!user_id) {
|
|
626
642
|
return NextResponse.json(
|
|
627
|
-
{
|
|
628
|
-
success: false,
|
|
629
|
-
error: '
|
|
643
|
+
{
|
|
644
|
+
success: false,
|
|
645
|
+
error: 'user_id is required',
|
|
630
646
|
unread_counts: []
|
|
631
647
|
},
|
|
632
648
|
{ status: 400 }
|
|
633
649
|
);
|
|
634
650
|
}
|
|
635
651
|
|
|
636
|
-
const
|
|
652
|
+
const chat_group_ids = chat_group_ids_param
|
|
653
|
+
? chat_group_ids_param.split(',')
|
|
654
|
+
: undefined;
|
|
655
|
+
|
|
656
|
+
const unread_counts = await hazo_chat_get_unread_count({
|
|
657
|
+
user_id,
|
|
658
|
+
chat_group_ids
|
|
659
|
+
});
|
|
637
660
|
|
|
638
661
|
return NextResponse.json({
|
|
639
662
|
success: true,
|
|
640
|
-
|
|
663
|
+
user_id,
|
|
641
664
|
unread_counts,
|
|
642
|
-
|
|
665
|
+
total_groups: unread_counts.length,
|
|
643
666
|
total_unread: unread_counts.reduce((sum, item) => sum + item.count, 0)
|
|
644
667
|
});
|
|
645
668
|
} catch (error) {
|
|
646
669
|
const error_message = error instanceof Error ? error.message : 'Unknown error';
|
|
647
670
|
return NextResponse.json(
|
|
648
|
-
{
|
|
649
|
-
success: false,
|
|
671
|
+
{
|
|
672
|
+
success: false,
|
|
650
673
|
error: error_message,
|
|
651
674
|
unread_counts: []
|
|
652
675
|
},
|
|
@@ -714,7 +737,7 @@ export async function getUnreadCounts(receiver_user_id: string) {
|
|
|
714
737
|
|
|
715
738
|
| Prop | Type | Required | Default | Description |
|
|
716
739
|
|------|------|----------|---------|-------------|
|
|
717
|
-
| `
|
|
740
|
+
| `chat_group_id` | `string` | ✅ | - | UUID of the chat group (CHANGED from `receiver_user_id` in v3.0) |
|
|
718
741
|
| `reference_id` | `string` | ❌ | - | Reference ID for chat context grouping |
|
|
719
742
|
| `reference_type` | `string` | ❌ | `'chat'` | Type of reference |
|
|
720
743
|
| `api_base_url` | `string` | ❌ | `'/api/hazo_chat'` | Base URL for API endpoints |
|
|
@@ -735,7 +758,7 @@ export async function getUnreadCounts(receiver_user_id: string) {
|
|
|
735
758
|
|
|
736
759
|
```tsx
|
|
737
760
|
<HazoChat
|
|
738
|
-
|
|
761
|
+
chat_group_id="group-123"
|
|
739
762
|
reference_id="project-456"
|
|
740
763
|
reference_type="project_chat"
|
|
741
764
|
api_base_url="/api/hazo_chat"
|
|
@@ -803,7 +826,7 @@ To make all chat bubbles fully round (instead of the default style with a tail):
|
|
|
803
826
|
|
|
804
827
|
```tsx
|
|
805
828
|
<HazoChat
|
|
806
|
-
|
|
829
|
+
chat_group_id="group-123"
|
|
807
830
|
reference_id="project-456"
|
|
808
831
|
show_sidebar_toggle={false} // Hide hamburger menu
|
|
809
832
|
show_delete_button={false} // Hide delete buttons
|
|
@@ -954,7 +977,7 @@ const {
|
|
|
954
977
|
mark_as_read, // (message_id) => Promise<void>
|
|
955
978
|
refresh, // () => void - Reload messages
|
|
956
979
|
} = useChatMessages({
|
|
957
|
-
|
|
980
|
+
chat_group_id: 'group-456', // CHANGED from receiver_user_id in v3.0
|
|
958
981
|
reference_id: 'chat-123',
|
|
959
982
|
reference_type: 'direct',
|
|
960
983
|
api_base_url: '/api/hazo_chat',
|
|
@@ -1017,7 +1040,7 @@ interface ChatMessage {
|
|
|
1017
1040
|
reference_id: string;
|
|
1018
1041
|
reference_type: string;
|
|
1019
1042
|
sender_user_id: string;
|
|
1020
|
-
|
|
1043
|
+
chat_group_id: string; // CHANGED from receiver_user_id in v3.0
|
|
1021
1044
|
message_text: string | null;
|
|
1022
1045
|
reference_list: ChatReferenceItem[] | null;
|
|
1023
1046
|
read_at: string | null;
|
|
@@ -1025,7 +1048,7 @@ interface ChatMessage {
|
|
|
1025
1048
|
created_at: string;
|
|
1026
1049
|
changed_at: string;
|
|
1027
1050
|
sender_profile?: HazoUserProfile;
|
|
1028
|
-
receiver_profile
|
|
1051
|
+
// receiver_profile removed in v3.0
|
|
1029
1052
|
is_sender: boolean;
|
|
1030
1053
|
send_status?: 'sending' | 'sent' | 'failed';
|
|
1031
1054
|
}
|
|
@@ -1059,32 +1082,204 @@ interface ChatReferenceItem {
|
|
|
1059
1082
|
|
|
1060
1083
|
**Note on MIME Type:** The `mime_type` property is optional. If not provided, the component will automatically infer the MIME type from the file extension (e.g., `.jpg` → `image/jpeg`, `.pdf` → `application/pdf`). This ensures document preview works even when `mime_type` is not explicitly set. Supported file extensions for inference include: `pdf`, `png`, `jpg`, `jpeg`, `gif`, `webp`, `txt`, `doc`, `docx`.
|
|
1061
1084
|
|
|
1085
|
+
### ChatGroup (NEW in v3.0, UPDATED in v3.1)
|
|
1086
|
+
|
|
1087
|
+
```typescript
|
|
1088
|
+
interface ChatGroup {
|
|
1089
|
+
id: string;
|
|
1090
|
+
client_user_id: string | null | undefined; // NULLABLE in v3.1 (only required for 'support' groups)
|
|
1091
|
+
group_type: ChatGroupType; // NEW in v3.1
|
|
1092
|
+
name?: string | null;
|
|
1093
|
+
created_at: string;
|
|
1094
|
+
changed_at: string;
|
|
1095
|
+
}
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
### ChatGroupType (NEW in v3.1)
|
|
1099
|
+
|
|
1100
|
+
```typescript
|
|
1101
|
+
type ChatGroupType = 'support' | 'peer' | 'group';
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
**Group Type Definitions:**
|
|
1105
|
+
- `'support'`: Client-to-staff support conversation (requires `client_user_id`)
|
|
1106
|
+
- `'peer'`: Peer-to-peer direct message between two users
|
|
1107
|
+
- `'group'`: Multi-user group conversation
|
|
1108
|
+
|
|
1109
|
+
### ChatGroupUser (NEW in v3.0, UPDATED in v3.1)
|
|
1110
|
+
|
|
1111
|
+
```typescript
|
|
1112
|
+
interface ChatGroupUser {
|
|
1113
|
+
chat_group_id: string;
|
|
1114
|
+
user_id: string;
|
|
1115
|
+
role: ChatGroupUserRole; // EXPANDED in v3.1
|
|
1116
|
+
created_at: string;
|
|
1117
|
+
changed_at: string;
|
|
1118
|
+
}
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
### ChatGroupUserRole (NEW in v3.0, EXPANDED in v3.1)
|
|
1122
|
+
|
|
1123
|
+
```typescript
|
|
1124
|
+
// v3.0
|
|
1125
|
+
type ChatGroupUserRole = 'client' | 'staff';
|
|
1126
|
+
|
|
1127
|
+
// v3.1 (expanded)
|
|
1128
|
+
type ChatGroupUserRole = 'client' | 'staff' | 'owner' | 'admin' | 'member';
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
**Role Definitions:**
|
|
1132
|
+
- `'client'`: Customer/end-user in support scenarios
|
|
1133
|
+
- `'staff'`: Support personnel in support scenarios
|
|
1134
|
+
- `'owner'`: Creator/owner of peer or group chats
|
|
1135
|
+
- `'admin'`: Delegated administrator in group chats
|
|
1136
|
+
- `'member'`: Standard participant in peer or group chats
|
|
1137
|
+
|
|
1138
|
+
### ChatGroupWithMembers (NEW in v3.0, UPDATED in v3.1)
|
|
1139
|
+
|
|
1140
|
+
```typescript
|
|
1141
|
+
interface ChatGroupWithMembers extends ChatGroup {
|
|
1142
|
+
members: (ChatGroupUser & { profile?: HazoUserProfile })[];
|
|
1143
|
+
owner_profile?: HazoUserProfile; // NEW in v3.1 - profile of the group owner
|
|
1144
|
+
}
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1062
1147
|
## Database Schema
|
|
1063
1148
|
|
|
1064
|
-
|
|
1149
|
+
**Breaking Changes in v3.0:** The database schema has been updated to support group-based chat. Migration required.
|
|
1150
|
+
|
|
1151
|
+
**New in v3.1:** Generic schema supporting multiple chat patterns - support, peer, and group conversations.
|
|
1152
|
+
|
|
1153
|
+
### PostgreSQL Enum Types (RECOMMENDED)
|
|
1154
|
+
|
|
1155
|
+
For PostgreSQL installations, create these custom enum types for type safety and consistency:
|
|
1156
|
+
|
|
1157
|
+
```sql
|
|
1158
|
+
-- Reference type for chat contexts
|
|
1159
|
+
CREATE TYPE hazo_enum_chat_type AS ENUM ('chat', 'field', 'project', 'support', 'general');
|
|
1160
|
+
|
|
1161
|
+
-- Group type for conversation patterns (v3.1)
|
|
1162
|
+
CREATE TYPE hazo_enum_group_type AS ENUM ('support', 'peer', 'group');
|
|
1163
|
+
|
|
1164
|
+
-- Membership roles (v3.1)
|
|
1165
|
+
CREATE TYPE hazo_enum_group_role AS ENUM ('client', 'staff', 'owner', 'admin', 'member');
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
### Group Types
|
|
1169
|
+
|
|
1170
|
+
hazo_chat supports three distinct group types to accommodate different conversation patterns:
|
|
1171
|
+
|
|
1172
|
+
| Type | Description | Use Case | `client_user_id` | Typical Roles |
|
|
1173
|
+
|------|-------------|----------|------------------|---------------|
|
|
1174
|
+
| **support** | Client-to-staff support conversation | Customer support, helpdesk | Required (identifies the client) | 'client', 'staff' |
|
|
1175
|
+
| **peer** | Peer-to-peer direct message (1:1) | Direct messaging between equals | Not used (null) | 'owner', 'member' |
|
|
1176
|
+
| **group** | Multi-user group conversation | Team collaboration, channels | Not used (null) | 'owner', 'admin', 'member' |
|
|
1177
|
+
|
|
1178
|
+
### Role Types
|
|
1179
|
+
|
|
1180
|
+
The `role` field in `hazo_chat_group_users` defines each member's permissions and relationship to the group:
|
|
1181
|
+
|
|
1182
|
+
| Role | Description | Used In | Capabilities |
|
|
1183
|
+
|------|-------------|---------|--------------|
|
|
1184
|
+
| **client** | Customer/end-user receiving support | support groups | Send messages, view messages |
|
|
1185
|
+
| **staff** | Support personnel helping clients | support groups | Send messages, view messages, assist client |
|
|
1186
|
+
| **owner** | Creator/owner of the conversation | peer, group | Full control, can add/remove members |
|
|
1187
|
+
| **admin** | Delegated administrator | group | Can manage members, moderate content |
|
|
1188
|
+
| **member** | Standard participant | peer, group | Send messages, view messages |
|
|
1189
|
+
|
|
1190
|
+
### hazo_chat_group Table (UPDATED in v3.1)
|
|
1191
|
+
|
|
1192
|
+
```sql
|
|
1193
|
+
-- PostgreSQL with enums (RECOMMENDED)
|
|
1194
|
+
CREATE TABLE hazo_chat_group (
|
|
1195
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1196
|
+
client_user_id UUID REFERENCES hazo_users(id), -- NULLABLE in v3.1
|
|
1197
|
+
group_type hazo_enum_group_type NOT NULL DEFAULT 'support', -- NEW in v3.1
|
|
1198
|
+
name VARCHAR(255),
|
|
1199
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1200
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1201
|
+
);
|
|
1202
|
+
|
|
1203
|
+
-- PostgreSQL without enums (alternative)
|
|
1204
|
+
CREATE TABLE hazo_chat_group (
|
|
1205
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1206
|
+
client_user_id UUID REFERENCES hazo_users(id), -- NULLABLE in v3.1
|
|
1207
|
+
group_type VARCHAR(20) NOT NULL DEFAULT 'support' CHECK (group_type IN ('support', 'peer', 'group')), -- NEW in v3.1
|
|
1208
|
+
name VARCHAR(255),
|
|
1209
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1210
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1211
|
+
);
|
|
1212
|
+
|
|
1213
|
+
CREATE INDEX idx_hazo_chat_group_client ON hazo_chat_group(client_user_id);
|
|
1214
|
+
CREATE INDEX idx_hazo_chat_group_type ON hazo_chat_group(group_type); -- NEW in v3.1
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
**Column Changes in v3.1:**
|
|
1218
|
+
- `client_user_id`: Changed from `NOT NULL` to nullable - only required for 'support' type groups
|
|
1219
|
+
- `group_type`: NEW field - defines the conversation pattern ('support', 'peer', 'group')
|
|
1220
|
+
|
|
1221
|
+
### hazo_chat_group_users Table (UPDATED in v3.1)
|
|
1222
|
+
|
|
1223
|
+
```sql
|
|
1224
|
+
-- PostgreSQL with enums (RECOMMENDED)
|
|
1225
|
+
CREATE TABLE hazo_chat_group_users (
|
|
1226
|
+
chat_group_id UUID NOT NULL REFERENCES hazo_chat_group(id) ON DELETE CASCADE,
|
|
1227
|
+
user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
1228
|
+
role hazo_enum_group_role NOT NULL, -- EXPANDED in v3.1
|
|
1229
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1230
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1231
|
+
PRIMARY KEY (chat_group_id, user_id)
|
|
1232
|
+
);
|
|
1233
|
+
|
|
1234
|
+
-- PostgreSQL without enums (alternative)
|
|
1235
|
+
CREATE TABLE hazo_chat_group_users (
|
|
1236
|
+
chat_group_id UUID NOT NULL REFERENCES hazo_chat_group(id) ON DELETE CASCADE,
|
|
1237
|
+
user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
|
|
1238
|
+
role VARCHAR(20) NOT NULL CHECK (role IN ('client', 'staff', 'owner', 'admin', 'member')), -- EXPANDED in v3.1
|
|
1239
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1240
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1241
|
+
PRIMARY KEY (chat_group_id, user_id)
|
|
1242
|
+
);
|
|
1243
|
+
|
|
1244
|
+
CREATE INDEX idx_hazo_chat_group_users_user ON hazo_chat_group_users(user_id);
|
|
1245
|
+
CREATE INDEX idx_hazo_chat_group_users_group ON hazo_chat_group_users(chat_group_id);
|
|
1246
|
+
CREATE INDEX idx_hazo_chat_group_users_role ON hazo_chat_group_users(role); -- NEW in v3.1
|
|
1247
|
+
```
|
|
1248
|
+
|
|
1249
|
+
**Column Changes in v3.1:**
|
|
1250
|
+
- `role`: EXPANDED from ('client', 'staff') to ('client', 'staff', 'owner', 'admin', 'member')
|
|
1251
|
+
|
|
1252
|
+
### hazo_chat Table (MODIFIED in v3.0)
|
|
1065
1253
|
|
|
1066
1254
|
```sql
|
|
1255
|
+
-- PostgreSQL
|
|
1067
1256
|
CREATE TABLE hazo_chat (
|
|
1068
|
-
id
|
|
1069
|
-
reference_id
|
|
1257
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
1258
|
+
reference_id UUID NOT NULL,
|
|
1070
1259
|
reference_type TEXT DEFAULT 'chat',
|
|
1071
|
-
sender_user_id
|
|
1072
|
-
|
|
1260
|
+
sender_user_id UUID NOT NULL REFERENCES hazo_users(id),
|
|
1261
|
+
chat_group_id UUID NOT NULL REFERENCES hazo_chat_group(id), -- CHANGED from receiver_user_id
|
|
1073
1262
|
message_text TEXT,
|
|
1074
|
-
reference_list
|
|
1075
|
-
read_at
|
|
1076
|
-
deleted_at
|
|
1077
|
-
created_at
|
|
1078
|
-
changed_at
|
|
1263
|
+
reference_list JSONB, -- JSON array of ChatReferenceItem
|
|
1264
|
+
read_at TIMESTAMPTZ,
|
|
1265
|
+
deleted_at TIMESTAMPTZ,
|
|
1266
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
1267
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
1079
1268
|
);
|
|
1080
1269
|
|
|
1081
1270
|
-- Indexes for performance
|
|
1082
1271
|
CREATE INDEX idx_hazo_chat_reference_id ON hazo_chat(reference_id);
|
|
1083
1272
|
CREATE INDEX idx_hazo_chat_sender ON hazo_chat(sender_user_id);
|
|
1084
|
-
CREATE INDEX
|
|
1085
|
-
CREATE INDEX idx_hazo_chat_created ON hazo_chat(created_at);
|
|
1273
|
+
CREATE INDEX idx_hazo_chat_group ON hazo_chat(chat_group_id); -- CHANGED from receiver index
|
|
1274
|
+
CREATE INDEX idx_hazo_chat_created ON hazo_chat(created_at DESC);
|
|
1086
1275
|
```
|
|
1087
1276
|
|
|
1277
|
+
**Migration Notes:**
|
|
1278
|
+
- Rename column: `receiver_user_id` → `chat_group_id`
|
|
1279
|
+
- Create new tables: `hazo_chat_group`, `hazo_chat_group_users`
|
|
1280
|
+
- Migrate existing 1-1 chats to groups with both users as members
|
|
1281
|
+
- Update foreign key constraints
|
|
1282
|
+
|
|
1088
1283
|
## UI Behavior & Responsive Design
|
|
1089
1284
|
|
|
1090
1285
|
### Hamburger Menu Button
|
|
@@ -1148,56 +1343,261 @@ max_file_size_mb = 10
|
|
|
1148
1343
|
allowed_types = pdf,png,jpg,jpeg,gif,txt,doc,docx
|
|
1149
1344
|
```
|
|
1150
1345
|
|
|
1151
|
-
## Migration from
|
|
1346
|
+
## Migration from v3.0 to v3.1
|
|
1347
|
+
|
|
1348
|
+
**Version 3.1** introduces schema changes to support multiple chat patterns (support, peer, group) while maintaining backward compatibility.
|
|
1349
|
+
|
|
1350
|
+
### What Changed in v3.1
|
|
1351
|
+
|
|
1352
|
+
| v3.0 | v3.1 |
|
|
1353
|
+
|------|------|
|
|
1354
|
+
| Fixed support pattern only | Three patterns: support, peer, group |
|
|
1355
|
+
| `client_user_id` always required | `client_user_id` nullable (only for support groups) |
|
|
1356
|
+
| 2 roles: 'client', 'staff' | 5 roles: 'client', 'staff', 'owner', 'admin', 'member' |
|
|
1357
|
+
| No `group_type` field | NEW `group_type` field ('support', 'peer', 'group') |
|
|
1358
|
+
|
|
1359
|
+
### Migration Steps (v3.0 to v3.1)
|
|
1360
|
+
|
|
1361
|
+
**Important:** v3.1 is backward compatible with v3.0 schema. Existing support-type groups continue to work without changes.
|
|
1362
|
+
|
|
1363
|
+
1. **Create PostgreSQL Enum Types (Optional but Recommended):**
|
|
1364
|
+
|
|
1365
|
+
```sql
|
|
1366
|
+
-- Reference type for chat contexts
|
|
1367
|
+
CREATE TYPE hazo_enum_chat_type AS ENUM ('chat', 'field', 'project', 'support', 'general');
|
|
1368
|
+
|
|
1369
|
+
-- Group type for conversation patterns
|
|
1370
|
+
CREATE TYPE hazo_enum_group_type AS ENUM ('support', 'peer', 'group');
|
|
1371
|
+
|
|
1372
|
+
-- Membership roles
|
|
1373
|
+
CREATE TYPE hazo_enum_group_role AS ENUM ('client', 'staff', 'owner', 'admin', 'member');
|
|
1374
|
+
```
|
|
1375
|
+
|
|
1376
|
+
2. **Add group_type Column to hazo_chat_group:**
|
|
1377
|
+
|
|
1378
|
+
```sql
|
|
1379
|
+
-- Add group_type column (defaults to 'support' for backward compatibility)
|
|
1380
|
+
ALTER TABLE hazo_chat_group
|
|
1381
|
+
ADD COLUMN group_type VARCHAR(20) NOT NULL DEFAULT 'support'
|
|
1382
|
+
CHECK (group_type IN ('support', 'peer', 'group'));
|
|
1383
|
+
|
|
1384
|
+
-- Or with enum type (if you created the enum):
|
|
1385
|
+
ALTER TABLE hazo_chat_group
|
|
1386
|
+
ADD COLUMN group_type hazo_enum_group_type NOT NULL DEFAULT 'support';
|
|
1387
|
+
|
|
1388
|
+
-- Add index for group_type
|
|
1389
|
+
CREATE INDEX idx_hazo_chat_group_type ON hazo_chat_group(group_type);
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
3. **Make client_user_id Nullable:**
|
|
1393
|
+
|
|
1394
|
+
```sql
|
|
1395
|
+
-- Remove NOT NULL constraint from client_user_id
|
|
1396
|
+
ALTER TABLE hazo_chat_group
|
|
1397
|
+
ALTER COLUMN client_user_id DROP NOT NULL;
|
|
1398
|
+
```
|
|
1399
|
+
|
|
1400
|
+
4. **Update Role Constraint in hazo_chat_group_users:**
|
|
1401
|
+
|
|
1402
|
+
```sql
|
|
1403
|
+
-- Drop old constraint
|
|
1404
|
+
ALTER TABLE hazo_chat_group_users
|
|
1405
|
+
DROP CONSTRAINT IF EXISTS hazo_chat_group_users_role_check;
|
|
1406
|
+
|
|
1407
|
+
-- Add new constraint with expanded roles
|
|
1408
|
+
ALTER TABLE hazo_chat_group_users
|
|
1409
|
+
ADD CONSTRAINT hazo_chat_group_users_role_check
|
|
1410
|
+
CHECK (role IN ('client', 'staff', 'owner', 'admin', 'member'));
|
|
1411
|
+
|
|
1412
|
+
-- Or with enum type (if you created the enum):
|
|
1413
|
+
ALTER TABLE hazo_chat_group_users
|
|
1414
|
+
ALTER COLUMN role TYPE hazo_enum_group_role
|
|
1415
|
+
USING role::hazo_enum_group_role;
|
|
1416
|
+
|
|
1417
|
+
-- Add index for role
|
|
1418
|
+
CREATE INDEX idx_hazo_chat_group_users_role ON hazo_chat_group_users(role);
|
|
1419
|
+
```
|
|
1420
|
+
|
|
1421
|
+
5. **Verify Existing Data:**
|
|
1422
|
+
|
|
1423
|
+
```sql
|
|
1424
|
+
-- All existing groups should have group_type = 'support'
|
|
1425
|
+
SELECT group_type, COUNT(*)
|
|
1426
|
+
FROM hazo_chat_group
|
|
1427
|
+
GROUP BY group_type;
|
|
1428
|
+
|
|
1429
|
+
-- All existing members should have role IN ('client', 'staff')
|
|
1430
|
+
SELECT role, COUNT(*)
|
|
1431
|
+
FROM hazo_chat_group_users
|
|
1432
|
+
GROUP BY role;
|
|
1433
|
+
```
|
|
1434
|
+
|
|
1435
|
+
### Creating New Group Types
|
|
1436
|
+
|
|
1437
|
+
After migration, you can create peer and group conversations:
|
|
1438
|
+
|
|
1439
|
+
```typescript
|
|
1440
|
+
// Support group (v3.0 style - still works)
|
|
1441
|
+
await db.insert_with_result('hazo_chat_group', {
|
|
1442
|
+
client_user_id: 'client-uuid',
|
|
1443
|
+
group_type: 'support',
|
|
1444
|
+
name: 'Customer Support'
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1447
|
+
// Peer-to-peer chat (v3.1)
|
|
1448
|
+
await db.insert_with_result('hazo_chat_group', {
|
|
1449
|
+
client_user_id: null, // Not used for peer chats
|
|
1450
|
+
group_type: 'peer',
|
|
1451
|
+
name: 'Alice & Bob'
|
|
1452
|
+
});
|
|
1453
|
+
|
|
1454
|
+
// Group conversation (v3.1)
|
|
1455
|
+
await db.insert_with_result('hazo_chat_group', {
|
|
1456
|
+
client_user_id: null, // Not used for group chats
|
|
1457
|
+
group_type: 'group',
|
|
1458
|
+
name: 'Project Team'
|
|
1459
|
+
});
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
### No Code Changes Required
|
|
1463
|
+
|
|
1464
|
+
The v3.1 schema changes are transparent to the component API. Your existing code continues to work:
|
|
1465
|
+
|
|
1466
|
+
```tsx
|
|
1467
|
+
// This works for all group types (support, peer, group)
|
|
1468
|
+
<HazoChat
|
|
1469
|
+
chat_group_id="group-123"
|
|
1470
|
+
reference_id="chat-456"
|
|
1471
|
+
reference_type="support"
|
|
1472
|
+
/>
|
|
1473
|
+
```
|
|
1474
|
+
|
|
1475
|
+
### TypeScript Type Updates
|
|
1476
|
+
|
|
1477
|
+
If you use TypeScript types from hazo_chat:
|
|
1478
|
+
|
|
1479
|
+
```typescript
|
|
1480
|
+
// v3.1 types (automatically available after updating package)
|
|
1481
|
+
import type {
|
|
1482
|
+
ChatGroup, // client_user_id is now optional
|
|
1483
|
+
ChatGroupType, // 'support' | 'peer' | 'group'
|
|
1484
|
+
ChatGroupUserRole // 'client' | 'staff' | 'owner' | 'admin' | 'member'
|
|
1485
|
+
} from 'hazo_chat';
|
|
1486
|
+
|
|
1487
|
+
const group: ChatGroup = {
|
|
1488
|
+
id: 'group-123',
|
|
1489
|
+
client_user_id: null, // ✅ Now optional
|
|
1490
|
+
group_type: 'peer', // ✅ New field
|
|
1491
|
+
name: 'Chat',
|
|
1492
|
+
created_at: new Date().toISOString(),
|
|
1493
|
+
changed_at: new Date().toISOString()
|
|
1494
|
+
};
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
## Migration from v2.x to v3.0
|
|
1152
1498
|
|
|
1153
|
-
Version
|
|
1499
|
+
**Version 3.0** introduces breaking changes to support group-based chat architecture.
|
|
1154
1500
|
|
|
1155
1501
|
### What Changed
|
|
1156
1502
|
|
|
1157
|
-
|
|
|
1503
|
+
| v2.x | v3.0 |
|
|
1158
1504
|
|------|------|
|
|
1159
|
-
|
|
|
1160
|
-
|
|
|
1161
|
-
|
|
|
1162
|
-
|
|
|
1505
|
+
| `receiver_user_id` prop | `chat_group_id` prop |
|
|
1506
|
+
| 1-1 chat only | Group-based chat with multiple participants |
|
|
1507
|
+
| `receiver_user_id` in API calls | `chat_group_id` in API calls |
|
|
1508
|
+
| Single `hazo_chat` table | Three tables: `hazo_chat_group`, `hazo_chat_group_users`, `hazo_chat` (modified) |
|
|
1509
|
+
| Unread count by `reference_id` | Unread count by `chat_group_id` |
|
|
1510
|
+
| `ChatMessage.receiver_profile` field | Field removed |
|
|
1163
1511
|
|
|
1164
1512
|
### Migration Steps
|
|
1165
1513
|
|
|
1166
|
-
1. **
|
|
1514
|
+
1. **Database Migration:**
|
|
1515
|
+
|
|
1516
|
+
```sql
|
|
1517
|
+
-- Step 1: Create new tables
|
|
1518
|
+
CREATE TABLE hazo_chat_group (...); -- See Database Schema section
|
|
1519
|
+
CREATE TABLE hazo_chat_group_users (...);
|
|
1520
|
+
|
|
1521
|
+
-- Step 2: Migrate existing data (example)
|
|
1522
|
+
-- For each unique sender-receiver pair, create a chat group
|
|
1523
|
+
INSERT INTO hazo_chat_group (id, client_user_id, name)
|
|
1524
|
+
SELECT
|
|
1525
|
+
gen_random_uuid(),
|
|
1526
|
+
receiver_user_id,
|
|
1527
|
+
'Migrated Chat ' || sender_user_id
|
|
1528
|
+
FROM hazo_chat
|
|
1529
|
+
GROUP BY sender_user_id, receiver_user_id;
|
|
1530
|
+
|
|
1531
|
+
-- Step 3: Rename column
|
|
1532
|
+
ALTER TABLE hazo_chat RENAME COLUMN receiver_user_id TO chat_group_id;
|
|
1533
|
+
|
|
1534
|
+
-- Step 4: Update foreign keys
|
|
1535
|
+
ALTER TABLE hazo_chat
|
|
1536
|
+
ADD CONSTRAINT fk_chat_group
|
|
1537
|
+
FOREIGN KEY (chat_group_id)
|
|
1538
|
+
REFERENCES hazo_chat_group(id);
|
|
1539
|
+
```
|
|
1540
|
+
|
|
1541
|
+
2. **Update Component Props:**
|
|
1167
1542
|
|
|
1168
1543
|
```tsx
|
|
1169
|
-
// Before (
|
|
1544
|
+
// Before (v2.x)
|
|
1170
1545
|
<HazoChat
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
document_save_location="/uploads"
|
|
1174
|
-
receiver_user_id="..."
|
|
1546
|
+
receiver_user_id="user-123"
|
|
1547
|
+
reference_id="chat-456"
|
|
1175
1548
|
/>
|
|
1176
1549
|
|
|
1177
|
-
// After (
|
|
1550
|
+
// After (v3.0)
|
|
1178
1551
|
<HazoChat
|
|
1179
|
-
|
|
1552
|
+
chat_group_id="group-123"
|
|
1553
|
+
reference_id="chat-456"
|
|
1180
1554
|
/>
|
|
1181
1555
|
```
|
|
1182
1556
|
|
|
1183
|
-
|
|
1557
|
+
3. **Update API Calls:**
|
|
1558
|
+
|
|
1559
|
+
```typescript
|
|
1560
|
+
// Before (v2.x)
|
|
1561
|
+
const response = await fetch(
|
|
1562
|
+
`/api/hazo_chat/messages?receiver_user_id=${userId}`
|
|
1563
|
+
);
|
|
1564
|
+
|
|
1565
|
+
// After (v3.0)
|
|
1566
|
+
const response = await fetch(
|
|
1567
|
+
`/api/hazo_chat/messages?chat_group_id=${groupId}`
|
|
1568
|
+
);
|
|
1569
|
+
```
|
|
1184
1570
|
|
|
1185
|
-
|
|
1571
|
+
4. **Update Type References:**
|
|
1186
1572
|
|
|
1187
1573
|
```typescript
|
|
1188
|
-
//
|
|
1189
|
-
|
|
1574
|
+
// Remove receiver_profile usage
|
|
1575
|
+
// message.receiver_profile → removed
|
|
1576
|
+
|
|
1577
|
+
// Update CreateMessagePayload
|
|
1578
|
+
// receiver_user_id → chat_group_id
|
|
1190
1579
|
```
|
|
1191
1580
|
|
|
1192
1581
|
### Why the Change?
|
|
1193
1582
|
|
|
1194
|
-
The
|
|
1583
|
+
The v2.x architecture supported only 1-1 communication. This was limiting for scenarios where:
|
|
1584
|
+
|
|
1585
|
+
- Multiple support staff need to rotate on a single client chat
|
|
1586
|
+
- Team collaboration is required within a chat context
|
|
1587
|
+
- Client needs to see all staff responses in one unified thread
|
|
1588
|
+
|
|
1589
|
+
The v3.0 group-based architecture solves these by:
|
|
1590
|
+
|
|
1591
|
+
- Supporting multiple users in a single chat group
|
|
1592
|
+
- Role-based access (client vs staff)
|
|
1593
|
+
- Unified message history for all group members
|
|
1594
|
+
- Better scalability for team-based support scenarios
|
|
1595
|
+
|
|
1596
|
+
## Migration from v1.x to v2.0
|
|
1195
1597
|
|
|
1196
|
-
-
|
|
1197
|
-
- Hydration mismatches
|
|
1198
|
-
- Complex webpack configuration
|
|
1598
|
+
Version 2.0 introduced API-first architecture (no server-side dependencies in client components).
|
|
1199
1599
|
|
|
1200
|
-
|
|
1600
|
+
See [v2.0 release notes](https://github.com/pub12/hazo_chat/releases/tag/v2.0.0) for details.
|
|
1201
1601
|
|
|
1202
1602
|
## Development
|
|
1203
1603
|
|