Mzansi Wallet Display done

This commit is contained in:
yaso 2026-06-26 10:33:06 +02:00
parent 003c8b7c0d
commit f588e9f715
11 changed files with 246 additions and 39 deletions

View file

@ -4,8 +4,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:mih_package_toolkit/mih_package_toolkit.dart';
import 'package:mzansi_innovation_hub/mih_hive/mzansi_profile_hive_data.dart';
import 'package:mzansi_innovation_hub/mih_hive/mzansi_wallet_hive_data.dart';
import 'package:mzansi_innovation_hub/mih_providers/about_mih_provider.dart';
import 'package:mzansi_innovation_hub/mih_providers/mih_access_controlls_provider.dart';
import 'package:mzansi_innovation_hub/mih_providers/mih_authentication_provider.dart';
@ -123,10 +123,14 @@ class _MzansiInnovationHubState extends State<MzansiInnovationHub> {
create: (context) => MihAuthenticationProvider(),
),
ChangeNotifierProvider(
create: (context) => MzansiProfileProvider(MzansiProfileHiveData()),
create: (context) => MzansiProfileProvider(
MzansiProfileHiveData(),
),
),
ChangeNotifierProvider(
create: (context) => MzansiWalletProvider(),
create: (context) => MzansiWalletProvider(
MzansiWalletHiveData(),
),
),
ChangeNotifierProvider(
create: (context) => MzansiAiProvider(),

View file

@ -14,6 +14,7 @@ import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_employee.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart';
import 'package:mzansi_innovation_hub/mih_objects/user_consent.dart';
import 'package:pwa_install/pwa_install.dart';
@ -29,8 +30,10 @@ void main() async {
apiDomain: AppEnviroment.baseApiUrl,
apiBasePath: "/auth",
);
// Offine Hive Data
await Hive.initFlutter('mih_offline_storage');
Hive.registerAdapters();
// Mzansi Profile Data
await Hive.openBox<AppUser>('user_box');
await Hive.openBox<Business>('business_box');
await Hive.openBox<BusinessUser>('business_user_box');
@ -39,6 +42,9 @@ void main() async {
await Hive.openBox<ProfileLink>('personal_profile_links_box');
await Hive.openBox<ProfileLink>('business_profile_links_box');
await Hive.openBox<BusinessEmployee>('business_employees_box');
// Mzansi Wallet Data
await Hive.openBox<MIHLoyaltyCard>('loyalty_card_box');
await Hive.openBox<MIHLoyaltyCard>('fav_loyalty_card_box');
// await Firebase.initializeApp(
// // options: DefaultFirebaseOptions.currentPlatform,

View file

@ -4,6 +4,7 @@ import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_employee.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart';
import 'package:mzansi_innovation_hub/mih_objects/user_consent.dart';
@ -14,5 +15,6 @@ import 'package:mzansi_innovation_hub/mih_objects/user_consent.dart';
AdapterSpec<UserConsent>(),
AdapterSpec<ProfileLink>(),
AdapterSpec<BusinessEmployee>(),
AdapterSpec<MIHLoyaltyCard>(),
])
part 'hive_adapters.g.dart';

View file

