Complete Offline Wallet Display & Edit

This commit is contained in:
yaso 2026-06-30 16:21:47 +02:00
parent 6ad1ea613c
commit 04f034971f
21 changed files with 973 additions and 507 deletions

View file

@ -1,7 +1,7 @@
analyzer: analyzer:
exclude: exclude:
- lib/**/*.g.dart - lib/mih_hive/*.g.dart
- lib/**/hive_registrar.g.dart - lib/mih_hive/hive_registrar.g.dart
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml

View file

@ -1,10 +1,14 @@
targets: targets:
$default: $default:
builders: builders:
# Disable type adapter generator since we use GenerateAdapters in hive_adapters.dart
hive_ce_generator:hive_type_adapter_generator:
enabled: false
# 1. Restrict adapter generation to your mih_hive folder # 1. Restrict adapter generation to your mih_hive folder
hive_ce_generator:hive_adapters_generator: hive_ce_generator:hive_adapters_generator:
generate_for: generate_for:
- lib/mih_hive/*.dart - lib/mih_hive/hive_adapters.dart
# 2. Restrict registrar generation to your entry points # 2. Restrict registrar generation to your entry points
hive_ce_generator:hive_registrar_generator: hive_ce_generator:hive_registrar_generator:

View file

@ -11,6 +11,7 @@ import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_go_router.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_go_router.dart';
import 'package:mzansi_innovation_hub/mih_hive/hive_registrar.g.dart'; import 'package:mzansi_innovation_hub/mih_hive/hive_registrar.g.dart';
import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/appointment.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.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_employee.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/business_user.dart';
@ -45,7 +46,12 @@ void main() async {
// Mzansi Wallet Data // Mzansi Wallet Data
await Hive.openBox<MIHLoyaltyCard>('loyalty_card_box'); await Hive.openBox<MIHLoyaltyCard>('loyalty_card_box');
await Hive.openBox<MIHLoyaltyCard>('fav_loyalty_card_box'); await Hive.openBox<MIHLoyaltyCard>('fav_loyalty_card_box');
await Hive.openBox<Map>('wallet_modifications_queue');
// About MIH Data
await Hive.openBox<int>('about_mih_box'); await Hive.openBox<int>('about_mih_box');
// Mih Calendar Data
await Hive.openBox<Appointment>('personal_calendar_box');
await Hive.openBox<Appointment>('business_calendar_box');
// await Firebase.initializeApp( // await Firebase.initializeApp(
// // options: DefaultFirebaseOptions.currentPlatform, // // options: DefaultFirebaseOptions.currentPlatform,

View file

@ -1,6 +1,7 @@
// hive_adapters.dart // hive_adapters.dart
import 'package:hive_ce/hive_ce.dart'; import 'package:hive_ce/hive_ce.dart';
import 'package:mzansi_innovation_hub/mih_objects/app_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/appointment.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.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_employee.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_user.dart'; import 'package:mzansi_innovation_hub/mih_objects/business_user.dart';
@ -16,5 +17,6 @@ import 'package:mzansi_innovation_hub/mih_objects/user_consent.dart';
AdapterSpec<ProfileLink>(), AdapterSpec<ProfileLink>(),
AdapterSpec<BusinessEmployee>(), AdapterSpec<BusinessEmployee>(),
AdapterSpec<MIHLoyaltyCard>(), AdapterSpec<MIHLoyaltyCard>(),
AdapterSpec<Appointment>(),
]) ])
part 'hive_adapters.g.dart'; part 'hive_adapters.g.dart';

View file

@ -357,13 +357,14 @@ class MIHLoyaltyCardAdapter extends TypeAdapter<MIHLoyaltyCard> {
favourite: fields[4] as String, favourite: fields[4] as String,
priority_index: (fields[5] as num).toInt(), priority_index: (fields[5] as num).toInt(),
nickname: fields[6] as String, nickname: fields[6] as String,
offline_id: fields[7] as String?,
); );
} }
@override @override
void write(BinaryWriter writer, MIHLoyaltyCard obj) { void write(BinaryWriter writer, MIHLoyaltyCard obj) {
writer writer
..writeByte(7) ..writeByte(8)
..writeByte(0) ..writeByte(0)
..write(obj.idloyalty_cards) ..write(obj.idloyalty_cards)
..writeByte(1) ..writeByte(1)
@ -377,7 +378,9 @@ class MIHLoyaltyCardAdapter extends TypeAdapter<MIHLoyaltyCard> {
..writeByte(5) ..writeByte(5)
..write(obj.priority_index) ..write(obj.priority_index)
..writeByte(6) ..writeByte(6)
..write(obj.nickname); ..write(obj.nickname)
..writeByte(7)
..write(obj.offline_id);
} }
@override @override
@ -390,3 +393,52 @@ class MIHLoyaltyCardAdapter extends TypeAdapter<MIHLoyaltyCard> {
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
typeId == other.typeId; typeId == other.typeId;
} }
class AppointmentAdapter extends TypeAdapter<Appointment> {
@override
final typeId = 7;
@override
Appointment read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return Appointment(
idappointments: (fields[0] as num).toInt(),
app_id: fields[1] as String,
business_id: fields[2] as String,
date_time: fields[3] as String,
title: fields[4] as String,
description: fields[5] as String,
);
}
@override
void write(BinaryWriter writer, Appointment obj) {
writer
..writeByte(6)
..writeByte(0)
..write(obj.idappointments)
..writeByte(1)
..write(obj.app_id)
..writeByte(2)
..write(obj.business_id)
..writeByte(3)
..write(obj.date_time)
..writeByte(4)
..write(obj.title)
..writeByte(5)
..write(obj.description);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is AppointmentAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View file

@ -1,7 +1,7 @@
# Generated by Hive CE # Generated by Hive CE
# Manual modifications may be necessary for certain migrations # Manual modifications may be necessary for certain migrations
# Check in to version control # Check in to version control
nextTypeId: 7 nextTypeId: 8
types: types:
AppUser: AppUser:
typeId: 0 typeId: 0
@ -127,7 +127,7 @@ types:
index: 7 index: 7
MIHLoyaltyCard: MIHLoyaltyCard:
typeId: 6 typeId: 6
nextIndex: 7 nextIndex: 8
fields: fields:
idloyalty_cards: idloyalty_cards:
index: 0 index: 0
@ -143,3 +143,21 @@ types:
index: 5 index: 5
nickname: nickname:
index: 6 index: 6
offline_id:
index: 7
Appointment:
typeId: 7
nextIndex: 6
fields:
idappointments:
index: 0
app_id:
index: 1
business_id:
index: 2
date_time:
index: 3
title:
index: 4
description:
index: 5

View file

@ -0,0 +1,33 @@
import 'package:hive_ce_flutter/hive_ce_flutter.dart';
import 'package:mzansi_innovation_hub/mih_objects/appointment.dart';
class MihCalendarHiveData {
final Box<Appointment> _personalAppointmentBox =
Hive.box<Appointment>('personal_calendar_box');
final Box<Appointment> _businessAppointmentBox =
Hive.box<Appointment>('business_calendar_box');
List<Appointment> getCachedPersonalAppointments() {
final appointments = _personalAppointmentBox.values.toList();
appointments.sort((a, b) {
final dateA = DateTime.parse(a.date_time);
final dateB = DateTime.parse(b.date_time);
return dateB.compareTo(dateA);
});
return appointments;
}
List<Appointment> getCachedBusinessAppointments() {
final appointments = _businessAppointmentBox.values.toList();
appointments.sort((a, b) {
final dateA = DateTime.parse(a.date_time);
final dateB = DateTime.parse(b.date_time);
return dateB.compareTo(dateA);
});
return appointments;
}
Future<bool> syncCalendarDataWithServer() async {
return false;
}
}

View file

@ -3,12 +3,15 @@ import 'package:ken_logger/ken_logger.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.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_providers/mzansi_profile_provider.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart';
import 'package:uuid/uuid.dart';
class MzansiWalletHiveData { class MzansiWalletHiveData {
final Box<MIHLoyaltyCard> _loyaltyCardBox = final Box<MIHLoyaltyCard> _loyaltyCardBox =
Hive.box<MIHLoyaltyCard>('loyalty_card_box'); Hive.box<MIHLoyaltyCard>('loyalty_card_box');
final Box<MIHLoyaltyCard> _favLoyaltyCardBox = final Box<MIHLoyaltyCard> _favLoyaltyCardBox =
Hive.box<MIHLoyaltyCard>('fav_loyalty_card_box'); Hive.box<MIHLoyaltyCard>('fav_loyalty_card_box');
final Box<Map> _modificationsQueue =
Hive.box<Map>('wallet_modifications_queue');
// Get Offline Data // Get Offline Data
List<MIHLoyaltyCard> getCachedLoyaltyCards() { List<MIHLoyaltyCard> getCachedLoyaltyCards() {
@ -19,10 +22,116 @@ class MzansiWalletHiveData {
List<MIHLoyaltyCard> getCachedFavLoyaltyCards() { List<MIHLoyaltyCard> getCachedFavLoyaltyCards() {
final cards = _favLoyaltyCardBox.values.toList(); final cards = _favLoyaltyCardBox.values.toList();
cards.sort((a, b) => a.shop_name.compareTo(b.shop_name)); cards.sort((a, b) => a.priority_index.compareTo(b.priority_index));
return cards; return cards;
} }
// Set Offline Data
Future<void> addLoyaltyCardLocally(MIHLoyaltyCard newCard) async {
await _loyaltyCardBox.put(newCard.offline_id, newCard);
if (newCard.favourite == "Yes") {
await _favLoyaltyCardBox.put(newCard.offline_id, newCard);
}
KenLogger.success("New Card Saved Locally.");
}
Future<void> deleteLoyaltyCardLocally(MIHLoyaltyCard deleteCard) async {
dynamic mainTargetKey;
dynamic favTargetKey;
for (var key in _loyaltyCardBox.keys) {
final card = _loyaltyCardBox.get(key);
if (card != null) {
if (deleteCard.idloyalty_cards != 0 &&
card.idloyalty_cards == deleteCard.idloyalty_cards) {
mainTargetKey = key;
break;
} else if (deleteCard.idloyalty_cards == 0 &&
card.offline_id == deleteCard.offline_id) {
mainTargetKey = key;
break;
}
}
}
for (var key in _favLoyaltyCardBox.keys) {
final card = _favLoyaltyCardBox.get(key);
if (card != null) {
if (deleteCard.idloyalty_cards != 0 &&
card.idloyalty_cards == deleteCard.idloyalty_cards) {
favTargetKey = key;
break;
} else if (deleteCard.idloyalty_cards == 0 &&
card.offline_id == deleteCard.offline_id) {
favTargetKey = key;
break;
}
}
}
if (mainTargetKey != null) {
await _loyaltyCardBox.delete(mainTargetKey);
KenLogger.success("Card Deleted Locally.");
}
if (favTargetKey != null) {
await _favLoyaltyCardBox.delete(favTargetKey);
KenLogger.success("Fav Card Deleted Locally.");
}
}
Future<void> updateLoyaltyCardLocally(MIHLoyaltyCard updatedCard) async {
dynamic mainTargetKey;
dynamic favTargetKey;
for (var key in _loyaltyCardBox.keys) {
final card = _loyaltyCardBox.get(key);
if (card != null) {
if (updatedCard.idloyalty_cards != 0 &&
card.idloyalty_cards == updatedCard.idloyalty_cards) {
mainTargetKey = key;
break;
} else if (updatedCard.idloyalty_cards == 0 &&
card.offline_id == updatedCard.offline_id) {
mainTargetKey = key;
break;
}
}
}
for (var key in _favLoyaltyCardBox.keys) {
final card = _favLoyaltyCardBox.get(key);
if (card != null) {
if (updatedCard.idloyalty_cards != 0 &&
card.idloyalty_cards == updatedCard.idloyalty_cards) {
favTargetKey = key;
break;
} else if (updatedCard.idloyalty_cards == 0 &&
card.offline_id == updatedCard.offline_id) {
favTargetKey = key;
break;
}
}
}
if (mainTargetKey != null) {
await _loyaltyCardBox.put(mainTargetKey, updatedCard);
KenLogger.success("Card Udpdated Locally.");
}
if (favTargetKey != null) {
if (updatedCard.favourite == "Yes") {
await _favLoyaltyCardBox.put(favTargetKey, updatedCard);
KenLogger.success("Fav Card Updated Locally.");
} else {
await _favLoyaltyCardBox.delete(favTargetKey);
KenLogger.success("Fav Card Removed Locally.");
}
} else {
if (updatedCard.offline_id == null) {
final String uniqueKey = const Uuid().v4();
await _favLoyaltyCardBox.put(uniqueKey, updatedCard);
KenLogger.success("Fav Card Added Locally.");
} else {
await _favLoyaltyCardBox.put(updatedCard.offline_id, updatedCard);
KenLogger.success("Fav Card Added Locally.");
}
}
}
// Cache data for offline use // Cache data for offline use
Future<void> cacheFavLoyaltyCardsData( Future<void> cacheFavLoyaltyCardsData(
List<MIHLoyaltyCard> remoteLoyaltyCards) async { List<MIHLoyaltyCard> remoteLoyaltyCards) async {
@ -51,9 +160,122 @@ class MzansiWalletHiveData {
cacheFavLoyaltyCardsData(remoteFavLoyaltyCards); cacheFavLoyaltyCardsData(remoteFavLoyaltyCards);
return true; return true;
} catch (error) { } catch (error) {
KenLogger.warning("MIH App Operating in Offline Mode. Sync Paused"); KenLogger.warning("MIH App Operating in Offline Mode. Sync Paused.");
return false; return false;
// KenLogger.warning("App operating offline mode. Sync paused: $error"); // KenLogger.warning("App operating offline mode. Sync paused: $error");
} }
} }
// Modicfications processing
Future<void> queueAddModification(MIHLoyaltyCard newCardData) async {
await _modificationsQueue.add({
'action': 'ADD',
'payload': newCardData,
});
KenLogger.warning("Add Card Queued For Online Sync");
}
Future<void> queueDeleteModification(MIHLoyaltyCard deleteCardData) async {
await _modificationsQueue.add({
'action': 'DELETE',
'payload': deleteCardData,
});
KenLogger.warning("Delete Card Queued For Online Sync");
}
Future<void> queueUpdateModification(MIHLoyaltyCard updatedCardData) async {
await _modificationsQueue.add({
'action': 'UPDATE',
'payload': updatedCardData,
});
KenLogger.warning("Update Card Queued For Online Sync");
}
Future<bool> processModificationsQueue(
MzansiProfileProvider profileProvider) async {
if (_modificationsQueue.isEmpty) {
return true;
}
final List<dynamic> queueKeys = _modificationsQueue.keys.toList();
for (var taskKey in queueKeys) {
final task = _modificationsQueue.get(taskKey);
if (task == null) {
continue;
}
final String action = task['action'];
final MIHLoyaltyCard taskCard = task['payload'];
KenLogger.warning(
"Card Details: id=${taskCard.idloyalty_cards}, shop=${taskCard.shop_name}, Nunber=${taskCard.card_number}, offline_id=${taskCard.offline_id}");
if (action == 'ADD') {
dynamic deleteCardTaskKey;
for (var entry in _modificationsQueue.toMap().entries) {
if (entry.value['action'] == 'DELETE' &&
entry.value['payload'].offline_id == taskCard.offline_id) {
deleteCardTaskKey = entry.key;
break;
}
}
if (deleteCardTaskKey != null) {
await _modificationsQueue.delete(taskKey); // Remove 'ADD'
await _modificationsQueue
.delete(deleteCardTaskKey); // Remove 'DELETE'
KenLogger.success(
"Offline add & delete cancelled out. Queue cleaned.");
continue;
}
final responseCode = await MIHMzansiWalletApis.addLoyaltyCardAPICallV2(
profileProvider.user!.app_id,
taskCard.shop_name,
taskCard.card_number,
taskCard.favourite,
taskCard.priority_index,
taskCard.nickname,
);
if (responseCode != null && responseCode == 201) {
await _modificationsQueue.delete(taskKey);
KenLogger.success("Add New Local Card to MIH Server");
} else {
KenLogger.warning("MIH App Operating in Offline Mode. Sync Paused");
return false;
}
}
if (action == 'DELETE') {
final responseCode =
await MIHMzansiWalletApis.deleteLoyaltyCardAPICallV2(
taskCard.idloyalty_cards,
);
if (responseCode != null && responseCode == 200) {
await _modificationsQueue.delete(taskKey);
KenLogger.success("Delete Local Card from MIH Server");
} else {
KenLogger.warning("MIH App Operating in Offline Mode. Sync Paused");
return false;
}
}
if (action == 'UPDATE') {
final responseCode =
await MIHMzansiWalletApis.updateLoyaltyCardAPICallV2(
taskCard.idloyalty_cards,
taskCard.favourite,
taskCard.priority_index,
taskCard.nickname,
taskCard.card_number,
);
if (responseCode != null && responseCode == 200) {
await _modificationsQueue.delete(taskKey);
KenLogger.success("Update Local Card from MIH Server");
} else {
KenLogger.warning("MIH App Operating in Offline Mode. Sync Paused");
return false;
}
}
}
return true;
}
bool isModificationNotEmpty() {
return _modificationsQueue.values.toList().isNotEmpty;
}
} }

View file

@ -6,6 +6,7 @@ class MIHLoyaltyCard {
final String favourite; final String favourite;
final int priority_index; final int priority_index;
final String nickname; final String nickname;
final String? offline_id;
const MIHLoyaltyCard({ const MIHLoyaltyCard({
required this.idloyalty_cards, required this.idloyalty_cards,
@ -15,6 +16,7 @@ class MIHLoyaltyCard {
required this.favourite, required this.favourite,
required this.priority_index, required this.priority_index,
required this.nickname, required this.nickname,
this.offline_id,
}); });
factory MIHLoyaltyCard.fromJson(Map<String, dynamic> json) { factory MIHLoyaltyCard.fromJson(Map<String, dynamic> json) {

View file

@ -24,8 +24,6 @@ class _MzansiAiState extends State<MzansiAi> {
mzansiProfileProvider.loadCachedProfileState(); mzansiProfileProvider.loadCachedProfileState();
if (mzansiProfileProvider.user == null) { if (mzansiProfileProvider.user == null) {
await mzansiProfileProvider.syncWithMihServerData(); await mzansiProfileProvider.syncWithMihServerData();
} else {
await mzansiProfileProvider.syncWithMihServerData();
} }
} }

View file

@ -11,7 +11,6 @@ import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.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_providers/mzansi_wallet_provider.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart'; import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart';
@ -130,19 +129,20 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
child: MihButton( child: MihButton(
onPressed: () async { onPressed: () async {
if (_formKey.currentState!.validate()) { if (_formKey.currentState!.validate()) {
int statusCode = await MIHMzansiWalletApis walletProvider.updateLocalLoyaltyCard(
.updateLoyaltyCardAPICall( mzansiProfileProvider,
walletProvider, MIHLoyaltyCard(
mzansiProfileProvider.user!, idloyalty_cards:
widget.cardList[index].idloyalty_cards, widget.cardList[index].idloyalty_cards,
widget.cardList[index].shop_name, app_id: widget.cardList[index].app_id,
widget.cardList[index].favourite, shop_name: widget.cardList[index].shop_name,
card_number: _cardNumberController.text,
favourite: widget.cardList[index].favourite,
priority_index:
widget.cardList[index].priority_index, widget.cardList[index].priority_index,
_nicknameController.text, nickname: _nicknameController.text,
_cardNumberController.text, ),
ctxt,
); );
if (statusCode == 200) {
context.pop(); context.pop();
context.pop(); context.pop();
MihAlertServices().successBasicAlert( MihAlertServices().successBasicAlert(
@ -150,9 +150,6 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
"You have successfully updated the loyalty card details.", "You have successfully updated the loyalty card details.",
context, context,
); );
} else {
MihAlertServices().internetConnectionAlert(context);
}
} else { } else {
MihAlertServices().inputErrorAlert(context); MihAlertServices().inputErrorAlert(context);
} }
@ -183,13 +180,10 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
MihAlertServices().deleteConfirmationAlert( MihAlertServices().deleteConfirmationAlert(
"This Card will be deleted permanently from your Mzansi Wallet. Are you certain you want to delete it?", "This Card will be deleted permanently from your Mzansi Wallet. Are you certain you want to delete it?",
() async { () async {
int statusCode = await MIHMzansiWalletApis.deleteLoyaltyCardAPICall( walletProvider.deleteLocalLoyaltyCard(
walletProvider, mzansiProfileProvider,
mzansiProfileProvider.user!, widget.cardList[index],
widget.cardList[index].idloyalty_cards,
context,
); );
if (statusCode == 200) {
context.pop(); context.pop();
context.pop(); context.pop();
MihAlertServices().successBasicAlert( MihAlertServices().successBasicAlert(
@ -197,10 +191,6 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
"You have successfully deleted the loyalty card from your Mzansi Wallet.", "You have successfully deleted the loyalty card from your Mzansi Wallet.",
context, context,
); );
} else {
context.pop();
MihAlertServices().internetConnectionAlert(context);
}
}, },
context, context,
); );
@ -231,34 +221,26 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
), ),
MihButton( MihButton(
onPressed: () async { onPressed: () async {
int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( await walletProvider.updateLocalLoyaltyCard(
walletProvider, mzansiProfileProvider,
mzansiProfileProvider.user!, MIHLoyaltyCard(
widget.cardList[index].idloyalty_cards, idloyalty_cards: widget.cardList[index].idloyalty_cards,
widget.cardList[index].shop_name, app_id: widget.cardList[index].app_id,
"Yes", shop_name: widget.cardList[index].shop_name,
_noFavourites, card_number: widget.cardList[index].card_number,
widget.cardList[index].nickname, favourite: "Yes",
widget.cardList[index].card_number, priority_index: _noFavourites,
ctxt, nickname: widget.cardList[index].nickname,
),
); );
if (statusCode == 200) {
context.pop(); context.pop();
context.pop(); context.pop();
await MIHMzansiWalletApis.getFavouriteLoyaltyCards(
walletProvider,
mzansiProfileProvider.user!.app_id,
context,
);
context.read<MzansiWalletProvider>().setToolIndex(1); context.read<MzansiWalletProvider>().setToolIndex(1);
MihAlertServices().successBasicAlert( MihAlertServices().successBasicAlert(
"Success!", "Success!",
"You have successfully added the loyalty card to your favourites.", "You have successfully added the loyalty card to your favourites.",
context, context,
); );
} else {
MihAlertServices().internetConnectionAlert(context);
}
}, },
buttonColor: MihColors.green(), buttonColor: MihColors.green(),
width: 300, width: 300,
@ -284,34 +266,26 @@ class _BuildLoyaltyCardListState extends State<BuildLoyaltyCardList> {
[ [
MihButton( MihButton(
onPressed: () async { onPressed: () async {
int statusCode = await MIHMzansiWalletApis.updateLoyaltyCardAPICall( await walletProvider.updateLocalLoyaltyCard(
walletProvider, mzansiProfileProvider,
mzansiProfileProvider.user!, MIHLoyaltyCard(
widget.cardList[index].idloyalty_cards, idloyalty_cards: widget.cardList[index].idloyalty_cards,
widget.cardList[index].shop_name, app_id: widget.cardList[index].app_id,
"", shop_name: widget.cardList[index].shop_name,
0, card_number: widget.cardList[index].card_number,
widget.cardList[index].nickname, favourite: "",
widget.cardList[index].card_number, priority_index: 0,
ctxt, nickname: widget.cardList[index].nickname,
),
); );
if (statusCode == 200) {
context.pop(); context.pop();
context.pop(); context.pop();
await MIHMzansiWalletApis.getFavouriteLoyaltyCards(
walletProvider,
mzansiProfileProvider.user!.app_id,
context,
);
context.read<MzansiWalletProvider>().setToolIndex(0); context.read<MzansiWalletProvider>().setToolIndex(0);
MihAlertServices().successBasicAlert( MihAlertServices().successBasicAlert(
"Success!", "Success!",
"You have successfully removed the loyalty card to your favourites.", "You have successfully removed the loyalty card to your favourites.",
context, context,
); );
} else {
MihAlertServices().internetConnectionAlert(context);
}
}, },
buttonColor: MihColors.red(), buttonColor: MihColors.red(),
width: 300, width: 300,

View file

@ -3,13 +3,14 @@ import 'package:go_router/go_router.dart';
import 'package:ken_logger/ken_logger.dart'; import 'package:ken_logger/ken_logger.dart';
import 'package:mih_package_toolkit/mih_package_toolkit.dart'; import 'package:mih_package_toolkit/mih_package_toolkit.dart';
import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/main.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_providers/mzansi_profile_provider.dart';
import 'package:mzansi_innovation_hub/mih_providers/mzansi_wallet_provider.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_wallet_provider.dart';
import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_wallet/components/mih_card_display.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_wallet_services.dart';
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
class MihAddCardWindow extends StatefulWidget { class MihAddCardWindow extends StatefulWidget {
const MihAddCardWindow({ const MihAddCardWindow({
@ -58,6 +59,38 @@ class _MihAddCardWindowState extends State<MihAddCardWindow> {
} }
} }
void addLoyaltyCard(MzansiProfileProvider profileProvider,
MzansiWalletProvider walletProvider) async {
if (_formKey.currentState!.validate()) {
if (_shopController.text == "") {
MihAlertServices().inputErrorAlert(context);
} else {
final String uniqueKey = const Uuid().v4();
MIHLoyaltyCard newCard = MIHLoyaltyCard(
idloyalty_cards: 0,
app_id: profileProvider.user!.app_id,
shop_name: _shopController.text,
card_number: _cardNumberController.text,
favourite: "No",
priority_index: 0,
nickname: _nicknameController.text,
offline_id: uniqueKey,
);
await walletProvider.addLocalLoyaltyCard(profileProvider, newCard);
context.pop();
KenLogger.success("Card Added Successfully");
successPopUp(
"Successfully Added Card",
"The loyalty card has been added to your favourites.",
0,
);
}
} else {
MihAlertServices().inputErrorAlert(context);
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final double width = MediaQuery.sizeOf(context).width; final double width = MediaQuery.sizeOf(context).width;
@ -224,38 +257,7 @@ class _MihAddCardWindowState extends State<MihAddCardWindow> {
Center( Center(
child: MihButton( child: MihButton(
onPressed: () async { onPressed: () async {
if (_formKey.currentState!.validate()) { addLoyaltyCard(mzansiProfileProvider, walletProvider);
if (_shopController.text == "") {
MihAlertServices().inputErrorAlert(context);
} else {
int statusCode = await MIHMzansiWalletApis
.addLoyaltyCardAPICall(
walletProvider,
mzansiProfileProvider.user!,
mzansiProfileProvider.user!.app_id,
_shopController.text,
_cardNumberController.text,
"",
0,
_nicknameController.text,
context,
);
if (statusCode == 201) {
context.pop();
KenLogger.success("Card Added Successfully");
successPopUp(
"Successfully Added Card",
"The loyalty card has been added to your favourites.",
0,
);
} else {
MihAlertServices()
.internetConnectionAlert(context);
}
}
} else {
MihAlertServices().inputErrorAlert(context);
}
}, },
buttonColor: MihColors.green(), buttonColor: MihColors.green(),
width: 300, width: 300,

View file

@ -28,7 +28,8 @@ class _MihWalletState extends State<MihWallet> {
if (mzansiProfileProvider.user == null) { if (mzansiProfileProvider.user == null) {
mzansiProfileProvider.syncWithMihServerData(); mzansiProfileProvider.syncWithMihServerData();
} }
if (walletProvider.loyaltyCards.isEmpty) { if (walletProvider.loyaltyCards.isEmpty ||
walletProvider.isLocalModificationsPending()) {
walletProvider.syncWithMihServerData(mzansiProfileProvider); walletProvider.syncWithMihServerData(mzansiProfileProvider);
} }
setState(() { setState(() {

View file

@ -28,11 +28,42 @@ class MzansiWalletProvider extends ChangeNotifier {
Future<bool> syncWithMihServerData( Future<bool> syncWithMihServerData(
MzansiProfileProvider profileProvider) async { MzansiProfileProvider profileProvider) async {
await _hiveData.processModificationsQueue(profileProvider);
bool success = await _hiveData.syncWalletWithServer(profileProvider); bool success = await _hiveData.syncWalletWithServer(profileProvider);
loadCachedWallet(); loadCachedWallet();
return success; return success;
} }
Future<void> addLocalLoyaltyCard(
MzansiProfileProvider profileProvider, MIHLoyaltyCard newCard) async {
await _hiveData.addLoyaltyCardLocally(newCard);
await _hiveData.queueAddModification(newCard);
await _hiveData.processModificationsQueue(profileProvider);
await _hiveData.syncWalletWithServer(profileProvider);
loadCachedWallet();
}
Future<void> deleteLocalLoyaltyCard(
MzansiProfileProvider profileProvider, MIHLoyaltyCard deleteCard) async {
await _hiveData.deleteLoyaltyCardLocally(deleteCard);
await _hiveData.queueDeleteModification(deleteCard);
loadCachedWallet();
_hiveData.processModificationsQueue(profileProvider);
}
bool isLocalModificationsPending() {
return _hiveData.isModificationNotEmpty();
}
Future<void> updateLocalLoyaltyCard(
MzansiProfileProvider profileProvider, MIHLoyaltyCard updatedCard) async {
await _hiveData.updateLoyaltyCardLocally(updatedCard);
await _hiveData.queueUpdateModification(updatedCard);
await _hiveData.processModificationsQueue(profileProvider);
await _hiveData.syncWalletWithServer(profileProvider);
loadCachedWallet();
}
void reset() { void reset() {
toolIndex = 0; toolIndex = 0;
loyaltyCards = []; loyaltyCards = [];

View file

@ -40,6 +40,25 @@ class MihMzansiCalendarApis {
} }
} }
static Future<int> getPersonalAppointmentsV2(
String app_id,
String date,
MihCalendarProvider mihCalendarProvider,
) async {
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/appointments/personal/$app_id?date=$date"));
if (response.statusCode == 200) {
Iterable l = jsonDecode(response.body);
List<Appointment> personalAppointments =
List<Appointment>.from(l.map((model) => Appointment.fromJson(model)));
mihCalendarProvider.setPersonalAppointments(
appointments: personalAppointments);
return response.statusCode;
} else {
throw Exception('failed to fatch personal appointments');
}
}
/// This function is used to fetch a list of appointment for a personal user. /// This function is used to fetch a list of appointment for a personal user.
/// ///
/// Patameters: /// Patameters:

View file

@ -127,6 +127,32 @@ class MIHMzansiWalletApis {
// } // }
} }
/// This function is used to Delete loyalty card from users mzansi wallet.
///
/// Patameters:-
/// AppUser signedInUser,
/// int idloyalty_cards,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS)
static Future<int?> deleteLoyaltyCardAPICallV2(
int idloyalty_cards,
) async {
try {
var response = await http.delete(
Uri.parse(
"${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/delete/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{"idloyalty_cards": idloyalty_cards}),
);
return response.statusCode;
} catch (error) {
return null;
}
}
/// This function is used to add a lopyalty card to users mzansi wallet. /// This function is used to add a lopyalty card to users mzansi wallet.
/// ///
/// Patameters:- /// Patameters:-
@ -187,6 +213,48 @@ class MIHMzansiWalletApis {
// } // }
} }
/// This function is used to add a lopyalty card to users mzansi wallet.
///
/// Patameters:-
/// AppUser signedInUser,
/// String app_id,
/// String shop_name,
/// String card_number,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS SUCCESS pop up)
static Future<int?> addLoyaltyCardAPICallV2(
String app_id,
String shop_name,
String card_number,
String favourite,
int priority_index,
String nickname,
) async {
try {
var response = await http
.post(
Uri.parse(
"${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": app_id,
"shop_name": shop_name,
"card_number": card_number,
"favourite": favourite,
"priority_index": priority_index,
"nickname": nickname,
}),
)
.timeout(const Duration(seconds: 5));
return response.statusCode;
} catch (error) {
return null;
}
}
/// This function is used to Update loyalty card from users mzansi wallet. /// This function is used to Update loyalty card from users mzansi wallet.
/// ///
/// Patameters:- /// Patameters:-
@ -238,6 +306,42 @@ class MIHMzansiWalletApis {
return response.statusCode; return response.statusCode;
} }
/// This function is used to Update loyalty card from users mzansi wallet.
///
/// Patameters:-
/// AppUser signedInUser,
/// int idloyalty_cards,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS)
static Future<int?> updateLoyaltyCardAPICallV2(
int idloyalty_cards,
String favourite,
int priority_index,
String nickname,
String card_number,
) async {
try {
var response = await http.put(
Uri.parse(
"${AppEnviroment.baseApiUrl}/mzasni-wallet/loyalty-cards/update/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"idloyalty_cards": idloyalty_cards,
"favourite": favourite,
"priority_index": priority_index,
"nickname": nickname,
"card_number": card_number,
}),
);
return response.statusCode;
} catch (error) {
return null;
}
}
//================== POP UPS ========================================================================== //================== POP UPS ==========================================================================
static void loadingPopUp(BuildContext context) { static void loadingPopUp(BuildContext context) {

View file

@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
jni
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)

View file

@ -10,6 +10,7 @@ import device_info_plus
import file_picker import file_picker
import file_saver import file_saver
import file_selector_macos import file_selector_macos
import firebase_ai
import firebase_app_check import firebase_app_check
import firebase_auth import firebase_auth
import firebase_core import firebase_core
@ -18,7 +19,6 @@ import geolocator_apple
import local_auth_darwin import local_auth_darwin
import mobile_scanner import mobile_scanner
import package_info_plus import package_info_plus
import path_provider_foundation
import printing import printing
import record_macos import record_macos
import screen_brightness_macos import screen_brightness_macos
@ -35,15 +35,15 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin")) FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin")) FirebaseAIPlugin.register(with: registry.registrar(forPlugin: "FirebaseAIPlugin"))
FirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FirebaseAppCheckPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin")) LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin")) PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin")) RecordMacOsPlugin.register(with: registry.registrar(forPlugin: "RecordMacOsPlugin"))
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@
#include <file_saver/file_saver_plugin.h> #include <file_saver/file_saver_plugin.h>
#include <file_selector_windows/file_selector_windows.h> #include <file_selector_windows/file_selector_windows.h>
#include <firebase_app_check/firebase_app_check_plugin_c_api.h>
#include <firebase_auth/firebase_auth_plugin_c_api.h> #include <firebase_auth/firebase_auth_plugin_c_api.h>
#include <firebase_core/firebase_core_plugin_c_api.h> #include <firebase_core/firebase_core_plugin_c_api.h>
#include <fl_downloader/fl_downloader_plugin_c_api.h> #include <fl_downloader/fl_downloader_plugin_c_api.h>
@ -16,7 +17,7 @@
#include <local_auth_windows/local_auth_plugin.h> #include <local_auth_windows/local_auth_plugin.h>
#include <printing/printing_plugin.h> #include <printing/printing_plugin.h>
#include <record_windows/record_windows_plugin_c_api.h> #include <record_windows/record_windows_plugin_c_api.h>
#include <screen_brightness_windows/screen_brightness_windows_plugin.h> #include <screen_brightness_windows/screen_brightness_windows_plugin_c_api.h>
#include <share_plus/share_plus_windows_plugin_c_api.h> #include <share_plus/share_plus_windows_plugin_c_api.h>
#include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h> #include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
@ -26,6 +27,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FileSaverPlugin")); registry->GetRegistrarForPlugin("FileSaverPlugin"));
FileSelectorWindowsRegisterWithRegistrar( FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows")); registry->GetRegistrarForPlugin("FileSelectorWindows"));
FirebaseAppCheckPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseAppCheckPluginCApi"));
FirebaseAuthPluginCApiRegisterWithRegistrar( FirebaseAuthPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi")); registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
FirebaseCorePluginCApiRegisterWithRegistrar( FirebaseCorePluginCApiRegisterWithRegistrar(
@ -42,8 +45,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("PrintingPlugin")); registry->GetRegistrarForPlugin("PrintingPlugin"));
RecordWindowsPluginCApiRegisterWithRegistrar( RecordWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); registry->GetRegistrarForPlugin("RecordWindowsPluginCApi"));
ScreenBrightnessWindowsPluginRegisterWithRegistrar( ScreenBrightnessWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPluginCApi"));
SharePlusWindowsPluginCApiRegisterWithRegistrar( SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar( SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar(

View file

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
file_saver file_saver
file_selector_windows file_selector_windows
firebase_app_check
firebase_auth firebase_auth
firebase_core firebase_core
fl_downloader fl_downloader
@ -20,6 +21,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
) )
list(APPEND FLUTTER_FFI_PLUGIN_LIST list(APPEND FLUTTER_FFI_PLUGIN_LIST
jni
) )
set(PLUGIN_BUNDLED_LIBRARIES) set(PLUGIN_BUNDLED_LIBRARIES)