Update Saqel Platform: 2026-09-08 18:19:28
This commit is contained in:
@@ -38,18 +38,28 @@ class TeacherLessonAuditModel {
|
||||
});
|
||||
|
||||
factory TeacherLessonAuditModel.fromJson(Map<String, dynamic> json) {
|
||||
final durationSeconds = (json['duration_seconds'] as num?)?.toDouble() ?? 0;
|
||||
final readiness = (json['pedagogical_readiness_score'] as num?)?.toInt();
|
||||
final visual = (json['visual_clarity_score'] as num?)?.toInt();
|
||||
final decisionValue = json['decision']?.toString() ?? 'pending';
|
||||
return TeacherLessonAuditModel(
|
||||
lessonTitle: json['lesson_title'] ?? '',
|
||||
subject: json['subject'] ?? 'الفيزياء',
|
||||
durationMinutes: (json['duration_minutes'] as num?)?.toDouble() ?? 22.5,
|
||||
durationGatePassed: json['duration_gate_passed'] ?? true,
|
||||
subject: json['subject'] ?? '',
|
||||
durationMinutes: (json['duration_minutes'] as num?)?.toDouble() ??
|
||||
durationSeconds / 60,
|
||||
durationGatePassed: json['duration_gate_passed'] ??
|
||||
(durationSeconds > 0 && durationSeconds <= 1500),
|
||||
durationWarning: json['duration_warning'],
|
||||
qualityScore: json['quality_score'] ?? 92,
|
||||
approvalStatus: json['approval_status'] ?? 'approved_for_broadcast',
|
||||
curriculumAlignment: json['curriculum_alignment'] ?? '96% تطابق مع مخرجات المنهاج الوزاري',
|
||||
audioClarity: json['audio_clarity'] ?? '95% نقاء صوتي ممتاز',
|
||||
socraticStopsCount: json['socratic_stops_count'] ?? 3,
|
||||
decision: json['decision'] ?? 'الحصة معتمدة ومؤهلة للبث المشفر والعرض للبيع خارج الثقافة العسكرية 🚀',
|
||||
qualityScore: (json['quality_score'] as num?)?.toInt() ?? readiness ?? 0,
|
||||
approvalStatus: json['approval_status'] ?? decisionValue,
|
||||
curriculumAlignment:
|
||||
json['curriculum_alignment'] ?? 'بانتظار تحليل الملف الفعلي',
|
||||
audioClarity: json['audio_clarity'] ??
|
||||
(visual == null
|
||||
? 'تم التحقق من وجود مسار صوت فعلي'
|
||||
: 'وضوح الصورة $visual%، وتم التحقق من وجود الصوت'),
|
||||
socraticStopsCount: (json['socratic_stops_count'] as num?)?.toInt() ?? 0,
|
||||
decision: json['report'] ?? json['reason'] ?? decisionValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -176,10 +186,11 @@ class TeacherProfileModel {
|
||||
factory TeacherProfileModel.fromJson(Map<String, dynamic> json) {
|
||||
final user = json['user'] as Map<String, dynamic>? ?? {};
|
||||
final profile = json['profile'] as Map<String, dynamic>? ?? {};
|
||||
|
||||
|
||||
List<String> grades = [];
|
||||
if (profile['grades_taught'] is List) {
|
||||
grades = (profile['grades_taught'] as List).map((e) => e.toString()).toList();
|
||||
grades =
|
||||
(profile['grades_taught'] as List).map((e) => e.toString()).toList();
|
||||
} else if (profile['grades_taught'] is String) {
|
||||
grades = [profile['grades_taught'].toString()];
|
||||
}
|
||||
@@ -191,7 +202,8 @@ class TeacherProfileModel {
|
||||
id: user['id'] is int ? user['id'] : 1,
|
||||
uuid: user['uuid']?.toString() ?? '',
|
||||
name: user['full_name']?.toString() ?? 'حساب معلم غير مكتمل',
|
||||
specialization: profile['specialization']?.toString() ?? 'بانتظار استكمال التخصص',
|
||||
specialization:
|
||||
profile['specialization']?.toString() ?? 'بانتظار استكمال التخصص',
|
||||
schoolName: profile['school_name']?.toString() ?? '',
|
||||
gradesTaught: grades,
|
||||
bio: profile['bio']?.toString() ?? '',
|
||||
@@ -248,7 +260,9 @@ class ChatConversationModel {
|
||||
|
||||
factory ChatConversationModel.fromJson(Map<String, dynamic> json) {
|
||||
return ChatConversationModel(
|
||||
userId: json['user_id'] is int ? json['user_id'] : int.tryParse(json['user_id']?.toString() ?? '0') ?? 0,
|
||||
userId: json['user_id'] is int
|
||||
? json['user_id']
|
||||
: int.tryParse(json['user_id']?.toString() ?? '0') ?? 0,
|
||||
userUuid: json['user_uuid']?.toString() ?? '',
|
||||
fullName: json['full_name']?.toString() ?? 'طالب صَقِل',
|
||||
role: json['role']?.toString() ?? 'student',
|
||||
@@ -288,11 +302,17 @@ class ChatMessageModel {
|
||||
|
||||
factory ChatMessageModel.fromJson(Map<String, dynamic> json) {
|
||||
return ChatMessageModel(
|
||||
id: json['id'] is int ? json['id'] : int.tryParse(json['id']?.toString() ?? '0') ?? 0,
|
||||
id: json['id'] is int
|
||||
? json['id']
|
||||
: int.tryParse(json['id']?.toString() ?? '0') ?? 0,
|
||||
uuid: json['uuid']?.toString() ?? '',
|
||||
isMine: json['is_mine'] ?? false,
|
||||
senderId: json['sender_id'] is int ? json['sender_id'] : int.tryParse(json['sender_id']?.toString() ?? '0') ?? 0,
|
||||
receiverId: json['receiver_id'] is int ? json['receiver_id'] : int.tryParse(json['receiver_id']?.toString() ?? '0') ?? 0,
|
||||
senderId: json['sender_id'] is int
|
||||
? json['sender_id']
|
||||
: int.tryParse(json['sender_id']?.toString() ?? '0') ?? 0,
|
||||
receiverId: json['receiver_id'] is int
|
||||
? json['receiver_id']
|
||||
: int.tryParse(json['receiver_id']?.toString() ?? '0') ?? 0,
|
||||
message: json['message']?.toString() ?? '',
|
||||
messageType: json['message_type']?.toString() ?? 'text',
|
||||
mediaUrl: json['media_url']?.toString(),
|
||||
|
||||
@@ -47,16 +47,22 @@ class TeacherRepository {
|
||||
// ============================================================================
|
||||
|
||||
Future<Map<String, dynamic>> requestOtp(String phoneNumber) async {
|
||||
AppLogger.log('Requesting Teacher OTP for $phoneNumber...', tag: 'TEACHER_REPO');
|
||||
AppLogger.log('Requesting Teacher OTP for $phoneNumber...',
|
||||
tag: 'TEACHER_REPO');
|
||||
try {
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.otpRequestEndpoint}'),
|
||||
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode({
|
||||
'phone_number': phoneNumber,
|
||||
'role': 'teacher',
|
||||
}),
|
||||
).timeout(const Duration(seconds: 30));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.otpRequestEndpoint}'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: json.encode({
|
||||
'phone_number': phoneNumber,
|
||||
'role': 'teacher',
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 30));
|
||||
|
||||
return json.decode(response.body);
|
||||
} catch (e) {
|
||||
@@ -65,20 +71,27 @@ class TeacherRepository {
|
||||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> verifyOtp(String phoneNumber, String otp, {String? fullName}) async {
|
||||
AppLogger.log('Verifying Teacher OTP for $phoneNumber...', tag: 'TEACHER_REPO');
|
||||
Future<Map<String, dynamic>> verifyOtp(String phoneNumber, String otp,
|
||||
{String? fullName}) async {
|
||||
AppLogger.log('Verifying Teacher OTP for $phoneNumber...',
|
||||
tag: 'TEACHER_REPO');
|
||||
try {
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.otpVerifyEndpoint}'),
|
||||
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
|
||||
body: json.encode({
|
||||
'phone_number': phoneNumber,
|
||||
'otp': otp,
|
||||
'role': 'teacher',
|
||||
if (fullName != null) 'full_name': fullName,
|
||||
'device_fingerprint': 'saqel_teacher_flutter',
|
||||
}),
|
||||
).timeout(const Duration(seconds: 30));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.otpVerifyEndpoint}'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: json.encode({
|
||||
'phone_number': phoneNumber,
|
||||
'otp': otp,
|
||||
'role': 'teacher',
|
||||
if (fullName != null) 'full_name': fullName,
|
||||
'device_fingerprint': 'saqel_teacher_flutter',
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 30));
|
||||
|
||||
final decoded = json.decode(response.body);
|
||||
if (decoded['status'] == 'success' && decoded['data']?['token'] != null) {
|
||||
@@ -95,10 +108,12 @@ class TeacherRepository {
|
||||
Future<Map<String, dynamic>?> getMe() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.meEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.meEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
return json.decode(response.body);
|
||||
@@ -114,10 +129,12 @@ class TeacherRepository {
|
||||
Future<TeacherProfileModel> getProfileStatus() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.profileStatusEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.profileStatusEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -141,17 +158,19 @@ class TeacherRepository {
|
||||
}) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.profileSetupEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'full_name': fullName,
|
||||
'specialization': specialization,
|
||||
'school_name': schoolName,
|
||||
'grades_taught': gradesTaught,
|
||||
'bio': bio,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 5));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.profileSetupEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'full_name': fullName,
|
||||
'specialization': specialization,
|
||||
'school_name': schoolName,
|
||||
'grades_taught': gradesTaught,
|
||||
'bio': bio,
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -181,10 +200,12 @@ class TeacherRepository {
|
||||
Future<List<ChatConversationModel>> getConversations() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.chatConversationsEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.chatConversationsEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -192,7 +213,7 @@ class TeacherRepository {
|
||||
final list = (decoded['data'] as List)
|
||||
.map((c) => ChatConversationModel.fromJson(c))
|
||||
.toList();
|
||||
if (list.isNotEmpty) return list;
|
||||
return list;
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
@@ -203,14 +224,18 @@ class TeacherRepository {
|
||||
Future<List<ChatMessageModel>> getMessages(int otherUserId) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.chatMessagesEndpoint}?other_user_id=$otherUserId'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse(
|
||||
'$baseUrl${AppConfig.chatMessagesEndpoint}?other_user_id=$otherUserId'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
if (decoded['status'] == 'success' && decoded['data']?['messages'] is List) {
|
||||
if (decoded['status'] == 'success' &&
|
||||
decoded['data']?['messages'] is List) {
|
||||
return (decoded['data']['messages'] as List)
|
||||
.map((m) => ChatMessageModel.fromJson(m))
|
||||
.toList();
|
||||
@@ -229,16 +254,18 @@ class TeacherRepository {
|
||||
}) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.chatMessagesEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'receiver_id': receiverId,
|
||||
'message': message,
|
||||
'message_type': messageType,
|
||||
if (mediaUrl != null) 'media_url': mediaUrl,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 5));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.chatMessagesEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'receiver_id': receiverId,
|
||||
'message': message,
|
||||
'message_type': messageType,
|
||||
if (mediaUrl != null) 'media_url': mediaUrl,
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -265,25 +292,28 @@ class TeacherRepository {
|
||||
}) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.broadcastEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'title': title,
|
||||
'message': message,
|
||||
'message_type': messageType,
|
||||
if (mediaUrl != null) 'media_url': mediaUrl,
|
||||
'grade_level': gradeLevel,
|
||||
'course_id': courseId,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 5));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.broadcastEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'title': title,
|
||||
'message': message,
|
||||
'message_type': messageType,
|
||||
if (mediaUrl != null) 'media_url': mediaUrl,
|
||||
'grade_level': gradeLevel,
|
||||
'course_id': courseId,
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
return decoded['status'] == 'success';
|
||||
}
|
||||
} catch (e) {
|
||||
AppLogger.error('broadcastAnnouncement notice', error: e, tag: 'TEACHER_REPO');
|
||||
AppLogger.error('broadcastAnnouncement notice',
|
||||
error: e, tag: 'TEACHER_REPO');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -299,15 +329,17 @@ class TeacherRepository {
|
||||
}) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.auditVideoEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'lesson_title': title,
|
||||
'duration_minutes': durationMinutes,
|
||||
'subject': subject,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.auditVideoEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'lesson_title': title,
|
||||
'duration_minutes': durationMinutes,
|
||||
'subject': subject,
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -325,6 +357,7 @@ class TeacherRepository {
|
||||
required double durationMinutes,
|
||||
required String gradeLevel,
|
||||
required String subject,
|
||||
required String curriculumKey,
|
||||
String? fileName,
|
||||
double? fileSizeMb,
|
||||
String? filePath,
|
||||
@@ -343,6 +376,7 @@ class TeacherRepository {
|
||||
'duration_minutes': durationMinutes.toString(),
|
||||
'grade_level': gradeLevel,
|
||||
'subject': subject,
|
||||
'curriculum_key': curriculumKey,
|
||||
});
|
||||
|
||||
final resolvedName = fileName ?? 'lesson.mp4';
|
||||
@@ -362,24 +396,49 @@ class TeacherRepository {
|
||||
throw StateError('لم يتم اختيار ملف فيديو صالح للرفع.');
|
||||
}
|
||||
|
||||
final streamed = await _client.send(request).timeout(const Duration(minutes: 10));
|
||||
final streamed =
|
||||
await _client.send(request).timeout(const Duration(minutes: 10));
|
||||
final response = await http.Response.fromStream(streamed);
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
return json.decode(response.body);
|
||||
}
|
||||
} catch (_) {}
|
||||
final decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||
if (response.statusCode == 200 || response.statusCode == 201)
|
||||
return decoded;
|
||||
throw StateError(
|
||||
decoded['message']?.toString() ?? 'رفض الخادم رفع الحصة.');
|
||||
} on StateError {
|
||||
rethrow;
|
||||
} catch (error) {
|
||||
throw StateError('تعذر رفع الحصة: $error');
|
||||
}
|
||||
}
|
||||
|
||||
throw StateError('لم يتم رفع الحصة أو نشرها على الخادم.');
|
||||
Future<Map<String, dynamic>> getCurriculumTree() async {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.curriculumTreeEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 30));
|
||||
final decoded = json.decode(response.body) as Map<String, dynamic>;
|
||||
if (response.statusCode == 200 &&
|
||||
decoded['status'] == 'success' &&
|
||||
decoded['data'] is Map) {
|
||||
return Map<String, dynamic>.from(decoded['data'] as Map);
|
||||
}
|
||||
throw StateError(
|
||||
decoded['message']?.toString() ?? 'تعذر تحميل شجرة المنهاج.');
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> getMonetizationDashboard() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.monetizationEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.monetizationEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -398,21 +457,24 @@ class TeacherRepository {
|
||||
}) async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.post(
|
||||
Uri.parse('$baseUrl${AppConfig.cliqPayoutEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'cliq_alias': cliqAlias,
|
||||
'amount_jod': amountJod,
|
||||
}),
|
||||
).timeout(const Duration(seconds: 5));
|
||||
final response = await _client
|
||||
.post(
|
||||
Uri.parse('$baseUrl${AppConfig.cliqPayoutEndpoint}'),
|
||||
headers: headers,
|
||||
body: json.encode({
|
||||
'cliq_alias': cliqAlias,
|
||||
'amount_jod': amountJod,
|
||||
}),
|
||||
)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
final decoded = json.decode(response.body);
|
||||
return TeacherPayoutRequestModel(
|
||||
cliqAlias: cliqAlias,
|
||||
amountJod: amountJod,
|
||||
requestedAt: 'اليوم، ${DateTime.now().hour}:${DateTime.now().minute.toString().padLeft(2, '0')}',
|
||||
requestedAt:
|
||||
'اليوم، ${DateTime.now().hour}:${DateTime.now().minute.toString().padLeft(2, '0')}',
|
||||
status: decoded['queue_status'] ?? decoded['status'] ?? 'queued',
|
||||
);
|
||||
}
|
||||
@@ -424,22 +486,25 @@ class TeacherRepository {
|
||||
Future<List<TeacherHomeworkModel>> getHomeworks() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.qnaEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.qnaEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
if (decoded['status'] == 'success' && decoded['data']?['homeworks'] is List) {
|
||||
if (decoded['status'] == 'success' &&
|
||||
decoded['data']?['homeworks'] is List) {
|
||||
return (decoded['data']['homeworks'] as List)
|
||||
.map((h) => TeacherHomeworkModel(
|
||||
id: h['id'].toString(),
|
||||
title: h['title']?.toString() ?? '',
|
||||
className: h['class_name']?.toString() ?? '',
|
||||
submitted: h['submitted']?.toString() ?? '0 من 38',
|
||||
submitted: h['submitted']?.toString() ?? '',
|
||||
dueDate: h['due_date']?.toString() ?? '',
|
||||
averageScore: h['average_score']?.toString() ?? '90%',
|
||||
averageScore: h['average_score']?.toString() ?? '',
|
||||
status: h['status']?.toString() ?? 'active',
|
||||
))
|
||||
.toList();
|
||||
@@ -453,14 +518,17 @@ class TeacherRepository {
|
||||
Future<List<StudentDoubtModel>> getStudentDoubts() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.qnaEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.qnaEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
if (decoded['status'] == 'success' && decoded['data']?['doubts'] is List) {
|
||||
if (decoded['status'] == 'success' &&
|
||||
decoded['data']?['doubts'] is List) {
|
||||
return (decoded['data']['doubts'] as List)
|
||||
.map((d) => StudentDoubtModel(
|
||||
id: d['id'].toString(),
|
||||
@@ -483,10 +551,12 @@ class TeacherRepository {
|
||||
Future<List<TeacherCourseModel>> getPublishedCourses() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.coursesEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.coursesEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
@@ -494,13 +564,15 @@ class TeacherRepository {
|
||||
return (decoded['data'] as List).map((c) {
|
||||
return TeacherCourseModel(
|
||||
id: c['id'].toString(),
|
||||
title: c['title'] ?? 'الفيزياء — الصف العاشر',
|
||||
grade: 'الصف العاشر الأساسي',
|
||||
totalLessons: int.tryParse(c['lessons_total']?.toString() ?? '0') ?? 0,
|
||||
militaryStudents: 83,
|
||||
externalSubscribers: 0,
|
||||
priceJod: double.tryParse(c['price_jod']?.toString() ?? '20.0') ?? 20.0,
|
||||
netRevenueJod: 0.0,
|
||||
title: c['title']?.toString() ?? '',
|
||||
grade: c['grade_level']?.toString() ?? '',
|
||||
totalLessons:
|
||||
int.tryParse(c['lessons_total']?.toString() ?? '0') ?? 0,
|
||||
militaryStudents: (c['military_students'] as num?)?.toInt() ?? 0,
|
||||
externalSubscribers: (c['external_subscribers'] as num?)?.toInt() ?? 0,
|
||||
priceJod:
|
||||
double.tryParse(c['price_jod']?.toString() ?? '') ?? 0,
|
||||
netRevenueJod: double.tryParse(c['net_revenue_jod']?.toString() ?? '') ?? 0,
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
@@ -517,10 +589,12 @@ class TeacherRepository {
|
||||
Future<Map<String, dynamic>> getMyReputation() async {
|
||||
try {
|
||||
final headers = await _authHeaders();
|
||||
final response = await _client.get(
|
||||
Uri.parse('$baseUrl${AppConfig.reputationEndpoint}'),
|
||||
headers: headers,
|
||||
).timeout(const Duration(seconds: 4));
|
||||
final response = await _client
|
||||
.get(
|
||||
Uri.parse('$baseUrl${AppConfig.reputationEndpoint}'),
|
||||
headers: headers,
|
||||
)
|
||||
.timeout(const Duration(seconds: 4));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = json.decode(response.body);
|
||||
|
||||
Reference in New Issue
Block a user