feat(student-profile): implement Priority 1 operational hub with tabs, inline document workflows, and audit history
This commit is contained in:
1 parent
0e99b73989
commit
489e87834e
6 files changed
+1613
-276
No files matched your search
@@ -4,6 +4,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:socket_io_client/socket_io_client.dart' as IO;
|
||||
import '../../core/network/api_constants.dart';
|
||||
import '../entities/student_model.dart';
|
||||
import '../entities/dashboard_models.dart' show RecentActivity;
|
||||
|
||||
/// Paginated student list returned from the API.
|
||||
class StudentPage {
|
||||
@@ -581,4 +582,25 @@ class StudentRepository {
|
||||
throw Exception(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Fetch Student Audit / Activity Log
|
||||
// ----------------------------------------------------------------
|
||||
Future<List<RecentActivity>> getStudentActivities(int studentId) async {
|
||||
try {
|
||||
final options = await _getAuthOptions();
|
||||
final response = await _dio.get(
|
||||
'/students/$studentId/activities',
|
||||
options: options,
|
||||
);
|
||||
final list = (response.data['activities'] as List?) ?? [];
|
||||
return list
|
||||
.map((a) => RecentActivity.fromJson(a as Map<String, dynamic>))
|
||||
.toList();
|
||||
} on DioException catch (e) {
|
||||
final msg =
|
||||
e.response?.data?['message'] ?? 'Failed to fetch student activities.';
|
||||
throw Exception(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../domain/repositories/document_repository.dart';
|
||||
import '../../domain/entities/document_requirement_model.dart';
|
||||
import '../../domain/entities/folder_model.dart';
|
||||
import '../../domain/entities/document_model.dart';
|
||||
import 'student_provider.dart';
|
||||
|
||||
final documentRepositoryProvider = Provider<DocumentRepository>((ref) {
|
||||
@@ -146,7 +147,7 @@ final documentPageProvider = FutureProvider.autoDispose<DocumentPage>((
|
||||
// Student-specific documents provider
|
||||
// ============================================================
|
||||
final studentDocumentsProvider = FutureProvider.family
|
||||
.autoDispose<List<dynamic>, int>((ref, studentId) async {
|
||||
.autoDispose<List<DocumentModel>, int>((ref, studentId) async {
|
||||
final repo = ref.read(documentRepositoryProvider);
|
||||
return repo.getDocumentsByStudent(studentId);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import '../../core/network/api_constants.dart';
|
||||
import '../../domain/repositories/student_repository.dart';
|
||||
import '../../domain/entities/student_model.dart';
|
||||
import '../../domain/entities/dashboard_models.dart' show RecentActivity;
|
||||
|
||||
// ============================================================
|
||||
// Academic Years Model
|
||||
@@ -68,6 +69,15 @@ final studentDetailProvider = FutureProvider.family
|
||||
return repo.getStudentById(studentId);
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// Student Activities / Audit Trail Provider
|
||||
// ============================================================
|
||||
final studentActivitiesProvider = FutureProvider.family
|
||||
.autoDispose<List<RecentActivity>, int>((ref, studentId) async {
|
||||
final repo = ref.read(studentRepositoryProvider);
|
||||
return repo.getStudentActivities(studentId);
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// Query params state — drives what the list shows
|
||||
// ============================================================
|
||||
|
||||
@@ -86,7 +86,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
|
||||
elevation: 1,
|
||||
titleSpacing: 0,
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
||||
tooltip: 'Back to Application',
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
@@ -130,12 +130,12 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.open_in_browser_rounded, size: 20),
|
||||
icon: const Icon(Icons.open_in_browser_rounded, size: 20, color: Colors.white),
|
||||
tooltip: 'Open in External Browser',
|
||||
onPressed: _openInBrowser,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
icon: const Icon(Icons.close, size: 20, color: Colors.white),
|
||||
tooltip: 'Close Documentation',
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user