enhanced search by gemini
This commit is contained in:
@@ -1,20 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mzansi_innovation_hub/main.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/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_objects/business.dart';
|
||||||
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_business_profile_preview.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 {
|
class BuildFavouriteBusinessesList extends StatefulWidget {
|
||||||
final List<BookmarkedBusiness> favouriteBusinesses;
|
final List<Business?> favouriteBusinesses;
|
||||||
final String? myLocation;
|
final String? myLocation;
|
||||||
final String? searchQuery;
|
|
||||||
const BuildFavouriteBusinessesList({
|
const BuildFavouriteBusinessesList({
|
||||||
super.key,
|
super.key,
|
||||||
required this.favouriteBusinesses,
|
required this.favouriteBusinesses,
|
||||||
required this.myLocation,
|
required this.myLocation,
|
||||||
required this.searchQuery,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -24,28 +20,6 @@ class BuildFavouriteBusinessesList extends StatefulWidget {
|
|||||||
|
|
||||||
class _BuildFavouriteBusinessesListState
|
class _BuildFavouriteBusinessesListState
|
||||||
extends State<BuildFavouriteBusinessesList> {
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
@@ -58,63 +32,37 @@ class _BuildFavouriteBusinessesListState
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
Future<Business?> businessDetails =
|
final Business? business = widget.favouriteBusinesses[index];
|
||||||
MihBusinessDetailsServices().getBusinessDetailsByBusinessId(
|
|
||||||
widget.favouriteBusinesses[index].business_id,
|
if (business == null) {
|
||||||
);
|
return const SizedBox(); // Or a placeholder if a business couldn't be loaded
|
||||||
return FutureBuilder<Business?>(
|
}
|
||||||
future: businessDetails,
|
|
||||||
builder: (context, snapshot) {
|
return Material(
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
color: MzansiInnovationHub.of(context)!.theme.primaryColor(),
|
||||||
return Row(
|
child: InkWell(
|
||||||
children: [
|
onTap: () {
|
||||||
Padding(
|
Navigator.of(context).pushNamed(
|
||||||
padding: const EdgeInsets.only(left: 25.0),
|
'/business-profile/view',
|
||||||
child: CircularProgressIndicator(),
|
arguments: BusinessViewArguments(
|
||||||
),
|
business,
|
||||||
],
|
business.Name,
|
||||||
);
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
return Center(
|
|
||||||
child: Text(
|
|
||||||
'Error: ${snapshot.error}',
|
|
||||||
style: TextStyle(color: Colors.red),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasData && snapshot.data != null) {
|
},
|
||||||
Business business = snapshot.data!;
|
splashColor: MzansiInnovationHub.of(context)!
|
||||||
return Material(
|
.theme
|
||||||
color: MzansiInnovationHub.of(context)!.theme.primaryColor(),
|
.secondaryColor()
|
||||||
child: InkWell(
|
.withOpacity(0.2),
|
||||||
onTap: () {
|
borderRadius: BorderRadius.circular(15),
|
||||||
Navigator.of(context).pushNamed(
|
child: Padding(
|
||||||
'/business-profile/view',
|
padding: EdgeInsets.symmetric(
|
||||||
arguments: BusinessViewArguments(
|
horizontal: 25,
|
||||||
business,
|
),
|
||||||
business.Name,
|
child: MihBusinessProfilePreview(
|
||||||
),
|
business: business, myLocation: widget.myLocation),
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
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();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mzansi_innovation_hub/main.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/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_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_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_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_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_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:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart';
|
||||||
import 'package:supertokens_flutter/supertokens.dart';
|
import 'package:supertokens_flutter/supertokens.dart';
|
||||||
|
|
||||||
@@ -26,33 +30,55 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
|||||||
final FocusNode searchFocusNode = FocusNode();
|
final FocusNode searchFocusNode = FocusNode();
|
||||||
late Future<List<BookmarkedBusiness>> boookmarkedBusinessListFuture;
|
late Future<List<BookmarkedBusiness>> boookmarkedBusinessListFuture;
|
||||||
List<BookmarkedBusiness> listBookmarkedBusinesses = [];
|
List<BookmarkedBusiness> listBookmarkedBusinesses = [];
|
||||||
final ValueNotifier<List<BookmarkedBusiness>> searchBookmarkedBusinesses =
|
final ValueNotifier<List<Business?>> searchBookmarkedBusinesses =
|
||||||
ValueNotifier([]);
|
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();
|
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() {
|
void _filterAndSetBusinesses() {
|
||||||
if (businessSearchController.text.isEmpty) {
|
List<Business?> businessesToDisplay = [];
|
||||||
searchBookmarkedBusinesses.value = listBookmarkedBusinesses;
|
String query = businessSearchController.text.toLowerCase();
|
||||||
} else {
|
for (var bookmarked in listBookmarkedBusinesses) {
|
||||||
List<BookmarkedBusiness> temp = [];
|
if (bookmarked.business_name.toLowerCase().contains(query)) {
|
||||||
for (var item in listBookmarkedBusinesses) {
|
if (_businessDetailsMap.containsKey(bookmarked.business_id)) {
|
||||||
if (item.business_name
|
businessesToDisplay.add(_businessDetailsMap[bookmarked.business_id]);
|
||||||
.toLowerCase()
|
|
||||||
.contains(businessSearchController.text.toLowerCase())) {
|
|
||||||
temp.add(item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
searchBookmarkedBusinesses.value = temp;
|
|
||||||
}
|
}
|
||||||
|
searchBookmarkedBusinesses.value = businessesToDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
businessSearchController.removeListener(searchBookmarkedBusinessByName);
|
|
||||||
businessSearchController.dispose();
|
businessSearchController.dispose();
|
||||||
searchFocusNode.dispose();
|
searchFocusNode.dispose();
|
||||||
searchBookmarkedBusinesses.dispose();
|
searchBookmarkedBusinesses.dispose();
|
||||||
@@ -61,8 +87,16 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
boookmarkedBusinessListFuture = getAllBookmarkedBusinessesForUser();
|
businessDetailsMapFuture =
|
||||||
businessSearchController.addListener(searchBookmarkedBusinessByName);
|
getAndMapAllBusinessDetailsForBookmarkedBusinesses();
|
||||||
|
businessSearchController.addListener(() {
|
||||||
|
if (_debounce?.isActive ?? false) {
|
||||||
|
_debounce!.cancel();
|
||||||
|
}
|
||||||
|
_debounce = Timer(const Duration(milliseconds: 200), () {
|
||||||
|
_filterAndSetBusinesses();
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -93,8 +127,8 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
FutureBuilder(
|
FutureBuilder<Map<String, Business?>>(
|
||||||
future: boookmarkedBusinessListFuture,
|
future: businessDetailsMapFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||||
return Mihloadingcircle(
|
return Mihloadingcircle(
|
||||||
@@ -102,18 +136,82 @@ class _MihFavouriteBusinessesState extends State<MihFavouriteBusinesses> {
|
|||||||
);
|
);
|
||||||
} else if (snapshot.connectionState == ConnectionState.done) {
|
} else if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
|
||||||
listBookmarkedBusinesses = snapshot.data!;
|
// No need to re-filter here, _filterAndSetBusinesses is called in initState
|
||||||
searchBookmarkedBusinessByName();
|
// and by the text controller listener.
|
||||||
return ValueListenableBuilder(
|
return ValueListenableBuilder<List<Business?>>(
|
||||||
valueListenable: searchBookmarkedBusinesses,
|
valueListenable:
|
||||||
builder: (context, value, child) {
|
searchBookmarkedBusinesses, // Listen to changes in this
|
||||||
return BuildFavouriteBusinessesList(
|
builder: (context, businesses, child) {
|
||||||
favouriteBusinesses: value,
|
// Display message if no results after search
|
||||||
myLocation: widget.myLocation,
|
if (businesses.isEmpty &&
|
||||||
searchQuery: businessSearchController.text,
|
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 {
|
} else {
|
||||||
|
// This block handles the case where there are no bookmarked businesses initially
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 50),
|
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(
|
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