Implement verified curriculum, video review, watch sessions, ledger safeguards, and remove demo data
This commit is contained in:
@@ -188,9 +188,9 @@ class TeacherProfileModel {
|
||||
required this.schoolName,
|
||||
required this.gradesTaught,
|
||||
required this.bio,
|
||||
this.rating = 4.9,
|
||||
this.studentsCount = 42,
|
||||
this.lessonsCount = 28,
|
||||
this.rating = 0,
|
||||
this.studentsCount = 0,
|
||||
this.lessonsCount = 0,
|
||||
});
|
||||
|
||||
factory TeacherProfileModel.fromJson(Map<String, dynamic> json) {
|
||||
|
||||
@@ -28,6 +28,8 @@ class TeacherMonetizationState {
|
||||
final List<TeacherPayoutRequestModel> payoutRequests;
|
||||
final bool isSubmittingPayout;
|
||||
final bool isLoading;
|
||||
final bool financialUnavailable;
|
||||
final String financialMessage;
|
||||
|
||||
const TeacherMonetizationState({
|
||||
required this.institutionalStudents,
|
||||
@@ -44,6 +46,8 @@ class TeacherMonetizationState {
|
||||
required this.payoutRequests,
|
||||
required this.isSubmittingPayout,
|
||||
this.isLoading = false,
|
||||
this.financialUnavailable = false,
|
||||
this.financialMessage = '',
|
||||
});
|
||||
|
||||
TeacherMonetizationState copyWith({
|
||||
@@ -61,6 +65,8 @@ class TeacherMonetizationState {
|
||||
List<TeacherPayoutRequestModel>? payoutRequests,
|
||||
bool? isSubmittingPayout,
|
||||
bool? isLoading,
|
||||
bool? financialUnavailable,
|
||||
String? financialMessage,
|
||||
}) {
|
||||
return TeacherMonetizationState(
|
||||
institutionalStudents:
|
||||
@@ -78,6 +84,8 @@ class TeacherMonetizationState {
|
||||
payoutRequests: payoutRequests ?? this.payoutRequests,
|
||||
isSubmittingPayout: isSubmittingPayout ?? this.isSubmittingPayout,
|
||||
isLoading: isLoading ?? this.isLoading,
|
||||
financialUnavailable: financialUnavailable ?? this.financialUnavailable,
|
||||
financialMessage: financialMessage ?? this.financialMessage,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -116,16 +124,21 @@ class TeacherMonetizationCubit extends Cubit<TeacherMonetizationState> {
|
||||
final mkt =
|
||||
audience['marketplace_students'] as Map<String, dynamic>? ?? {};
|
||||
final wallet = data['wallet'] as Map<String, dynamic>? ?? {};
|
||||
final unavailable = data['financial_status'] == 'unavailable';
|
||||
|
||||
final instCount = (inst['count'] as num?)?.toDouble() ?? 0.0;
|
||||
final paidCount = (mkt['count'] as num?)?.toDouble() ?? 0.0;
|
||||
final gross =
|
||||
(data['gross_revenue_jod'] as num?)?.toDouble() ?? (paidCount * 20.0);
|
||||
final tShare = gross * 0.55;
|
||||
final dShare = gross * 0.15;
|
||||
final pShare = gross * 0.30;
|
||||
final split = data['revenue_split'] as Map<String, dynamic>? ?? {};
|
||||
// Never infer a wallet from subscriber counts, course prices, or old
|
||||
// percentages. The backend returns null until a provider-backed ledger
|
||||
// and eligible watch-minute policy are live.
|
||||
final gross = (data['gross_revenue_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final tShare = (split['teacher_amount_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final dShare =
|
||||
(split['directorate_amount_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final pShare = (split['platform_amount_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final avail =
|
||||
(wallet['available_balance_jod'] as num?)?.toDouble() ?? tShare;
|
||||
(wallet['available_balance_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final withdrawn =
|
||||
(wallet['total_withdrawn_jod'] as num?)?.toDouble() ?? 0.0;
|
||||
final alias = wallet['cliq_payout_alias']?.toString() ?? '';
|
||||
@@ -154,6 +167,8 @@ class TeacherMonetizationCubit extends Cubit<TeacherMonetizationState> {
|
||||
cliqAlias: alias,
|
||||
courses: courses,
|
||||
payoutRequests: payouts,
|
||||
financialUnavailable: unavailable,
|
||||
financialMessage: data['financial_message']?.toString() ?? '',
|
||||
isLoading: false,
|
||||
));
|
||||
} catch (_) {
|
||||
@@ -162,15 +177,8 @@ class TeacherMonetizationCubit extends Cubit<TeacherMonetizationState> {
|
||||
}
|
||||
|
||||
void updateSubscribers(double subscribers) {
|
||||
final gross = subscribers * state.pricePerCourse;
|
||||
emit(state.copyWith(
|
||||
studentSubscribers: subscribers,
|
||||
grossRevenue: gross,
|
||||
teacherShare: gross * 0.55,
|
||||
directorateShare: gross * 0.15,
|
||||
platformShare: gross * 0.30,
|
||||
availableBalance: gross * 0.55,
|
||||
));
|
||||
// Presentation must not fabricate revenue from a manually changed count.
|
||||
emit(state.copyWith(studentSubscribers: subscribers));
|
||||
}
|
||||
|
||||
Future<void> submitCliqPayout({
|
||||
@@ -186,14 +194,8 @@ class TeacherMonetizationCubit extends Cubit<TeacherMonetizationState> {
|
||||
final updatedList =
|
||||
List<TeacherPayoutRequestModel>.from(state.payoutRequests)
|
||||
..insert(0, req);
|
||||
final newAvail =
|
||||
(state.availableBalance - amountJod).clamp(0.0, double.infinity);
|
||||
final newWithdrawn = state.totalWithdrawn + amountJod;
|
||||
|
||||
emit(state.copyWith(
|
||||
payoutRequests: updatedList,
|
||||
availableBalance: newAvail,
|
||||
totalWithdrawn: newWithdrawn,
|
||||
isSubmittingPayout: false,
|
||||
));
|
||||
} catch (_) {
|
||||
|
||||
@@ -286,6 +286,40 @@ class _TeacherMonetizationTabState extends State<TeacherMonetizationTab> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<TeacherMonetizationCubit, TeacherMonetizationState>(
|
||||
builder: (context, state) {
|
||||
if (state.financialUnavailable) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: TeacherTheme.surfaceCard,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
border: Border.all(color: TeacherTheme.surfaceBorder),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(CupertinoIcons.lock_circle_fill,
|
||||
color: TeacherTheme.royalGold, size: 34),
|
||||
const SizedBox(height: 12),
|
||||
const Text('الأرباح والسحب غير متاحين حالياً',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w800)),
|
||||
const SizedBox(height: 8),
|
||||
Text(state.financialMessage,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF94A3B8), fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
|
||||
Reference in New Issue
Block a user