@ -338,3 +338,55 @@ class BusinessEmployeeAdapter extends TypeAdapter<BusinessEmployee> {
runtimeType == other.runtimeType &&
typeId == other.typeId;
}
class MIHLoyaltyCardAdapter extends TypeAdapter<MIHLoyaltyCard> {
@override
final typeId = 6;
@override
MIHLoyaltyCard read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return MIHLoyaltyCard(
idloyalty_cards: (fields[0] as num).toInt(),
app_id: fields[1] as String,
shop_name: fields[2] as String,
card_number: fields[3] as String,
favourite: fields[4] as String,
priority_index: (fields[5] as num).toInt(),
nickname: fields[6] as String,
);
}
@override
void write(BinaryWriter writer, MIHLoyaltyCard obj) {
writer
..writeByte(7)
..writeByte(0)
..write(obj.idloyalty_cards)
..writeByte(1)
..write(obj.app_id)
..writeByte(2)
..write(obj.shop_name)
..writeByte(3)
..write(obj.card_number)
..writeByte(4)
..write(obj.favourite)
..writeByte(5)
..write(obj.priority_index)
..writeByte(6)
..write(obj.nickname);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is MIHLoyaltyCardAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View file

@ -1,7 +1,7 @@
# Generated by Hive CE
# Manual modifications may be necessary for certain migrations
# Check in to version control
nextTypeId: 6
nextTypeId: 7
types:
AppUser:
typeId: 0
@ -125,3 +125,21 @@ types:
index: 6
username:
index: 7
MIHLoyaltyCard:
typeId: 6
nextIndex: 7
fields:
idloyalty_cards:
index: 0
app_id:
index: 1
shop_name:
index: 2
card_number:
index: 3
favourite:
index: 4
priority_index:
index: 5
nickname:
index: 6

View file

@ -11,6 +11,7 @@ extension HiveRegistrar on HiveInterface {
registerAdapter(BusinessAdapter());
registerAdapter(BusinessEmployeeAdapter());
registerAdapter(BusinessUserAdapter());
registerAdapter(MIHLoyaltyCardAdapter());
registerAdapter(ProfileLinkAdapter());
registerAdapter(UserConsentAdapter());
}
@ -22,6 +23,7 @@ extension IsolatedHiveRegistrar on IsolatedHiveInterface {
registerAdapter(BusinessAdapter());
registerAdapter(BusinessEmployeeAdapter());
registerAdapter(BusinessUserAdapter());
registerAdapter(MIHLoyaltyCardAdapter());
registerAdapter(ProfileLinkAdapter());
registerAdapter(UserConsentAdapter());
}

View file

@ -0,0 +1,59 @@
import 'package:hive_ce_flutter/hive_ce_flutter.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart';
class MzansiWalletHiveData {
final Box<MIHLoyaltyCard> _loyaltyCardBox =
Hive.box<MIHLoyaltyCard>('loyalty_card_box');
final Box<MIHLoyaltyCard> _favLoyaltyCardBox =
Hive.box<MIHLoyaltyCard>('fav_loyalty_card_box');
// Get Offline Data
List<MIHLoyaltyCard> getCachedLoyaltyCards() {
final cards = _loyaltyCardBox.values.toList();
cards.sort((a, b) => a.shop_name.compareTo(b.shop_name));
return cards;
}
List<MIHLoyaltyCard> getCachedFavLoyaltyCards() {
final cards = _favLoyaltyCardBox.values.toList();
cards.sort((a, b) => a.shop_name.compareTo(b.shop_name));
return cards;
}
// Cache data for offline use
Future<void> cacheFavLoyaltyCardsData(
List<MIHLoyaltyCard> remoteLoyaltyCards) async {
await _favLoyaltyCardBox.clear();
await _favLoyaltyCardBox.addAll(remoteLoyaltyCards);
KenLogger.success("Favourite Loyalty Cards Cached");
}
Future<void> cacheLoyaltyCardsData(
List<MIHLoyaltyCard> remoteFavLoyaltyCards) async {
await _loyaltyCardBox.clear();
await _loyaltyCardBox.addAll(remoteFavLoyaltyCards);
KenLogger.success("Loyalty Cards Cached");
}
// Sync Local Data from data from MIH Server
Future<bool> syncWalletWithServer(
MzansiProfileProvider profileProvider) async {
try {
final remoteLoyaltyCards = await MIHMzansiWalletApis.getLoyaltyCardsV2(
profileProvider.user!.app_id);
cacheLoyaltyCardsData(remoteLoyaltyCards);
final remoteFavLoyaltyCards =
await MIHMzansiWalletApis.getFavouriteLoyaltyCardsV2(
profileProvider.user!.app_id);
cacheFavLoyaltyCardsData(remoteFavLoyaltyCards);
return true;
} catch (error) {
KenLogger.warning("App Operating in Offline Mode. Sync Paused");
return false;
// KenLogger.warning("App operating offline mode. Sync paused: $error");
}
}
}

View file

@ -20,50 +20,32 @@ class MihWallet extends StatefulWidget {
class _MihWalletState extends State<MihWallet> {
bool _isLoadingInitialData = true;
late final MihCards _cards;
late final MihCardFavourites _cardFavourites;
Future<void> _loadInitialData() async {
setState(() {
_isLoadingInitialData = true;
});
MzansiProfileProvider mzansiProfileProvider =
context.read<MzansiProfileProvider>();
mzansiProfileProvider.loadCachedProfileState();
MzansiWalletProvider walletProvider = context.read<MzansiWalletProvider>();
walletProvider.loadCachedWallet();
if (mzansiProfileProvider.user == null) {
await MihDataHelperServices().loadUserDataWithBusinessesData(
mzansiProfileProvider,
);
mzansiProfileProvider.syncWithMihServerData();
}
if (walletProvider.loyaltyCards.isEmpty) {
walletProvider.syncWithMihServerData(mzansiProfileProvider);
}
await setLoyaltyCards(mzansiProfileProvider, walletProvider);
await setFavouritesCards(mzansiProfileProvider, walletProvider);
setState(() {
_isLoadingInitialData = false;
});
}
Future<void> setLoyaltyCards(
MzansiProfileProvider mzansiProfileProvider,
MzansiWalletProvider walletProvider,
) async {
await MIHMzansiWalletApis.getLoyaltyCards(
walletProvider, mzansiProfileProvider.user!.app_id, context);
}
Future<void> setFavouritesCards(
MzansiProfileProvider mzansiProfileProvider,
MzansiWalletProvider walletProvider,
) async {
await MIHMzansiWalletApis.getFavouriteLoyaltyCards(
walletProvider, mzansiProfileProvider.user!.app_id, context);
}
@override
void initState() {
super.initState();
_cards = MihCards();
_cardFavourites = MihCardFavourites();
_loadInitialData();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
_loadInitialData();
}
});
}
@override
@ -122,8 +104,8 @@ class _MihWalletState extends State<MihWallet> {
List<Widget> getToolBody() {
return [
_cards,
_cardFavourites,
MihCards(),
MihCardFavourites(),
];
}

View file

@ -1,5 +1,6 @@
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:mih_package_toolkit/mih_package_toolkit.dart';
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
import 'package:mzansi_innovation_hub/mih_providers/mzansi_wallet_provider.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_add_card_window.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
@ -161,6 +162,37 @@ class _MihCardsState extends State<MihCards> {
onTap: () {
addCardWindow(context, width);
},
),
SpeedDialChild(
child: Icon(
Icons.cloud_sync_rounded,
color: MihColors.primary(),
),
label: "Sync Wallet",
labelBackgroundColor: MihColors.green(),
labelStyle: TextStyle(
color: MihColors.primary(),
fontWeight: FontWeight.bold,
),
backgroundColor: MihColors.green(),
onTap: () async {
MzansiProfileProvider profileProvider =
context.read<MzansiProfileProvider>();
bool success = await walletProvider
.syncWithMihServerData(profileProvider);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
MihSnackBar(
child: Text(
success
? "Wallet Synced with MIH Server."
: "MIH App operation in Offline Mode",
),
// backgroundColor: success ? null : MihColors.red(),
),
);
}
},
)
]),
)

