import 'package:dio/dio.dart'; import '../domain/project.dart'; import '../domain/project_task.dart'; import 'dart:convert'; import '../domain/project_task_comment.dart'; class ProjectRepository { final Dio _dio; ProjectRepository(this._dio); Future> getProjects() async { try { final response = await _dio.get('/projects'); if (response.data == null) return []; return (response.data as List).map((p) => Project.fromJson(p)).toList(); } on DioException catch (e) { if (e.response?.statusCode == 404) { throw Exception("Projects API endpoint not found. Please ensure the backend server is updated to the latest Docker image."); } throw Exception(e.message ?? 'Unknown error fetching projects'); } } Future createProject({ required String name, String? description, int? customerId, double? budget, }) async { final response = await _dio.post('/projects', data: { 'name': name, if (description != null) 'description': description, if (customerId != null) 'customerId': customerId, if (budget != null) 'budget': budget, }); return Project.fromJson(response.data); } Future updateProject({ required int projectId, String? name, String? description, int? customerId, double? budget, String? status, }) async { final response = await _dio.put('/projects/$projectId', data: { if (name != null) 'name': name, if (description != null) 'description': description, if (customerId != null) 'customerId': customerId, if (budget != null) 'budget': budget, if (status != null) 'status': status, }); return Project.fromJson(response.data); } Future deleteProject(int projectId) async { await _dio.delete('/projects/$projectId'); } Future> getTasks(int projectId) async { final response = await _dio.get('/projects/$projectId/tasks'); return (response.data as List).map((t) => ProjectTask.fromJson(t)).toList(); } Future createTask({ required int projectId, required String title, String? description, String? assigneeName, int? assigneeUserId, bool? isBillable, double? hourlyRate, }) async { final response = await _dio.post('/projects/$projectId/tasks', data: { 'title': title, if (description != null) 'description': description, if (assigneeName != null) 'assigneeName': assigneeName, if (assigneeUserId != null) 'assigneeUserId': assigneeUserId, if (isBillable != null) 'isBillable': isBillable, if (hourlyRate != null) 'hourlyRate': hourlyRate, }); return ProjectTask.fromJson(response.data); } Future updateTask({ required int taskId, String? title, String? description, String? assigneeName, int? assigneeUserId, String? status, bool? isBillable, double? hourlyRate, double? hoursLogged, }) async { final response = await _dio.put('/projects/tasks/$taskId', data: { if (title != null) 'title': title, if (description != null) 'description': description, if (assigneeName != null) 'assigneeName': assigneeName, if (assigneeUserId != null) 'assigneeUserId': assigneeUserId, if (status != null) 'status': status, if (isBillable != null) 'isBillable': isBillable, if (hourlyRate != null) 'hourlyRate': hourlyRate, if (hoursLogged != null) 'hoursLogged': hoursLogged, }); return ProjectTask.fromJson(response.data); } Future deleteTask(int taskId) async { await _dio.delete('/projects/tasks/$taskId'); } Future> getComments(int taskId) async { final response = await _dio.get('/projects/tasks/$taskId/comments'); return (response.data as List).map((c) => ProjectTaskComment.fromJson(c)).toList(); } Future addComment({ required int taskId, required String content, List? imagesBase64, }) async { final response = await _dio.post('/projects/tasks/$taskId/comments', data: { 'content': content, if (imagesBase64 != null && imagesBase64.isNotEmpty) 'imagesJson': jsonEncode(imagesBase64), }); return ProjectTaskComment.fromJson(response.data); } }