refactor: Projektstruktur in app/ und backend/ aufgeteilt

This commit is contained in:
2026-03-24 15:06:44 +01:00
parent 5f5d5995c5
commit 2673ef658d
449 changed files with 28551 additions and 167 deletions

162
app/lib/models/chat.dart Normal file
View File

@@ -0,0 +1,162 @@
import 'chat_message.dart';
enum ChatType { general, jobSpecific }
class Chat {
final String id;
final String title;
final String? receiver;
final ChatType type;
final String? jobId; // only for job-specific chats
final String? jobNumber; // only for job-specific chats
final List<ChatMessage> messages;
final DateTime lastMessageTime;
final String lastMessagePreview;
Chat({
required this.id,
required this.title,
this.receiver,
required this.type,
this.jobId,
this.jobNumber,
required this.messages,
required this.lastMessageTime,
required this.lastMessagePreview,
});
factory Chat.fromJson(Map<String, dynamic> json) {
final messagesList = json['messages'] as List? ?? [];
final messages =
messagesList
.map(
(messageJson) =>
ChatMessage.fromJson(messageJson as Map<String, dynamic>),
)
.toList();
return Chat(
id: json['id']?.toString() ?? '',
title: json['title']?.toString() ?? '',
receiver: json['receiver']?.toString(),
type:
json['type'] == 'jobSpecific'
? ChatType.jobSpecific
: ChatType.general,
jobId: json['jobId']?.toString(),
jobNumber: json['jobNumber']?.toString(),
messages: messages,
lastMessageTime: _resolveLastMessageTime(json, messages),
lastMessagePreview: _resolveLastMessagePreview(json, messages),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'receiver': receiver,
'type': type == ChatType.jobSpecific ? 'jobSpecific' : 'general',
'jobId': jobId,
'jobNumber': jobNumber,
'messages': messages.map((message) => message.toJson()).toList(),
'lastMessageTime': lastMessageTime.toIso8601String(),
'lastMessagePreview': lastMessagePreview,
};
}
// Factory constructor for general chat
factory Chat.general({
required String id,
required String title,
String? receiver,
required List<ChatMessage> messages,
}) {
final lastMessage = messages.isNotEmpty ? messages.last : null;
return Chat(
id: id,
title: title,
receiver: receiver,
type: ChatType.general,
messages: messages,
lastMessageTime: lastMessage?.createdAt ?? DateTime.now(),
lastMessagePreview:
lastMessage != null
? _previewForMessage(lastMessage)
: 'Noch keine Nachrichten',
);
}
// Factory constructor for job-specific chat
factory Chat.jobSpecific({
required String id,
required String jobId,
required String jobNumber,
String? receiver,
required List<ChatMessage> messages,
}) {
final lastMessage = messages.isNotEmpty ? messages.last : null;
return Chat(
id: id,
title: 'Job $jobNumber',
receiver: receiver,
type: ChatType.jobSpecific,
jobId: jobId,
jobNumber: jobNumber,
messages: messages,
lastMessageTime: lastMessage?.createdAt ?? DateTime.now(),
lastMessagePreview:
lastMessage != null
? _previewForMessage(lastMessage)
: 'Noch keine Nachrichten',
);
}
static DateTime _resolveLastMessageTime(
Map<String, dynamic> json,
List<ChatMessage> messages,
) {
if (messages.isNotEmpty) {
return messages.last.createdAt;
}
final raw = json['lastMessageTime']?.toString();
if (raw != null) {
final parsed = DateTime.tryParse(raw);
if (parsed != null) {
return parsed;
}
}
return DateTime.now();
}
static String _resolveLastMessagePreview(
Map<String, dynamic> json,
List<ChatMessage> messages,
) {
if (messages.isNotEmpty) {
return _previewForMessage(messages.last);
}
return json['lastMessagePreview']?.toString() ?? 'Noch keine Nachrichten';
}
static String _previewForMessage(ChatMessage message) {
if (message.contentType == ChatContentType.image) {
return '[Bild]';
}
return message.content;
}
@override
String toString() {
return 'Chat(id: $id, title: $title, type: $type, jobId: $jobId, messagesCount: ${messages.length})';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Chat && other.id == id;
}
@override
int get hashCode => id.hashCode;
}