View file

@ -1,17 +1,38 @@
import 'package:flutter/material.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:mzansi_innovation_hub/mih_hive/mzansi_wallet_hive_data.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
class MzansiWalletProvider extends ChangeNotifier {
final MzansiWalletHiveData _hiveData;
List<MIHLoyaltyCard> loyaltyCards;
List<MIHLoyaltyCard> favouriteCards;
int toolIndex;
MzansiWalletProvider({
MzansiWalletProvider(
this._hiveData, {
this.loyaltyCards = const [],
this.favouriteCards = const [],
this.toolIndex = 0,
});
void loadCachedWallet() {
loyaltyCards = _hiveData.getCachedLoyaltyCards();
favouriteCards = _hiveData.getCachedFavLoyaltyCards();
KenLogger.success("Mzansi Wallet Loaded from Cache");
notifyListeners();
}
Future<bool> syncWithMihServerData(
MzansiProfileProvider profileProvider) async {
bool success = await _hiveData.syncWalletWithServer(profileProvider);
loadCachedWallet();
return success;
}
void reset() {
toolIndex = 0;
loyaltyCards = [];

View file

@ -31,6 +31,21 @@ class MIHMzansiWalletApis {
}
}
static Future<List<MIHLoyaltyCard>> getLoyaltyCardsV2(
String app_id,
) async {
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/$app_id"));
if (response.statusCode == 200) {
Iterable l = jsonDecode(response.body);
List<MIHLoyaltyCard> myCards = List<MIHLoyaltyCard>.from(
l.map((model) => MIHLoyaltyCard.fromJson(model)));
return myCards;
} else {
throw Exception('failed to fatch loyalty cards');
}
}
static Future<void> getFavouriteLoyaltyCards(
MzansiWalletProvider walletProvider,
String app_id,
@ -44,10 +59,24 @@ class MIHMzansiWalletApis {
List<MIHLoyaltyCard> myCards = List<MIHLoyaltyCard>.from(
l.map((model) => MIHLoyaltyCard.fromJson(model)));
walletProvider.setFavouriteCards(cards: myCards);
} else {
throw Exception('failed to fatch loyalty cards');
}
}
static Future<List<MIHLoyaltyCard>> getFavouriteLoyaltyCardsV2(
String app_id,
) async {
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/favourites/$app_id"));
if (response.statusCode == 200) {
Iterable l = jsonDecode(response.body);
List<MIHLoyaltyCard> myCards = List<MIHLoyaltyCard>.from(
l.map((model) => MIHLoyaltyCard.fromJson(model)));
return myCards;
} else {
throw Exception('failed to fatch loyalty cards');
}
// else {
// throw Exception('failed to fatch loyalty cards');
// }
}
/// This function is used to Delete loyalty card from users mzansi wallet.