frontendPlayer/lib/presentation/pages/plan_renewal_page.dart
2026-04-10 09:55:19 +03:30

390 lines
14 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import '../../core/constants/app_colors.dart';
import '../../core/constants/app_text_styles.dart';
import '../widgets/teacher_panel_scaffold.dart';
import 'course_page.dart';
import 'license_page.dart';
import 'ticket_page.dart';
import 'transaction_page.dart';
class PlanRenewalPage extends StatefulWidget {
const PlanRenewalPage({super.key});
@override
State<PlanRenewalPage> createState() => _PlanRenewalPageState();
}
class _PlanRenewalPageState extends State<PlanRenewalPage> {
int _billingCycle = 365;
int _selectedPlan = 3;
String _extraSpace = '5 GB';
bool _useLocalServer = false;
bool _acceptTerms = false;
final List<Map<String, dynamic>> _plans = const [
{'size': '20 GB', 'monthly': 82000},
{'size': '50 GB', 'monthly': 145000},
{'size': '125 GB', 'monthly': 343000},
{'size': '250 GB', 'monthly': 395000},
{'size': '500 GB', 'monthly': 999000},
{'size': '1000 GB', 'monthly': 1455000},
];
int get _cycleFactor {
if (_billingCycle == 60) return 2;
if (_billingCycle == 365) return 12;
return 1;
}
int get _fee => (_plans[_selectedPlan]['monthly'] as int) * _cycleFactor;
int get _payable => _fee;
Widget _buildLabeledField(String label, String value, {String? helperText}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: AppTextStyles.bodyLarge),
const SizedBox(height: 8),
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: AppColors.sidebarBg.withValues(alpha: 0.6),
),
color: Colors.white,
),
child: Text(
value,
style: AppTextStyles.bodyLarge.copyWith(color: AppColors.sidebarBg),
),
),
if (helperText != null) ...[
const SizedBox(height: 8),
Text(helperText, style: AppTextStyles.bodyMedium),
],
],
);
}
Widget _buildMainContent() {
final isDesktop = MediaQuery.of(context).size.width > 900;
final isMobile = !isDesktop;
final plan = _plans[_selectedPlan];
return SingleChildScrollView(
padding: EdgeInsets.symmetric(
horizontal: isDesktop ? 32 : 16,
vertical: 24,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () => Navigator.pop(context),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.arrow_back,
color: AppColors.sidebarBg,
size: 20,
),
const SizedBox(width: 8),
Text(
'بازگشت به داشبورد',
style: AppTextStyles.bodyMedium.copyWith(
color: AppColors.sidebarBg,
),
),
],
),
),
const SizedBox(height: 20),
Text('پلن فضا', style: AppTextStyles.headlineMedium),
const SizedBox(height: 20),
Flex(
direction: isMobile ? Axis.vertical : Axis.horizontal,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: isMobile ? 0 : 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildLabeledField('سررسید', '۱۴۰۵/۰۸/۱۰'),
const SizedBox(height: 16),
Text('فضای اضافه', style: AppTextStyles.bodyLarge),
const SizedBox(height: 8),
DropdownButtonFormField<String>(
initialValue: _extraSpace,
isExpanded: true,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: AppColors.sidebarBg.withValues(alpha: 0.6),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: AppColors.sidebarBg.withValues(alpha: 0.6),
),
),
),
items: const ['0 GB', '5 GB', '10 GB', '20 GB', '50 GB']
.map(
(value) => DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: AppTextStyles.bodyLarge,
),
),
)
.toList(),
onChanged: (value) {
if (value == null) return;
setState(() => _extraSpace = value);
},
),
const SizedBox(height: 8),
Text(
'فضای اضافه روی همین مجموعه فعال می‌شود و در صورت نیاز می‌توانید بعدا آن را تغییر دهید.',
style: AppTextStyles.bodyMedium,
),
const SizedBox(height: 16),
Row(
children: [
Checkbox(
value: _useLocalServer,
onChanged: (value) {
setState(() => _useLocalServer = value ?? false);
},
),
Text('سرور آلمان', style: AppTextStyles.bodyLarge),
],
),
Text(
'در صورت انتخاب، بکاپ‌گیری روی سرور ثانویه هم انجام می‌شود و هزینه سرویس تغییر می‌کند.',
style: AppTextStyles.bodyMedium,
),
],
),
),
SizedBox(width: isMobile ? 0 : 32, height: isMobile ? 24 : 0),
Expanded(
flex: isMobile ? 0 : 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('دوره پرداخت', style: AppTextStyles.headlineMedium),
const SizedBox(height: 10),
Wrap(
spacing: 20,
runSpacing: 8,
children: [
_buildCycleOption('۳۰ ماهه', 30),
_buildCycleOption('۶۰ ماهه', 60),
_buildCycleOption('سالانه', 365),
],
),
const SizedBox(height: 24),
Text('فضا', style: AppTextStyles.headlineMedium),
const SizedBox(height: 8),
...List.generate(_plans.length, (index) {
final item = _plans[index];
final monthly = item['monthly'] as int;
final selected = index == _selectedPlan;
return InkWell(
onTap: () => setState(() => _selectedPlan = index),
borderRadius: BorderRadius.circular(8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Icon(
selected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: selected
? AppColors.sidebarBg
: AppColors.textSecondary,
),
const SizedBox(width: 8),
Expanded(
child: RichText(
text: TextSpan(
style: AppTextStyles.bodyLarge,
children: [
TextSpan(
text:
'ماهانه ${_formatNumber(monthly)} تومان - ',
),
TextSpan(
text: item['size'] as String,
style: AppTextStyles.bodyLarge.copyWith(
color: selected
? AppColors.creditCardBorder
: AppColors.textPrimary,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
],
),
),
);
}),
],
),
),
],
),
const SizedBox(height: 28),
Text('پرداخت', style: AppTextStyles.headlineMedium),
const SizedBox(height: 12),
_buildLabeledField('تعرفه', '${_formatNumber(_fee)} تومان'),
const SizedBox(height: 14),
_buildLabeledField(
'پرداخت',
'${_formatNumber(_payable)} تومان',
helperText:
'مبلغ پرداخت با توجه به زمان باقی‌مانده از اعتبار فعلی و تغییرات پلن، ممکن است کمی تغییر کند.',
),
const SizedBox(height: 14),
_buildLabeledField('اعتبار', '۰'),
const SizedBox(height: 18),
Row(
children: [
Checkbox(
value: _acceptTerms,
onChanged: (value) {
setState(() => _acceptTerms = value ?? false);
},
),
Expanded(
child: Text(
'شرایط و قوانین سایت را مطالعه کرده و می‌پذیرم.',
style: AppTextStyles.bodyMedium,
),
),
],
),
const SizedBox(height: 20),
Wrap(
spacing: 12,
runSpacing: 10,
children: [
SizedBox(
width: isMobile ? double.infinity : 160,
height: 44,
child: ElevatedButton(
onPressed: _acceptTerms ? () {} : null,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.success,
foregroundColor: Colors.white,
disabledBackgroundColor: AppColors.success.withValues(
alpha: 0.35,
),
),
child: const Text('تایید'),
),
),
SizedBox(
width: isMobile ? double.infinity : 160,
height: 44,
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.error.withValues(alpha: 0.85),
foregroundColor: Colors.white,
),
child: const Text('انصراف'),
),
),
],
),
const SizedBox(height: 16),
Text(
'پلن انتخاب‌شده: ${plan['size']}',
style: AppTextStyles.bodyMedium,
),
],
),
);
}
Widget _buildCycleOption(String title, int value) {
final selected = _billingCycle == value;
return InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => setState(() => _billingCycle = value),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
selected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: selected ? AppColors.sidebarBg : AppColors.textSecondary,
),
Text(title, style: AppTextStyles.bodyLarge),
],
),
);
}
String _formatNumber(int number) {
final chars = number.toString().split('').reversed.toList();
final buffer = StringBuffer();
for (var i = 0; i < chars.length; i++) {
if (i != 0 && i % 3 == 0) {
buffer.write(',');
}
buffer.write(chars[i]);
}
return buffer.toString().split('').reversed.join();
}
@override
Widget build(BuildContext context) {
return TeacherPanelScaffold(
selectedMenu: PanelMenu.none,
onDashboardTap: () {
if (Navigator.of(context).canPop()) {
Navigator.of(context).pop();
}
},
onCourseTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const CoursePage()),
);
},
onLicenseTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const PanelLicensePage()),
);
},
onTransactionTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const TransactionPage()),
);
},
onTicketTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const TicketPage()),
);
},
child: _buildMainContent(),
);
}
}