marco.pms.mobileapp/lib/view/subscriptions/subscriptions_screen.dart

201 lines
8.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/controller/subscriptions/subscription_controller.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
class SubscriptionScreen extends StatelessWidget {
final SubscriptionController controller = Get.put(SubscriptionController());
SubscriptionScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Subscription Plans',
style: TextStyle(
color: Colors.black87,
),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () => Get.back(),
),
),
body: SafeArea(
child: Column(
children: [
_buildFrequencyTabs(),
Expanded(
child: Obx(() {
if (controller.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
if (controller.plans.isEmpty) {
return const Center(child: Text("No Plans Available"));
}
return RefreshIndicator(
onRefresh: () =>
controller.fetchPlans(controller.selectedFrequency.value),
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(16),
child: Column(
children: controller.plans.map((plan) {
final features = _extractFeatures(plan);
final currency = plan['currency']?['symbol'] ?? '';
return Card(
margin: const EdgeInsets.only(bottom: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 3,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleMedium(
plan['planName'] ?? 'Plan',
fontWeight: 700,
),
MySpacing.height(4),
MyText.bodySmall(
plan['description'] ?? '',
color: Colors.grey[700],
),
MySpacing.height(8),
Text(
"$currency${plan['price'] ?? 0}",
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.green,
),
),
MySpacing.height(8),
Text(
"Trial: ${plan['trialDays'] ?? 0} days",
style: const TextStyle(color: Colors.grey),
),
MySpacing.height(12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: features
.map((f) => Row(
children: [
const Icon(Icons.check,
size: 16,
color: Colors.green),
const SizedBox(width: 6),
Expanded(
child: Text(
f,
style: const TextStyle(
fontSize: 13),
)),
],
))
.toList(),
),
MySpacing.height(16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
Get.toNamed('/create-tenant', arguments: {
'planId': plan['id'] ?? '',
'amount': plan['price'] ?? 0,
'planName':
plan['planName'] ?? 'Subscription',
});
},
child: MyText.bodyMedium(
'Subscribe for $currency${plan['price']}',
color: Colors.white,
),
),
),
],
),
),
);
}).toList(),
),
),
);
}),
),
],
),
),
);
}
// --- Frequency Tab Bar ---
Widget _buildFrequencyTabs() {
return Obx(() {
return Container(
color: Colors.blue[50],
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: controller.frequencies.map((freq) {
final isSelected = controller.selectedFrequency.value == freq;
return GestureDetector(
onTap: () => controller.fetchPlans(freq),
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.white,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? Colors.blue : Colors.grey.shade300),
),
child: Text(
_capitalize(freq),
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontWeight: isSelected ? FontWeight.bold : FontWeight.w500,
),
),
),
);
}).toList(),
),
);
});
}
// --- Helper to extract feature names dynamically ---
List<String> _extractFeatures(Map<String, dynamic> plan) {
final features = <String>[];
try {
final modules = plan['features']?['modules'] ?? {};
modules.forEach((key, value) {
if (value is Map && value['enabled'] == true) {
features.add(value['name'] ?? key);
}
});
final supports = plan['features']?['supports'] ?? {};
supports.forEach((k, v) {
if (v == true) {
features.add(
k.toString().replaceAll(RegExp(r'([a-z])([A-Z])'), r'\1 \2'));
}
});
} catch (e) {
print("Feature parse error: $e");
}
return features;
}
String _capitalize(String str) =>
str.isEmpty ? '' : str[0].toUpperCase() + str.substring(1);
}