194 lines
7.0 KiB
Dart
194 lines
7.0 KiB
Dart
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import '../../data/models/teacher_models.dart';
|
|
import '../../data/repositories/teacher_repository.dart';
|
|
|
|
/**
|
|
* ==============================================================================
|
|
* SAQEL TEACHER STUDIO - MONETIZATION CUBIT
|
|
* ==============================================================================
|
|
*
|
|
* إدارة المحفظة المالية والتسييل وسحوبات كليك (CliQ Payouts):
|
|
* - حساب عوائد النموذج المزدوج (1,420 مجاني مدعوم مقابل 380 مدفوع خارجي)
|
|
* - تقسيم الحصص: 55% للمعلم / 15% لمديرية الثقافة / 30% للمنصة
|
|
* - إرسال واعتماد طلبات السحب عبر كليك.
|
|
*/
|
|
|
|
class TeacherMonetizationState {
|
|
final double institutionalStudents;
|
|
final double studentSubscribers;
|
|
final double pricePerCourse;
|
|
final double grossRevenue;
|
|
final double teacherShare;
|
|
final double directorateShare;
|
|
final double platformShare;
|
|
final double availableBalance;
|
|
final double totalWithdrawn;
|
|
final String cliqAlias;
|
|
final List<TeacherCourseModel> courses;
|
|
final List<TeacherPayoutRequestModel> payoutRequests;
|
|
final bool isSubmittingPayout;
|
|
final bool isLoading;
|
|
|
|
const TeacherMonetizationState({
|
|
required this.institutionalStudents,
|
|
required this.studentSubscribers,
|
|
required this.pricePerCourse,
|
|
required this.grossRevenue,
|
|
required this.teacherShare,
|
|
required this.directorateShare,
|
|
required this.platformShare,
|
|
required this.availableBalance,
|
|
required this.totalWithdrawn,
|
|
required this.cliqAlias,
|
|
required this.courses,
|
|
required this.payoutRequests,
|
|
required this.isSubmittingPayout,
|
|
this.isLoading = false,
|
|
});
|
|
|
|
TeacherMonetizationState copyWith({
|
|
double? institutionalStudents,
|
|
double? studentSubscribers,
|
|
double? pricePerCourse,
|
|
double? grossRevenue,
|
|
double? teacherShare,
|
|
double? directorateShare,
|
|
double? platformShare,
|
|
double? availableBalance,
|
|
double? totalWithdrawn,
|
|
String? cliqAlias,
|
|
List<TeacherCourseModel>? courses,
|
|
List<TeacherPayoutRequestModel>? payoutRequests,
|
|
bool? isSubmittingPayout,
|
|
bool? isLoading,
|
|
}) {
|
|
return TeacherMonetizationState(
|
|
institutionalStudents: institutionalStudents ?? this.institutionalStudents,
|
|
studentSubscribers: studentSubscribers ?? this.studentSubscribers,
|
|
pricePerCourse: pricePerCourse ?? this.pricePerCourse,
|
|
grossRevenue: grossRevenue ?? this.grossRevenue,
|
|
teacherShare: teacherShare ?? this.teacherShare,
|
|
directorateShare: directorateShare ?? this.directorateShare,
|
|
platformShare: platformShare ?? this.platformShare,
|
|
availableBalance: availableBalance ?? this.availableBalance,
|
|
totalWithdrawn: totalWithdrawn ?? this.totalWithdrawn,
|
|
cliqAlias: cliqAlias ?? this.cliqAlias,
|
|
courses: courses ?? this.courses,
|
|
payoutRequests: payoutRequests ?? this.payoutRequests,
|
|
isSubmittingPayout: isSubmittingPayout ?? this.isSubmittingPayout,
|
|
isLoading: isLoading ?? this.isLoading,
|
|
);
|
|
}
|
|
}
|
|
|
|
class TeacherMonetizationCubit extends Cubit<TeacherMonetizationState> {
|
|
final TeacherRepository repository;
|
|
|
|
TeacherMonetizationCubit({required this.repository})
|
|
: super(const TeacherMonetizationState(
|
|
institutionalStudents: 83,
|
|
studentSubscribers: 0,
|
|
pricePerCourse: 20.0,
|
|
grossRevenue: 0.0,
|
|
teacherShare: 0.0,
|
|
directorateShare: 0.0,
|
|
platformShare: 0.0,
|
|
availableBalance: 0.0,
|
|
totalWithdrawn: 0.0,
|
|
cliqAlias: '0798583052@CLIQ',
|
|
courses: [],
|
|
payoutRequests: [],
|
|
isSubmittingPayout: false,
|
|
isLoading: false,
|
|
));
|
|
|
|
Future<void> loadMonetization() async {
|
|
emit(state.copyWith(isLoading: true));
|
|
try {
|
|
final data = await repository.getMonetizationDashboard();
|
|
final courses = await repository.getPublishedCourses();
|
|
|
|
final audience = data['audience_breakdown'] as Map<String, dynamic>? ?? {};
|
|
final inst = audience['institutional_students'] as Map<String, dynamic>? ?? {};
|
|
final mkt = audience['marketplace_students'] as Map<String, dynamic>? ?? {};
|
|
final wallet = data['wallet'] as Map<String, dynamic>? ?? {};
|
|
|
|
final instCount = (inst['count'] as num?)?.toDouble() ?? 83.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 avail = (wallet['available_balance_jod'] as num?)?.toDouble() ?? tShare;
|
|
final withdrawn = (wallet['total_withdrawn_jod'] as num?)?.toDouble() ?? 0.0;
|
|
final alias = wallet['cliq_payout_alias']?.toString() ?? '0798583052@CLIQ';
|
|
|
|
List<TeacherPayoutRequestModel> payouts = [];
|
|
if (wallet['recent_payouts'] is List) {
|
|
payouts = (wallet['recent_payouts'] as List).map((p) {
|
|
return TeacherPayoutRequestModel(
|
|
cliqAlias: p['teacher_cliq_alias']?.toString() ?? alias,
|
|
amountJod: (p['amount_jod'] as num?)?.toDouble() ?? 0.0,
|
|
requestedAt: p['created_at']?.toString() ?? 'اليوم',
|
|
status: p['status']?.toString() ?? 'queued',
|
|
);
|
|
}).toList();
|
|
}
|
|
|
|
emit(state.copyWith(
|
|
institutionalStudents: instCount,
|
|
studentSubscribers: paidCount,
|
|
grossRevenue: gross,
|
|
teacherShare: tShare,
|
|
directorateShare: dShare,
|
|
platformShare: pShare,
|
|
availableBalance: avail,
|
|
totalWithdrawn: withdrawn,
|
|
cliqAlias: alias,
|
|
courses: courses,
|
|
payoutRequests: payouts,
|
|
isLoading: false,
|
|
));
|
|
} catch (_) {
|
|
emit(state.copyWith(isLoading: false));
|
|
}
|
|
}
|
|
|
|
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,
|
|
));
|
|
}
|
|
|
|
Future<void> submitCliqPayout({
|
|
required String cliqAlias,
|
|
required double amountJod,
|
|
}) async {
|
|
emit(state.copyWith(isSubmittingPayout: true));
|
|
try {
|
|
final req = await repository.requestCliqPayout(
|
|
cliqAlias: cliqAlias,
|
|
amountJod: amountJod,
|
|
);
|
|
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 (_) {
|
|
emit(state.copyWith(isSubmittingPayout: false));
|
|
}
|
|
}
|
|
}
|