forked from yaso_meth/mih-project
enhanced search by gemini
This commit is contained in:
@@ -1,20 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/arguments.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_business_profile_preview.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart';
|
||||
|
||||
class BuildFavouriteBusinessesList extends StatefulWidget {
|
||||
final List<BookmarkedBusiness> favouriteBusinesses;
|
||||
final List<Business?> favouriteBusinesses;
|
||||
final String? myLocation;
|
||||
final String? searchQuery;
|
||||
const BuildFavouriteBusinessesList({
|
||||
super.key,
|
||||
required this.favouriteBusinesses,
|
||||
required this.myLocation,
|
||||
required this.searchQuery,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -24,28 +20,6 @@ class BuildFavouriteBusinessesList extends StatefulWidget {
|
||||
|
||||
class _BuildFavouriteBusinessesListState
|
||||
extends State<BuildFavouriteBusinessesList> {
|
||||
List<Business?> businesses = [];
|
||||
|
||||
List<Business?> getListOfBusinesses() {
|
||||
List<Business?> businesses = [];
|
||||
for (var item in widget.favouriteBusinesses) {
|
||||
MihBusinessDetailsServices()
|
||||
.getBusinessDetailsByBusinessId(item.business_id)
|
||||
.then((business) {
|
||||
if (business != null) {
|
||||
businesses.add(business);
|
||||
}
|
||||
});
|
||||
}
|
||||
return businesses;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
businesses = getListOfBusinesses();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.separated(
|
||||
@@ -58,63 +32,37 @@ class _BuildFavouriteBusinessesListState
|
||||
);
|
||||
},
|
||||
itemBuilder: (context, index) {
|
||||
Future<Business?> businessDetails =
|
||||
MihBusinessDetailsServices().getBusinessDetailsByBusinessId(
|
||||
widget.favouriteBusinesses[index].business_id,
|
||||
);
|
||||
return FutureBuilder<Business?>(
|
||||
future: businessDetails,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'Error: ${snapshot.error}',
|
||||
style: TextStyle(color: Colors.red),
|
||||
final Business? business = widget.favouriteBusinesses[index];
|
||||
|
||||
if (business == null) {
|
||||
return const SizedBox(); // Or a placeholder if a business couldn't be loaded
|
||||
}
|
||||
|
||||
return Material(
|
||||
color: MzansiInnovationHub.of(context)!.theme.primaryColor(),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/view',
|
||||
arguments: BusinessViewArguments(
|
||||
business,
|
||||
business.Name,
|
||||
),
|
||||
);
|
||||
} else if (snapshot.hasData && snapshot.data != null) {
|
||||
Business business = snapshot.data!;
|
||||
return Material(
|
||||
color: MzansiInnovationHub.of(context)!.theme.primaryColor(),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
'/business-profile/view',
|
||||
arguments: BusinessViewArguments(
|
||||
business,
|
||||
business.Name,
|
||||
),
|
||||
);
|
||||
},
|
||||
splashColor: MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor()
|
||||
.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Padding(
|
||||
padding: EdgeInsetsGeometry.symmetric(
|
||||
// vertical: 5,
|
||||
horizontal: 25,
|
||||
),
|
||||
child: MihBusinessProfilePreview(
|
||||
business: business, myLocation: widget.myLocation),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
print(snapshot.data);
|
||||
return SizedBox();
|
||||
}
|
||||
},
|
||||
},
|
||||
splashColor: MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor()
|
||||
.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 25,
|
||||
),
|
||||
child: MihBusinessProfilePreview(
|
||||
business: business, myLocation: widget.myLocation),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/bookmarked_business.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_objects/business.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tool_body.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_search_bar.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mzansi_directory/builders/build_favourite_businesses_list.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart';
|
||||
import 'package:supertokens_flutter/supertokens.dart';
|
||||
|
||||
@@ -26,33 +30,55 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
||||
final FocusNode searchFocusNode = FocusNode();
|
||||
late Future<List<BookmarkedBusiness>> boookmarkedBusinessListFuture;
|
||||
List<BookmarkedBusiness> listBookmarkedBusinesses = [];
|
||||
final ValueNotifier<List<BookmarkedBusiness>> searchBookmarkedBusinesses =
|
||||
final ValueNotifier<List<Business?>> searchBookmarkedBusinesses =
|
||||
ValueNotifier([]);
|
||||
Future<List<BookmarkedBusiness>> getAllBookmarkedBusinessesForUser() async {
|
||||
late Future<Map<String, Business?>> businessDetailsMapFuture;
|
||||
Map<String, Business?> _businessDetailsMap = {};
|
||||
Timer? _debounce;
|
||||
|
||||
Future<Map<String, Business?>>
|
||||
getAndMapAllBusinessDetailsForBookmarkedBusinesses() async {
|
||||
String user_id = await SuperTokens.getUserId();
|
||||
return MihMzansiDirectoryServices().getAllUserBookmarkedBusiness(user_id);
|
||||
List<BookmarkedBusiness> bookmarked = await MihMzansiDirectoryServices()
|
||||
.getAllUserBookmarkedBusiness(user_id);
|
||||
|
||||
// Store the bookmarked list for search filtering
|
||||
listBookmarkedBusinesses = bookmarked;
|
||||
|
||||
Map<String, Business?> businessMap = {};
|
||||
List<Future<Business?>> detailFutures = [];
|
||||
|
||||
for (var item in bookmarked) {
|
||||
detailFutures.add(MihBusinessDetailsServices()
|
||||
.getBusinessDetailsByBusinessId(item.business_id));
|
||||
}
|
||||
|
||||
List<Business?> details = await Future.wait(detailFutures);
|
||||
|
||||
for (int i = 0; i < bookmarked.length; i++) {
|
||||
businessMap[bookmarked[i].business_id] = details[i];
|
||||
}
|
||||
_businessDetailsMap = businessMap;
|
||||
_filterAndSetBusinesses();
|
||||
return businessMap;
|
||||
}
|
||||
|
||||
void searchBookmarkedBusinessByName() {
|
||||
if (businessSearchController.text.isEmpty) {
|
||||
searchBookmarkedBusinesses.value = listBookmarkedBusinesses;
|
||||
} else {
|
||||
List<BookmarkedBusiness> temp = [];
|
||||
for (var item in listBookmarkedBusinesses) {
|
||||
if (item.business_name
|
||||
.toLowerCase()
|
||||
.contains(businessSearchController.text.toLowerCase())) {
|
||||
temp.add(item);
|
||||
void _filterAndSetBusinesses() {
|
||||
List<Business?> businessesToDisplay = [];
|
||||
String query = businessSearchController.text.toLowerCase();
|
||||
for (var bookmarked in listBookmarkedBusinesses) {
|
||||
if (bookmarked.business_name.toLowerCase().contains(query)) {
|
||||
if (_businessDetailsMap.containsKey(bookmarked.business_id)) {
|
||||
businessesToDisplay.add(_businessDetailsMap[bookmarked.business_id]);
|
||||
}
|
||||
}
|
||||
searchBookmarkedBusinesses.value = temp;
|
||||
}
|
||||
searchBookmarkedBusinesses.value = businessesToDisplay;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
businessSearchController.removeListener(searchBookmarkedBusinessByName);
|
||||
businessSearchController.dispose();
|
||||
searchFocusNode.dispose();
|
||||
searchBookmarkedBusinesses.dispose();
|
||||
@@ -61,8 +87,16 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
boookmarkedBusinessListFuture = getAllBookmarkedBusinessesForUser();
|
||||
businessSearchController.addListener(searchBookmarkedBusinessByName);
|
||||
businessDetailsMapFuture =
|
||||
getAndMapAllBusinessDetailsForBookmarkedBusinesses();
|
||||
businessSearchController.addListener(() {
|
||||
if (_debounce?.isActive ?? false) {
|
||||
_debounce!.cancel();
|
||||
}
|
||||
_debounce = Timer(const Duration(milliseconds: 200), () {
|
||||
_filterAndSetBusinesses();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -93,8 +127,8 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder(
|
||||
future: boookmarkedBusinessListFuture,
|
||||
FutureBuilder<Map<String, Business?>>(
|
||||
future: businessDetailsMapFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Mihloadingcircle(
|
||||
@@ -102,18 +136,82 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
||||
);
|
||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||
listBookmarkedBusinesses = snapshot.data!;
|
||||
searchBookmarkedBusinessByName();
|
||||
return ValueListenableBuilder(
|
||||
valueListenable: searchBookmarkedBusinesses,
|
||||
builder: (context, value, child) {
|
||||
return BuildFavouriteBusinessesList(
|
||||
favouriteBusinesses: value,
|
||||
myLocation: widget.myLocation,
|
||||
searchQuery: businessSearchController.text,
|
||||
// No need to re-filter here, _filterAndSetBusinesses is called in initState
|
||||
// and by the text controller listener.
|
||||
return ValueListenableBuilder<List<Business?>>(
|
||||
valueListenable:
|
||||
searchBookmarkedBusinesses, // Listen to changes in this
|
||||
builder: (context, businesses, child) {
|
||||
// Display message if no results after search
|
||||
if (businesses.isEmpty &&
|
||||
businessSearchController.text.isNotEmpty) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 50),
|
||||
Icon(
|
||||
Icons
|
||||
.search_off_rounded, // A different icon for "no results"
|
||||
size: 150,
|
||||
color: MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0),
|
||||
child: SizedBox(
|
||||
width: 500,
|
||||
child: Text(
|
||||
"No businesses found for '${businessSearchController.text}'", // Specific message for no search results
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
} else if (businesses.isEmpty) {
|
||||
// Initial empty state
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 50),
|
||||
Icon(
|
||||
Icons.business_center_rounded,
|
||||
size: 150,
|
||||
color: MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.secondaryColor(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0),
|
||||
child: SizedBox(
|
||||
width: 500,
|
||||
child: Text(
|
||||
"No favourites yet, use Mzansi Search to find and bookmark businesses you like",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return BuildFavouriteBusinessesList(
|
||||
favouriteBusinesses:
|
||||
businesses, // Pass the filtered list from ValueNotifier
|
||||
myLocation: widget.myLocation,
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
// This block handles the case where there are no bookmarked businesses initially
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 50),
|
||||
@@ -140,13 +238,16 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
||||
),
|
||||
],
|
||||
);
|
||||
// return Center(
|
||||
// child: Text("No bookmarked businesses found"),
|
||||
// );
|
||||
}
|
||||
} else {
|
||||
} else if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text("Error loading bookmarked businesses"),
|
||||
child: Text(
|
||||
"Error loading bookmarked businesses: ${snapshot.error}"), // Show specific error
|
||||
);
|
||||
} else {
|
||||
// Fallback for unexpected states
|
||||
return Center(
|
||||
child: Text("An unknown error occurred."),
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user