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( _buildActionButton(
context, context,
label: "Subscribe", label: "Subscribe",
icon: LucideIcons.bell, icon: LucideIcons.indian_rupee,
option: null, option: null,
), ),
const SizedBox(height: 16), const SizedBox(height: 16),

View File

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

View File

@ -38,7 +38,8 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
_loading = false; _loading = false;
}); });
} catch (e, s) { } 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); if (mounted) setState(() => _loading = false);
} }
} }
@ -48,11 +49,15 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
child: Column(mainAxisSize: MainAxisSize.min, children: [ child: Column(mainAxisSize: MainAxisSize.min, children: [
const Icon(Icons.info_outline, size: 48, color: Colors.grey), const Icon(Icons.info_outline, size: 48, color: Colors.grey),
const SizedBox(height: 12), 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), const SizedBox(height: 8),
ElevatedButton( ElevatedButton(
onPressed: () => Get.toNamed('/subscription'), onPressed: () => Get.toNamed('/subscription'),
child: const Text("View Plans"), 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) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( 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( leading: IconButton(
icon: const Icon(Icons.arrow_back_ios_new), icon: const Icon(Icons.arrow_back_ios_new),
onPressed: () => Get.back(), onPressed: () => Get.back(),
@ -78,31 +84,50 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Card( Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12)),
elevation: 3, elevation: 3,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text( Text(
_planDisplayName(_plan!), _planDisplayName(_plan!),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text(_plan!['description'] ?? '', style: const TextStyle(color: Colors.grey)), Text(_plan!['description'] ?? '',
style:
const TextStyle(color: Colors.grey)),
const SizedBox(height: 12), const SizedBox(height: 12),
Row( Row(
children: [ children: [
Text("Price: ", style: TextStyle(color: Colors.grey[700])), Text("Price: ",
Text("${_currencySymbol(_plan!)}${_plan!['price'] ?? 0}", style: const TextStyle(fontWeight: FontWeight.bold)), style: TextStyle(
color: Colors.grey[700])),
Text(
"${_currencySymbol(_plan!)}${_plan!['price'] ?? 0}",
style: const TextStyle(
fontWeight: FontWeight.bold)),
const Spacer(), const Spacer(),
Text("Trial: ${_plan!['trialDays'] ?? 0} days", style: const TextStyle(color: Colors.grey)), Text(
"Trial: ${_plan!['trialDays'] ?? 0} days",
style: const TextStyle(
color: Colors.grey)),
], ],
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
if (_plan!['startedAt'] != null) if (_plan!['startedAt'] != null)
Text("Started: ${_plan!['startedAt']}", style: const TextStyle(color: Colors.grey)), Text("Started: ${_plan!['startedAt']}",
style: const TextStyle(
color: Colors.grey)),
if (_plan!['expiresAt'] != null) if (_plan!['expiresAt'] != null)
Text("Expires: ${_plan!['expiresAt']}", style: const TextStyle(color: Colors.grey)), Text("Expires: ${_plan!['expiresAt']}",
style: const TextStyle(
color: Colors.grey)),
]), ]),
), ),
), ),
@ -128,9 +153,12 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
onPressed: () { onPressed: () {
// navigate to subscription page (renew flow) // navigate to subscription page (renew flow)
// pass current plan id so subscription screen can preselect if needed // 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"), child: const Text("Renew Plan"),
), ),
], ],
@ -163,18 +191,25 @@ class _CurrentPlanScreenState extends State<CurrentPlanScreen> {
final supports = plan['features']?['supports'] ?? {}; final supports = plan['features']?['supports'] ?? {};
if (supports is Map) { if (supports is Map) {
supports.forEach((k, v) { 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 (_) {} } catch (_) {}
if (features.isEmpty) return [const SizedBox.shrink()]; if (features.isEmpty) return [const SizedBox.shrink()];
return [ return [
const SizedBox(height: 12), 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), const SizedBox(height: 8),
...features.map((f) => Padding( ...features.map((f) => Padding(
padding: const EdgeInsets.symmetric(vertical: 4), 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( return RefreshIndicator(
color: Colors.white,
backgroundColor: Colors.blue,
onRefresh: () => onRefresh: () =>
controller.fetchPlans(controller.selectedFrequency.value), controller.fetchPlans(controller.selectedFrequency.value),
child: SingleChildScrollView( child: SingleChildScrollView(
@ -61,6 +63,7 @@ class SubscriptionScreen extends StatelessWidget {
MyText.titleMedium( MyText.titleMedium(
plan['planName'] ?? 'Plan', plan['planName'] ?? 'Plan',
fontWeight: 700, fontWeight: 700,
fontSize: 25,
), ),
MySpacing.height(4), MySpacing.height(4),
MyText.bodySmall( MyText.bodySmall(
@ -71,7 +74,7 @@ class SubscriptionScreen extends StatelessWidget {
Text( Text(
"$currency${plan['price'] ?? 0}", "$currency${plan['price'] ?? 0}",
style: const TextStyle( style: const TextStyle(
fontSize: 20, fontSize: 30,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.green, color: Colors.green,
), ),
@ -88,14 +91,14 @@ class SubscriptionScreen extends StatelessWidget {
.map((f) => Row( .map((f) => Row(
children: [ children: [
const Icon(Icons.check, const Icon(Icons.check,
size: 16, size: 20,
color: Colors.green), color: Colors.green),
const SizedBox(width: 6), const SizedBox(width: 6),
Expanded( Expanded(
child: Text( child: Text(
f, f,
style: const TextStyle( style: const TextStyle(
fontSize: 13), fontSize: 18),
)), )),
], ],
)) ))
@ -105,6 +108,12 @@ class SubscriptionScreen extends StatelessWidget {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 15),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))
),
onPressed: () { onPressed: () {
Get.toNamed('/create-tenant', arguments: { Get.toNamed('/create-tenant', arguments: {
'planId': plan['id'] ?? '', 'planId': plan['id'] ?? '',
@ -114,8 +123,9 @@ class SubscriptionScreen extends StatelessWidget {
}); });
}, },
child: MyText.bodyMedium( child: MyText.bodyMedium(
'Subscribe for $currency${plan['price']}', 'Subscribe',
color: Colors.white, color: Colors.white,
fontSize: 18,
), ),
), ),
), ),
@ -151,10 +161,10 @@ class SubscriptionScreen extends StatelessWidget {
padding: padding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 8), const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: isSelected ? Colors.blue : Colors.white, color: isSelected ? Colors.green : Colors.white,
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
border: Border.all( border: Border.all(
color: isSelected ? Colors.blue : Colors.grey.shade300), color: isSelected ? Colors.green : Colors.grey.shade300),
), ),
child: Text( child: Text(
_capitalize(freq), _capitalize(freq),

View File

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