Update: 2026-07-12 05:49:17

This commit is contained in:
Hamza-Ayed
2026-07-12 05:49:17 +03:00
parent 24fb56f08f
commit 1f68cb7333
3 changed files with 129 additions and 104 deletions
@@ -22,25 +22,29 @@ class TransitHomePage extends StatelessWidget {
title: 'Mawasalati'.tr,
isleading: true,
body: [
Expanded(
child: RefreshIndicator(
onRefresh: c.fetchMyEnrollments,
child: c.isLoadingEnrollments
? const Center(child: CircularProgressIndicator())
: c.myEnrollments.isEmpty
? _emptyState(c)
: ListView(
padding: const EdgeInsets.all(16),
children: [
Text('My Memberships'.tr,
style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 12),
...c.myEnrollments.map((e) => _enrollmentCard(e, c)),
const SizedBox(height: 20),
_addOrgTile(),
],
),
),
Column(
children: [
Expanded(
child: RefreshIndicator(
onRefresh: c.fetchMyEnrollments,
child: c.isLoadingEnrollments
? const Center(child: CircularProgressIndicator())
: c.myEnrollments.isEmpty
? _emptyState(c)
: ListView(
padding: const EdgeInsets.all(16),
children: [
Text('My Memberships'.tr,
style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 12),
...c.myEnrollments.map((e) => _enrollmentCard(e, c)),
const SizedBox(height: 20),
_addOrgTile(),
],
),
),
),
],
),
],
),
@@ -22,7 +22,9 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
@override
void initState() {
super.initState();
Get.find<TransitController>().browseOrgs();
WidgetsBinding.instance.addPostFrameCallback((_) {
Get.find<TransitController>().browseOrgs();
});
}
@override
@@ -32,59 +34,69 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
title: 'Choose your institution'.tr,
isleading: true,
body: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: _searchCtrl,
onSubmitted: (v) => c.browseOrgs(search: v),
decoration: InputDecoration(
hintText: 'Search for a university or institution...'.tr,
prefixIcon: const Icon(Icons.search),
filled: true,
fillColor: AppColor.cardColor,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColor.borderColor),
Column(
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(
controller: _searchCtrl,
onSubmitted: (v) => c.browseOrgs(search: v),
decoration: InputDecoration(
hintText: 'Search for a university or institution...'.tr,
prefixIcon: const Icon(Icons.search),
filled: true,
fillColor: AppColor.cardColor,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColor.borderColor),
),
),
),
),
),
),
Expanded(
child: c.isLoadingOrgs
? const Center(child: CircularProgressIndicator())
: c.browsableOrgs.isEmpty
? Center(
child: Text('No results'.tr, style: AppStyle.title),
)
: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: c.browsableOrgs.length,
itemBuilder: (_, i) {
final org = c.browsableOrgs[i];
return Card(
margin: const EdgeInsets.only(bottom: 10),
color: AppColor.cardColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
side: BorderSide(color: AppColor.borderColor),
),
child: ListTile(
title: Text(org.nameAr, style: AppStyle.title),
subtitle: Text(org.city, style: AppStyle.subtitle),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () => _showActivateSheet(context, c, org),
),
);
},
),
Expanded(
child: c.isLoadingOrgs
? const Center(child: CircularProgressIndicator())
: c.browsableOrgs.isEmpty
? Center(
child: Text('No results'.tr, style: AppStyle.title),
)
: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: c.browsableOrgs.length,
itemBuilder: (_, i) {
final org = c.browsableOrgs[i];
return Card(
margin: const EdgeInsets.only(bottom: 10),
color: AppColor.cardColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
side: BorderSide(color: AppColor.borderColor),
),
child: ListTile(
title:
Text(org.nameAr, style: AppStyle.title),
subtitle:
Text(org.city, style: AppStyle.subtitle),
trailing: const Icon(Icons.arrow_forward_ios,
size: 16),
onTap: () =>
_showActivateSheet(context, c, org),
),
);
},
),
),
],
),
],
),
);
}
void _showActivateSheet(BuildContext context, TransitController c, TransitOrg org) {
void _showActivateSheet(
BuildContext context, TransitController c, TransitOrg org) {
final idCtrl = TextEditingController();
bool loading = false;
@@ -107,7 +119,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(org.nameAr, style: AppStyle.headTitle2.copyWith(fontSize: 18)),
Text(org.nameAr,
style: AppStyle.headTitle2.copyWith(fontSize: 18)),
const SizedBox(height: 6),
Text('Enter your student/employee ID to activate membership'.tr,
style: AppStyle.subtitle),
@@ -118,7 +131,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
hintText: 'Student ID'.tr,
filled: true,
fillColor: AppColor.secondaryColor,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12)),
),
),
const SizedBox(height: 16),
@@ -128,7 +142,8 @@ class _TransitOrgBrowsePageState extends State<TransitOrgBrowsePage> {
onPressed: () async {
if (idCtrl.text.trim().isEmpty) return;
setState(() => loading = true);
final ok = await c.activateEnrollment(org.id, idCtrl.text.trim());
final ok =
await c.activateEnrollment(org.id, idCtrl.text.trim());
setState(() => loading = false);
if (ok && ctx.mounted) {
Navigator.pop(ctx);
@@ -21,7 +21,9 @@ class _TransitRoutesPageState extends State<TransitRoutesPage> {
@override
void initState() {
super.initState();
Get.find<TransitController>().openOrgRoutes(widget.orgId);
WidgetsBinding.instance.addPostFrameCallback((_) {
Get.find<TransitController>().openOrgRoutes(widget.orgId);
});
}
@override
@@ -31,41 +33,45 @@ class _TransitRoutesPageState extends State<TransitRoutesPage> {
title: widget.orgName,
isleading: true,
body: [
Expanded(
child: c.isLoadingRoutes
? const Center(child: CircularProgressIndicator())
: c.currentOrgRoutes.isEmpty
? Center(
child: Text('No active routes currently'.tr, style: AppStyle.title),
)
: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: c.currentOrgRoutes.length,
itemBuilder: (_, i) {
final r = c.currentOrgRoutes[i];
return Card(
margin: const EdgeInsets.only(bottom: 10),
color: AppColor.cardColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
side: BorderSide(color: AppColor.borderColor),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: AppColor.accentColor.withOpacity(0.15),
child: Icon(Icons.directions_bus, color: AppColor.accentColor),
),
title: Text(r.nameAr, style: AppStyle.title),
subtitle: Text('${r.stopCount} ${'Stops'.tr}', style: AppStyle.subtitle),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () => Get.to(
() => TransitLiveMapPage(routeId: r.id, routeName: r.nameAr),
),
),
);
},
),
Column(
children: [
Expanded(
child: c.isLoadingRoutes
? const Center(child: CircularProgressIndicator())
: c.currentOrgRoutes.isEmpty
? Center(
child: Text('No active routes currently'.tr, style: AppStyle.title),
)
: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: c.currentOrgRoutes.length,
itemBuilder: (_, i) {
final r = c.currentOrgRoutes[i];
return Card(
margin: const EdgeInsets.only(bottom: 10),
color: AppColor.cardColor,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
side: BorderSide(color: AppColor.borderColor),
),
child: ListTile(
leading: CircleAvatar(
backgroundColor: AppColor.accentColor.withOpacity(0.15),
child: Icon(Icons.directions_bus, color: AppColor.accentColor),
),
title: Text(r.nameAr, style: AppStyle.title),
subtitle: Text('${r.stopCount} ${'Stops'.tr}', style: AppStyle.subtitle),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: () => Get.to(
() => TransitLiveMapPage(routeId: r.id, routeName: r.nameAr),
),
),
);
},
),
),
],
),
],
),