feat: Implement messaging functionality with conversation and chat screens, and enhance agent detail views.
This commit is contained in:
281
lib/features/messaging/data/models/messaging_models.dart
Normal file
281
lib/features/messaging/data/models/messaging_models.dart
Normal file
@@ -0,0 +1,281 @@
|
||||
enum MessageType {
|
||||
text,
|
||||
file,
|
||||
image,
|
||||
system;
|
||||
|
||||
static MessageType fromString(String? value) {
|
||||
switch (value?.toUpperCase()) {
|
||||
case 'FILE':
|
||||
return MessageType.file;
|
||||
case 'IMAGE':
|
||||
return MessageType.image;
|
||||
case 'SYSTEM':
|
||||
return MessageType.system;
|
||||
default:
|
||||
return MessageType.text;
|
||||
}
|
||||
}
|
||||
|
||||
String toApiString() => name.toUpperCase();
|
||||
}
|
||||
|
||||
enum MessageStatus {
|
||||
sent,
|
||||
delivered,
|
||||
read;
|
||||
|
||||
static MessageStatus fromString(String? value) {
|
||||
switch (value?.toUpperCase()) {
|
||||
case 'DELIVERED':
|
||||
return MessageStatus.delivered;
|
||||
case 'READ':
|
||||
return MessageStatus.read;
|
||||
default:
|
||||
return MessageStatus.sent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OtherParty {
|
||||
final String id;
|
||||
final String? userId;
|
||||
final String name;
|
||||
final String? avatar;
|
||||
final String? headline;
|
||||
final bool isOnline;
|
||||
final String? lastSeenAt;
|
||||
|
||||
const OtherParty({
|
||||
required this.id,
|
||||
this.userId,
|
||||
required this.name,
|
||||
this.avatar,
|
||||
this.headline,
|
||||
this.isOnline = false,
|
||||
this.lastSeenAt,
|
||||
});
|
||||
|
||||
factory OtherParty.fromJson(Map<String, dynamic> json) {
|
||||
return OtherParty(
|
||||
id: json['id'] as String,
|
||||
userId: json['userId'] as String?,
|
||||
name: json['name'] as String? ?? '',
|
||||
avatar: json['avatar'] as String?,
|
||||
headline: json['headline'] as String?,
|
||||
isOnline: json['isOnline'] as bool? ?? false,
|
||||
lastSeenAt: json['lastSeenAt'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Conversation {
|
||||
final String id;
|
||||
final String userId;
|
||||
final String agentProfileId;
|
||||
final String? lastMessageAt;
|
||||
final String? lastMessageText;
|
||||
final int userUnreadCount;
|
||||
final int agentUnreadCount;
|
||||
final int unreadCount;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
final OtherParty otherParty;
|
||||
final List<ChatMessage>? messages;
|
||||
|
||||
const Conversation({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.agentProfileId,
|
||||
this.lastMessageAt,
|
||||
this.lastMessageText,
|
||||
this.userUnreadCount = 0,
|
||||
this.agentUnreadCount = 0,
|
||||
this.unreadCount = 0,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.otherParty,
|
||||
this.messages,
|
||||
});
|
||||
|
||||
factory Conversation.fromJson(Map<String, dynamic> json) {
|
||||
return Conversation(
|
||||
id: json['id'] as String,
|
||||
userId: json['userId'] as String,
|
||||
agentProfileId: json['agentProfileId'] as String,
|
||||
lastMessageAt: json['lastMessageAt'] as String?,
|
||||
lastMessageText: json['lastMessageText'] as String?,
|
||||
userUnreadCount: json['userUnreadCount'] as int? ?? 0,
|
||||
agentUnreadCount: json['agentUnreadCount'] as int? ?? 0,
|
||||
unreadCount: json['unreadCount'] as int? ?? 0,
|
||||
createdAt: json['createdAt'] as String,
|
||||
updatedAt: json['updatedAt'] as String,
|
||||
otherParty:
|
||||
OtherParty.fromJson(json['otherParty'] as Map<String, dynamic>),
|
||||
messages: (json['messages'] as List<dynamic>?)
|
||||
?.map((e) => ChatMessage.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Conversation copyWith({
|
||||
int? unreadCount,
|
||||
String? lastMessageAt,
|
||||
String? lastMessageText,
|
||||
OtherParty? otherParty,
|
||||
List<ChatMessage>? messages,
|
||||
}) {
|
||||
return Conversation(
|
||||
id: id,
|
||||
userId: userId,
|
||||
agentProfileId: agentProfileId,
|
||||
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
|
||||
lastMessageText: lastMessageText ?? this.lastMessageText,
|
||||
userUnreadCount: userUnreadCount,
|
||||
agentUnreadCount: agentUnreadCount,
|
||||
unreadCount: unreadCount ?? this.unreadCount,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
otherParty: otherParty ?? this.otherParty,
|
||||
messages: messages ?? this.messages,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SenderProfile {
|
||||
final String? firstName;
|
||||
final String? lastName;
|
||||
final String? avatar;
|
||||
|
||||
const SenderProfile({this.firstName, this.lastName, this.avatar});
|
||||
|
||||
factory SenderProfile.fromJson(Map<String, dynamic> json) {
|
||||
return SenderProfile(
|
||||
firstName: json['firstName'] as String?,
|
||||
lastName: json['lastName'] as String?,
|
||||
avatar: json['avatar'] as String?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MessageSender {
|
||||
final String id;
|
||||
final String role;
|
||||
final SenderProfile? userProfile;
|
||||
final SenderProfile? agentProfile;
|
||||
|
||||
const MessageSender({
|
||||
required this.id,
|
||||
required this.role,
|
||||
this.userProfile,
|
||||
this.agentProfile,
|
||||
});
|
||||
|
||||
String get displayName {
|
||||
final profile = userProfile ?? agentProfile;
|
||||
if (profile == null) return 'Unknown';
|
||||
return '${profile.firstName ?? ''} ${profile.lastName ?? ''}'.trim();
|
||||
}
|
||||
|
||||
String? get avatar => userProfile?.avatar ?? agentProfile?.avatar;
|
||||
|
||||
factory MessageSender.fromJson(Map<String, dynamic> json) {
|
||||
return MessageSender(
|
||||
id: json['id'] as String,
|
||||
role: json['role'] as String? ?? '',
|
||||
userProfile: json['userProfile'] != null
|
||||
? SenderProfile.fromJson(
|
||||
json['userProfile'] as Map<String, dynamic>)
|
||||
: null,
|
||||
agentProfile: json['agentProfile'] != null
|
||||
? SenderProfile.fromJson(
|
||||
json['agentProfile'] as Map<String, dynamic>)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ChatMessage {
|
||||
final String id;
|
||||
final String conversationId;
|
||||
final String senderId;
|
||||
final String content;
|
||||
final MessageType messageType;
|
||||
final String? fileUrl;
|
||||
final String? fileName;
|
||||
final int? fileSize;
|
||||
final String? mimeType;
|
||||
final MessageStatus status;
|
||||
final String? deliveredAt;
|
||||
final String? readAt;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
final MessageSender sender;
|
||||
|
||||
const ChatMessage({
|
||||
required this.id,
|
||||
required this.conversationId,
|
||||
required this.senderId,
|
||||
required this.content,
|
||||
this.messageType = MessageType.text,
|
||||
this.fileUrl,
|
||||
this.fileName,
|
||||
this.fileSize,
|
||||
this.mimeType,
|
||||
this.status = MessageStatus.sent,
|
||||
this.deliveredAt,
|
||||
this.readAt,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.sender,
|
||||
});
|
||||
|
||||
bool isMine(String currentUserId) => senderId == currentUserId;
|
||||
|
||||
factory ChatMessage.fromJson(Map<String, dynamic> json) {
|
||||
return ChatMessage(
|
||||
id: json['id'] as String,
|
||||
conversationId: json['conversationId'] as String,
|
||||
senderId: json['senderId'] as String,
|
||||
content: json['content'] as String? ?? '',
|
||||
messageType: MessageType.fromString(json['messageType'] as String?),
|
||||
fileUrl: json['fileUrl'] as String?,
|
||||
fileName: json['fileName'] as String?,
|
||||
fileSize: json['fileSize'] as int?,
|
||||
mimeType: json['mimeType'] as String?,
|
||||
status: MessageStatus.fromString(json['status'] as String?),
|
||||
deliveredAt: json['deliveredAt'] as String?,
|
||||
readAt: json['readAt'] as String?,
|
||||
createdAt: json['createdAt'] as String,
|
||||
updatedAt: json['updatedAt'] as String,
|
||||
sender: json['sender'] != null
|
||||
? MessageSender.fromJson(json['sender'] as Map<String, dynamic>)
|
||||
: MessageSender(id: json['senderId'] as String, role: ''),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PaginationInfo {
|
||||
final int page;
|
||||
final int limit;
|
||||
final int total;
|
||||
final int pages;
|
||||
|
||||
const PaginationInfo({
|
||||
required this.page,
|
||||
required this.limit,
|
||||
required this.total,
|
||||
required this.pages,
|
||||
});
|
||||
|
||||
bool get hasMore => page < pages;
|
||||
|
||||
factory PaginationInfo.fromJson(Map<String, dynamic> json) {
|
||||
return PaginationInfo(
|
||||
page: json['page'] as int? ?? 1,
|
||||
limit: json['limit'] as int? ?? 50,
|
||||
total: json['total'] as int? ?? 0,
|
||||
pages: json['pages'] as int? ?? 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user