UI updated of Subscription module

This commit is contained in:
Manish 2025-11-04 16:37:56 +05:30
parent e674d18542
commit 3008a6ab79
5 changed files with 87 additions and 38 deletions

View File

@ -139,7 +139,7 @@ class _WelcomeScreenState extends State<WelcomeScreen>
_buildActionButton(
context,
label: "Subscribe",
icon: LucideIcons.bell,
icon: LucideIcons.indian_rupee,
option: null,
),
const SizedBox(height: 16),

View File

@ -317,7 +317,7 @@ class _UserProfileBarState extends State<UserProfileBar>
),
SizedBox(height: spacingHeight),
_menuItemRow(
icon: LucideIcons.bell,
icon: LucideIcons.indian_rupee,
label: 'Subscription',
onTap: _onSubscribeTap,
iconColor: Colors.redAccent,

View File

@ -38,7 +38,8 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
_loading = false;
});
} catch (e, s) {
logSafe("❌ Exception while fetching current plan: $e\n$s", level: LogLevel.error);
logSafe("❌ Exception while fetching current plan: $e\n$s",
level: LogLevel.error);
if (mounted) setState(() => _loading = false);
}
}
@ -48,11 +49,15 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
child: Column(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.info_outline, size: 48, color: Colors.grey),
const SizedBox(height: 12),
const Text("No active subscription", style: TextStyle(fontSize: 16, color: Colors.grey)),
const Text("No active subscription",
style: TextStyle(fontSize: 16, color: Colors.grey)),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => Get.toNamed('/subscription'),
child: const Text("View Plans"),
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.green),
),
),
]),
);
@ -62,7 +67,8 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Current Plan", style: TextStyle(fontWeight: FontWeight.w600, color: Colors.black)),
title: const Text("Current Plan",
style: TextStyle(fontWeight: FontWeight.w600, color: Colors.black)),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () => Get.back(),
@ -78,32 +84,51 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
elevation: 3,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
_planDisplayName(_plan!),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(_plan!['description'] ?? '', style: const TextStyle(color: Colors.grey)),
const SizedBox(height: 12),
Row(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Price: ", style: TextStyle(color: Colors.grey[700])),
Text("${_currencySymbol(_plan!)}${_plan!['price'] ?? 0}", style: const TextStyle(fontWeight: FontWeight.bold)),
const Spacer(),
Text("Trial: ${_plan!['trialDays'] ?? 0} days", style: const TextStyle(color: Colors.grey)),
],
),
const SizedBox(height: 12),
if (_plan!['startedAt'] != null)
Text("Started: ${_plan!['startedAt']}", style: const TextStyle(color: Colors.grey)),
if (_plan!['expiresAt'] != null)
Text("Expires: ${_plan!['expiresAt']}", style: const TextStyle(color: Colors.grey)),
]),
Text(
_planDisplayName(_plan!),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text(_plan!['description'] ?? '',
style:
const TextStyle(color: Colors.grey)),
const SizedBox(height: 12),
Row(
children: [
Text("Price: ",
style: TextStyle(
color: Colors.grey[700])),
Text(
"${_currencySymbol(_plan!)}${_plan!['price'] ?? 0}",
style: const TextStyle(
fontWeight: FontWeight.bold)),
const Spacer(),
Text(
"Trial: ${_plan!['trialDays'] ?? 0} days",
style: const TextStyle(
color: Colors.grey)),
],
),
const SizedBox(height: 12),
if (_plan!['startedAt'] != null)
Text("Started: ${_plan!['startedAt']}",
style: const TextStyle(
color: Colors.grey)),
if (_plan!['expiresAt'] != null)
Text("Expires: ${_plan!['expiresAt']}",
style: const TextStyle(
color: Colors.grey)),
]),
),
),
@ -128,9 +153,12 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
onPressed: () {
// navigate to subscription page (renew flow)
// pass current plan id so subscription screen can preselect if needed
Get.toNamed('/subscription', arguments: {'currentPlanId': _plan!['id']});
Get.toNamed('/subscription',
arguments: {'currentPlanId': _plan!['id']});
},
style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 14)),
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(vertical: 14)),
child: const Text("Renew Plan"),
),
],
@ -163,18 +191,25 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
final supports = plan['features']?['supports'] ?? {};
if (supports is Map) {
supports.forEach((k, v) {
if (v == true) features.add(k.toString().replaceAll(RegExp(r'([a-z])([A-Z])'), r'\1 \2'));
if (v == true)
features.add(
k.toString().replaceAll(RegExp(r'([a-z])([A-Z])'), r'\1 \2'));
});
}
} catch (_) {}
if (features.isEmpty) return [const SizedBox.shrink()];
return [
const SizedBox(height: 12),
const Text("Included features", style: TextStyle(fontWeight: FontWeight.w600)),
const Text("Included features",
style: TextStyle(fontWeight: FontWeight.w600)),
const SizedBox(height: 8),
...features.map((f) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(children: [const Icon(Icons.check, size: 16, color: Colors.green), const SizedBox(width: 8), Expanded(child: Text(f))]),
child: Row(children: [
const Icon(Icons.check, size: 16, color: Colors.green),
const SizedBox(width: 8),
Expanded(child: Text(f))
]),
)),
];
}

View File

@ -38,6 +38,8 @@ class SubscriptionScreen extends StatelessWidget {
}
return RefreshIndicator(
color: Colors.white,
backgroundColor: Colors.blue,
onRefresh: () =>
controller.fetchPlans(controller.selectedFrequency.value),
child: SingleChildScrollView(
@ -61,6 +63,7 @@ class SubscriptionScreen extends StatelessWidget {
MyText.titleMedium(
plan['planName'] ?? 'Plan',
fontWeight: 700,
fontSize: 25,
),
MySpacing.height(4),
MyText.bodySmall(
@ -71,7 +74,7 @@ class SubscriptionScreen extends StatelessWidget {
Text(
"$currency${plan['price'] ?? 0}",
style: const TextStyle(
fontSize: 20,
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.green,
),
@ -88,14 +91,14 @@ class SubscriptionScreen extends StatelessWidget {
.map((f) => Row(
children: [
const Icon(Icons.check,
size: 16,
size: 20,
color: Colors.green),
const SizedBox(width: 6),
Expanded(
child: Text(
f,
style: const TextStyle(
fontSize: 13),
fontSize: 18),
)),
],
))
@ -105,6 +108,12 @@ class SubscriptionScreen extends StatelessWidget {
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))
),
onPressed: () {
Get.toNamed('/create-tenant', arguments: {
'planId': plan['id'] ?? '',
@ -114,8 +123,9 @@ class SubscriptionScreen extends StatelessWidget {
});
},
child: MyText.bodyMedium(
'Subscribe for $currency${plan['price']}',
'Subscribe',
color: Colors.white,
fontSize: 18,
),
),
),
@ -151,10 +161,10 @@ class SubscriptionScreen extends StatelessWidget {
padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.white,
color: isSelected ? Colors.green : Colors.white,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: isSelected ? Colors.blue : Colors.grey.shade300),
color: isSelected ? Colors.green : Colors.grey.shade300),
),
child: Text(
_capitalize(freq),

View File

@ -127,6 +127,10 @@ class _TenantCreateScreenState extends State<TenantCreateScreen> {
"Create Tenant",
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),
),
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () => Get.back(),
),
centerTitle: true,
elevation: 0,
),