Compare commits
11 Commits
63263801af
...
6245aa9ef4
| Author | SHA1 | Date |
|---|---|---|
|
|
6245aa9ef4 | 2 years ago |
|
|
98b35fbc61 | 2 years ago |
|
|
c5cefa2309 | 2 years ago |
|
|
76fd46c654 | 2 years ago |
|
|
08fd442a36 | 2 years ago |
|
|
95fec1e62d | 2 years ago |
|
|
8168e5a81d | 2 years ago |
|
|
fd6b7c2803 | 2 years ago |
|
|
b9a5429de5 | 2 years ago |
|
|
8a8efa37f2 | 2 years ago |
|
|
057a202ed9 | 2 years ago |
@ -1,44 +0,0 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final account = accountFromJson(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:mc_common_app/models/parent_list.dart';
|
||||
|
||||
|
||||
|
||||
|
||||
Account accountFromJson(String str) => Account.fromJson(json.decode(str));
|
||||
|
||||
String accountToJson(Account data) => json.encode(data.toJson());
|
||||
|
||||
class Account {
|
||||
Account({
|
||||
required this.parentList,
|
||||
required this.selectedItem,
|
||||
});
|
||||
|
||||
List<ParentList>? parentList;
|
||||
int selectedItem;
|
||||
|
||||
factory Account.fromJson(Map<String, dynamic> json) => Account(
|
||||
parentList: json["parentList"] == null
|
||||
? null
|
||||
: List<ParentList>.from(
|
||||
json["parentList"].map((x) => ParentList.fromJson(x))),
|
||||
selectedItem:
|
||||
json["selectedItem"] == null ? null : json["selectedItem"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"parentList": parentList == null
|
||||
? null
|
||||
: List<dynamic>.from(parentList!.map((x) => x.toJson())),
|
||||
"selectedItem": selectedItem == null ? null : selectedItem,
|
||||
};
|
||||
|
||||
Map<String, dynamic> toJsonData() => {
|
||||
"selectedItem": selectedItem == null ? null : selectedItem,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
class AdsBankDetailsModel {
|
||||
int? id;
|
||||
int? mcBankAccountID;
|
||||
int? adsID;
|
||||
bool? isActive;
|
||||
String? bankName;
|
||||
String? iban;
|
||||
|
||||
AdsBankDetailsModel({this.id, this.mcBankAccountID, this.adsID, this.isActive, this.bankName, this.iban});
|
||||
|
||||
AdsBankDetailsModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
mcBankAccountID = json['mcBankAccountID'];
|
||||
adsID = json['adsID'];
|
||||
isActive = json['isActive'];
|
||||
bankName = json['bankName'];
|
||||
iban = json['iban'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['mcBankAccountID'] = mcBankAccountID;
|
||||
data['adsID'] = adsID;
|
||||
data['isActive'] = isActive;
|
||||
data['bankName'] = bankName;
|
||||
data['iban'] = iban;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
class PhotoSpecialServiceScheduleModel {
|
||||
int? photoOfficeID;
|
||||
String? fromDate;
|
||||
String? toDate;
|
||||
int? photoOfficeAppointmentScheduleID;
|
||||
String? photoOfficeName;
|
||||
String? description;
|
||||
String? areaName;
|
||||
String? latitude;
|
||||
String? longitude;
|
||||
int? distanceKM;
|
||||
int? totalItemsCount;
|
||||
List<PhotoOfficeScheduleSlots>? photoOfficeScheduleSlots;
|
||||
|
||||
PhotoSpecialServiceScheduleModel(
|
||||
{this.photoOfficeID,
|
||||
this.fromDate,
|
||||
this.toDate,
|
||||
this.photoOfficeAppointmentScheduleID,
|
||||
this.photoOfficeName,
|
||||
this.description,
|
||||
this.areaName,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.distanceKM,
|
||||
this.totalItemsCount,
|
||||
this.photoOfficeScheduleSlots});
|
||||
|
||||
PhotoSpecialServiceScheduleModel.fromJson(Map<String, dynamic> json) {
|
||||
photoOfficeID = json['photoOfficeID'];
|
||||
fromDate = json['fromDate'];
|
||||
toDate = json['toDate'];
|
||||
photoOfficeAppointmentScheduleID = json['photoOfficeAppointmentScheduleID'];
|
||||
photoOfficeName = json['photoOfficeName'];
|
||||
description = json['description'];
|
||||
areaName = json['areaName'];
|
||||
latitude = json['latitude'];
|
||||
longitude = json['longitude'];
|
||||
distanceKM = json['distanceKM'];
|
||||
totalItemsCount = json['totalItemsCount'];
|
||||
if (json['photoOfficeScheduleSlots'] != null) {
|
||||
photoOfficeScheduleSlots = <PhotoOfficeScheduleSlots>[];
|
||||
json['photoOfficeScheduleSlots'].forEach((v) {
|
||||
photoOfficeScheduleSlots!.add(PhotoOfficeScheduleSlots.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['photoOfficeID'] = photoOfficeID;
|
||||
data['fromDate'] = fromDate;
|
||||
data['toDate'] = toDate;
|
||||
data['photoOfficeAppointmentScheduleID'] = photoOfficeAppointmentScheduleID;
|
||||
data['photoOfficeName'] = photoOfficeName;
|
||||
data['description'] = description;
|
||||
data['areaName'] = areaName;
|
||||
data['latitude'] = latitude;
|
||||
data['longitude'] = longitude;
|
||||
data['distanceKM'] = distanceKM;
|
||||
data['totalItemsCount'] = totalItemsCount;
|
||||
if (photoOfficeScheduleSlots != null) {
|
||||
data['photoOfficeScheduleSlots'] = photoOfficeScheduleSlots!.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class PhotoOfficeScheduleSlots {
|
||||
int? id;
|
||||
String? slotDate;
|
||||
String? startTime;
|
||||
String? endTime;
|
||||
|
||||
PhotoOfficeScheduleSlots({this.id, this.slotDate, this.startTime, this.endTime});
|
||||
|
||||
PhotoOfficeScheduleSlots.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
slotDate = json['slotDate'];
|
||||
startTime = json['startTime'];
|
||||
endTime = json['endTime'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['slotDate'] = slotDate;
|
||||
data['startTime'] = startTime;
|
||||
data['endTime'] = endTime;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
|
||||
class ChatMessageModel {
|
||||
String? senderUserID;
|
||||
String? senderName;
|
||||
int? messageType;
|
||||
ChatMessageTypeEnum? messageTypeEnum;
|
||||
String? message;
|
||||
RequestOffer? requestOffer;
|
||||
int? requestID;
|
||||
int? requestOfferID;
|
||||
bool? isMyMessage;
|
||||
|
||||
ChatMessageModel({
|
||||
this.senderUserID,
|
||||
this.senderName,
|
||||
this.messageType,
|
||||
this.message,
|
||||
this.requestOffer,
|
||||
this.requestID,
|
||||
this.requestOfferID,
|
||||
this.isMyMessage = true,
|
||||
});
|
||||
|
||||
ChatMessageModel.fromJson(Map<String, dynamic> json) {
|
||||
final myUserId = AppState().getUser.data!.userInfo!.userId.toString();
|
||||
senderUserID = json['senderUserID'];
|
||||
senderName = json['senderName'];
|
||||
messageType = json['messageType'];
|
||||
messageTypeEnum = (json['messageType'] as int).toChatMessageTypeEnum();
|
||||
message = json['message'];
|
||||
requestOffer = json['requestOffer'] != null ? RequestOffer.fromJson(json['requestOffer']) : null;
|
||||
requestID = json['requestID'];
|
||||
requestOfferID = json['requestOfferID'];
|
||||
isMyMessage = (json['senderUserId']).toString() == myUserId;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['senderUserID'] = senderUserID;
|
||||
data['senderName'] = senderName;
|
||||
data['messageType'] = messageType;
|
||||
data['message'] = message;
|
||||
if (requestOffer != null) {
|
||||
data['requestOffer'] = requestOffer!.toJson();
|
||||
}
|
||||
data['requestID'] = requestID;
|
||||
data['requestOfferID'] = requestOfferID;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class RequestOffer {
|
||||
int? id;
|
||||
int? requestID;
|
||||
int? serviceProviderID;
|
||||
int? offerStatus;
|
||||
RequestOfferStatusEnum? requestOfferStatusEnum;
|
||||
String? comment;
|
||||
double? price;
|
||||
String? offeredItemCreatedBy;
|
||||
String? offeredItemCreatedOn;
|
||||
|
||||
RequestOffer({
|
||||
this.id,
|
||||
this.requestID,
|
||||
this.serviceProviderID,
|
||||
this.offerStatus,
|
||||
this.comment,
|
||||
this.price,
|
||||
this.offeredItemCreatedBy,
|
||||
this.offeredItemCreatedOn,
|
||||
this.requestOfferStatusEnum = RequestOfferStatusEnum.offer,
|
||||
});
|
||||
|
||||
RequestOffer.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
requestID = json['requestID'];
|
||||
serviceProviderID = json['serviceProviderID'];
|
||||
offerStatus = json['offerStatus'];
|
||||
offerStatus = json['offerStatus'];
|
||||
requestOfferStatusEnum = ((json['offerStatus']) as int).toRequestOfferStatusEnum();
|
||||
comment = json['comment'];
|
||||
price = json['price'];
|
||||
offeredItemCreatedBy = json['offeredItemCreatedBy'];
|
||||
offeredItemCreatedOn = json['offeredItemCreatedOn'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['requestID'] = requestID;
|
||||
data['serviceProviderID'] = serviceProviderID;
|
||||
data['offerStatus'] = offerStatus;
|
||||
data['comment'] = comment;
|
||||
data['price'] = price;
|
||||
data['offeredItemCreatedBy'] = offeredItemCreatedBy;
|
||||
data['offeredItemCreatedOn'] = offeredItemCreatedOn;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
class ConfigModel {
|
||||
ConfigModel(this.endpoint, this.organizationName);
|
||||
|
||||
String endpoint;
|
||||
|
||||
String organizationName;
|
||||
|
||||
factory ConfigModel.fromJson(Map<String, dynamic> json) =>
|
||||
ConfigModel("", "");
|
||||
|
||||
// Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
|
||||
}
|
||||
@ -1,65 +0,0 @@
|
||||
class ContentInfoModel {
|
||||
int? totalItemsCount;
|
||||
int? statusCode;
|
||||
String? message;
|
||||
List<ContentInfoDataModel>? data;
|
||||
|
||||
ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
|
||||
ContentInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
totalItemsCount = json['totalItemsCount'];
|
||||
statusCode = json['statusCode'];
|
||||
message = json['message'];
|
||||
if (json['data'] != null) {
|
||||
data = [];
|
||||
json['data'].forEach((v) {
|
||||
data?.add(new ContentInfoDataModel.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['totalItemsCount'] = this.totalItemsCount;
|
||||
data['statusCode'] = this.statusCode;
|
||||
data['message'] = this.message;
|
||||
if (this.data != null) {
|
||||
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ContentInfoDataModel {
|
||||
int? contentInfoId;
|
||||
int? contentTypeId;
|
||||
String? content;
|
||||
String? contentTypeNameEn;
|
||||
String? contentTypeNameAr;
|
||||
String? fileName;
|
||||
String? exposeFilePath;
|
||||
|
||||
ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath});
|
||||
|
||||
ContentInfoDataModel.fromJson(Map<String, dynamic> json) {
|
||||
contentInfoId = json['contentInfoId'];
|
||||
contentTypeId = json['contentTypeId'];
|
||||
content = json['content'];
|
||||
contentTypeNameEn = json['contentTypeNameEn'];
|
||||
contentTypeNameAr = json['contentTypeNameAr'];
|
||||
fileName = json['fileName'];
|
||||
exposeFilePath = json['exposeFilePath'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['contentInfoId'] = this.contentInfoId;
|
||||
data['contentTypeId'] = this.contentTypeId;
|
||||
data['content'] = this.content;
|
||||
data['contentTypeNameEn'] = this.contentTypeNameEn;
|
||||
data['contentTypeNameAr'] = this.contentTypeNameAr;
|
||||
data['fileName'] = this.fileName;
|
||||
data['exposeFilePath'] = this.exposeFilePath;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -1,62 +0,0 @@
|
||||
class MemberModel {
|
||||
int? totalItemsCount;
|
||||
int? statusCode;
|
||||
String? message;
|
||||
List<MemberDataModel>? data;
|
||||
|
||||
MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
|
||||
MemberModel.fromJson(Map<String, dynamic> json) {
|
||||
totalItemsCount = json['totalItemsCount'];
|
||||
statusCode = json['statusCode'];
|
||||
message = json['message'];
|
||||
if (json['data'] != null) {
|
||||
data = [];
|
||||
json['data'].forEach((v) {
|
||||
data?.add(new MemberDataModel.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['totalItemsCount'] = this.totalItemsCount;
|
||||
data['statusCode'] = this.statusCode;
|
||||
data['message'] = this.message;
|
||||
if (this.data != null) {
|
||||
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class MemberDataModel {
|
||||
int? committeeId;
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
String? description;
|
||||
String? picture;
|
||||
int? orderNo;
|
||||
|
||||
MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo});
|
||||
|
||||
MemberDataModel.fromJson(Map<String, dynamic> json) {
|
||||
committeeId = json['committeeId'];
|
||||
firstName = json['firstName'];
|
||||
lastName = json['lastName'];
|
||||
description = json['description'];
|
||||
picture = json['picture'];
|
||||
orderNo = json['orderNo'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['committeeId'] = this.committeeId;
|
||||
data['firstName'] = this.firstName;
|
||||
data['lastName'] = this.lastName;
|
||||
data['description'] = this.description;
|
||||
data['picture'] = this.picture;
|
||||
data['orderNo'] = this.orderNo;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -1,26 +0,0 @@
|
||||
class ParentList {
|
||||
ParentList({
|
||||
required this.dbId,
|
||||
required this.text,
|
||||
required this.path,
|
||||
required this.isSelected,
|
||||
});
|
||||
|
||||
int dbId;
|
||||
String text;
|
||||
String path;
|
||||
bool isSelected;
|
||||
|
||||
factory ParentList.fromJson(Map<String, dynamic> json) => ParentList(
|
||||
dbId: json["dbId"] == null ? null : json["dbId"],
|
||||
text: json["text"] == null ? null : json["text"],
|
||||
path: json["path"] == null ? null : json["path"],
|
||||
isSelected: false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"dbId": dbId == null ? null : dbId,
|
||||
"text": text == null ? null : text,
|
||||
"path": path == null ? null : path,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,169 @@
|
||||
class OffersModel {
|
||||
int? id;
|
||||
int? requestID;
|
||||
int? serviceProviderID;
|
||||
ServiceProvider? serviceProvider;
|
||||
int? offerStatus;
|
||||
String? offerStatusText;
|
||||
String? comment;
|
||||
double? price;
|
||||
|
||||
OffersModel(
|
||||
{this.id,
|
||||
this.requestID,
|
||||
this.serviceProviderID,
|
||||
this.serviceProvider,
|
||||
this.offerStatus,
|
||||
this.offerStatusText,
|
||||
this.comment,
|
||||
this.price});
|
||||
|
||||
OffersModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
requestID = json['requestID'];
|
||||
serviceProviderID = json['serviceProviderID'];
|
||||
serviceProvider = json['serviceProvider'] != null
|
||||
? ServiceProvider.fromJson(json['serviceProvider'])
|
||||
: null;
|
||||
offerStatus = json['offerStatus'];
|
||||
offerStatusText = json['offerStatusText'];
|
||||
comment = json['comment'];
|
||||
price = json['price'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['requestID'] = requestID;
|
||||
data['serviceProviderID'] = serviceProviderID;
|
||||
if (serviceProvider != null) {
|
||||
data['serviceProvider'] = serviceProvider!.toJson();
|
||||
}
|
||||
data['offerStatus'] = offerStatus;
|
||||
data['offerStatusText'] = offerStatusText;
|
||||
data['comment'] = comment;
|
||||
data['price'] = price;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceProvider {
|
||||
int? providerId;
|
||||
String? providerGUID;
|
||||
String? firstName;
|
||||
String? lastName;
|
||||
String? name;
|
||||
int? gender;
|
||||
String? genderName;
|
||||
String? mobileNo;
|
||||
String? email;
|
||||
bool? isEmailVerfied;
|
||||
bool? isCompleted;
|
||||
int? city;
|
||||
String? cityName;
|
||||
int? country;
|
||||
String? countryName;
|
||||
int? accountStatus;
|
||||
String? accountStatusText;
|
||||
int? activityStatus;
|
||||
String? activityStatusText;
|
||||
String? bankName;
|
||||
String? iBanNo;
|
||||
bool? isActive;
|
||||
String? subscriptionDate;
|
||||
String? companyName;
|
||||
String? currency;
|
||||
String? branch;
|
||||
dynamic requestOffer;
|
||||
|
||||
ServiceProvider(
|
||||
{this.providerId,
|
||||
this.providerGUID,
|
||||
this.firstName,
|
||||
this.lastName,
|
||||
this.name,
|
||||
this.gender,
|
||||
this.genderName,
|
||||
this.mobileNo,
|
||||
this.email,
|
||||
this.isEmailVerfied,
|
||||
this.isCompleted,
|
||||
this.city,
|
||||
this.cityName,
|
||||
this.country,
|
||||
this.countryName,
|
||||
this.accountStatus,
|
||||
this.accountStatusText,
|
||||
this.activityStatus,
|
||||
this.activityStatusText,
|
||||
this.bankName,
|
||||
this.iBanNo,
|
||||
this.isActive,
|
||||
this.subscriptionDate,
|
||||
this.companyName,
|
||||
this.currency,
|
||||
this.branch,
|
||||
this.requestOffer});
|
||||
|
||||
ServiceProvider.fromJson(Map<String, dynamic> json) {
|
||||
providerId = json['providerId'];
|
||||
providerGUID = json['providerGUID'];
|
||||
firstName = json['firstName'];
|
||||
lastName = json['lastName'];
|
||||
name = json['name'];
|
||||
gender = json['gender'];
|
||||
genderName = json['genderName'];
|
||||
mobileNo = json['mobileNo'];
|
||||
email = json['email'];
|
||||
isEmailVerfied = json['isEmailVerfied'];
|
||||
isCompleted = json['isCompleted'];
|
||||
city = json['city'];
|
||||
cityName = json['cityName'];
|
||||
country = json['country'];
|
||||
countryName = json['countryName'];
|
||||
accountStatus = json['accountStatus'];
|
||||
accountStatusText = json['accountStatusText'];
|
||||
activityStatus = json['activityStatus'];
|
||||
activityStatusText = json['activityStatusText'];
|
||||
bankName = json['bankName'];
|
||||
iBanNo = json['iBanNo'];
|
||||
isActive = json['isActive'];
|
||||
subscriptionDate = json['subscriptionDate'];
|
||||
companyName = json['companyName'];
|
||||
currency = json['currency'];
|
||||
branch = json['branch'];
|
||||
requestOffer = json['requestOffer'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['providerId'] = providerId;
|
||||
data['providerGUID'] = providerGUID;
|
||||
data['firstName'] = firstName;
|
||||
data['lastName'] = lastName;
|
||||
data['name'] = name;
|
||||
data['gender'] = gender;
|
||||
data['genderName'] = genderName;
|
||||
data['mobileNo'] = mobileNo;
|
||||
data['email'] = email;
|
||||
data['isEmailVerfied'] = isEmailVerfied;
|
||||
data['isCompleted'] = isCompleted;
|
||||
data['city'] = city;
|
||||
data['cityName'] = cityName;
|
||||
data['country'] = country;
|
||||
data['countryName'] = countryName;
|
||||
data['accountStatus'] = accountStatus;
|
||||
data['accountStatusText'] = accountStatusText;
|
||||
data['activityStatus'] = activityStatus;
|
||||
data['activityStatusText'] = activityStatusText;
|
||||
data['bankName'] = bankName;
|
||||
data['iBanNo'] = iBanNo;
|
||||
data['isActive'] = isActive;
|
||||
data['subscriptionDate'] = subscriptionDate;
|
||||
data['companyName'] = companyName;
|
||||
data['currency'] = currency;
|
||||
data['branch'] = branch;
|
||||
data['requestOffer'] = requestOffer;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
///
|
||||
/// This example was taken from
|
||||
/// https://flutter.dev/docs/development/data-and-backend/json
|
||||
///
|
||||
|
||||
/// This allows the `User` class to access private members in
|
||||
/// the generated file. The value for this is *.g.dart, where
|
||||
/// the star denotes the source file name.
|
||||
|
||||
/// An annotation for the code generator to know that this class needs the
|
||||
/// JSON serialization logic to be generated.
|
||||
|
||||
class BackendResponse {
|
||||
BackendResponse({required this.id, required this.isOk, required this.result});
|
||||
|
||||
int id;
|
||||
bool isOk;
|
||||
dynamic result;
|
||||
|
||||
/// A necessary factory constructor for creating a new User instance
|
||||
/// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
|
||||
/// The constructor is named after the source class, in this case, User.
|
||||
factory BackendResponse.fromJson(Map<String, dynamic> json) =>
|
||||
BackendResponse(
|
||||
id: 1,
|
||||
isOk: false,
|
||||
result: null,
|
||||
);
|
||||
//
|
||||
// /// `toJson` is the convention for a class to declare support for serialization
|
||||
// /// to JSON. The implementation simply calls the private, generated
|
||||
// /// helper method `_$UserToJson`.
|
||||
// Map<String, dynamic> toJson() => _$BackendResponseToJson(this);
|
||||
}
|
||||
@ -1,105 +0,0 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final itemModel = itemModelFromJson(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
ItemModel itemModelFromJson(String str) => ItemModel.fromJson(json.decode(str));
|
||||
|
||||
String itemModelToJson(ItemModel data) => json.encode(data.toJson());
|
||||
|
||||
class ItemModel {
|
||||
final int? messageStatus;
|
||||
final int? totalItemsCount;
|
||||
final List<ItemData>? data;
|
||||
final String? message;
|
||||
|
||||
ItemModel({
|
||||
this.messageStatus,
|
||||
this.totalItemsCount,
|
||||
this.data,
|
||||
this.message,
|
||||
});
|
||||
|
||||
factory ItemModel.fromJson(Map<String, dynamic> json) => ItemModel(
|
||||
messageStatus: json["messageStatus"],
|
||||
totalItemsCount: json["totalItemsCount"],
|
||||
data: json["data"] == null ? [] : List<ItemData>.from(json["data"]!.map((x) => ItemData.fromJson(x))),
|
||||
message: json["message"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"messageStatus": messageStatus,
|
||||
"totalItemsCount": totalItemsCount,
|
||||
"data": data == null ? [] : List<dynamic>.from(data!.map((x) => x.toJson())),
|
||||
"message": message,
|
||||
};
|
||||
}
|
||||
|
||||
class ItemData {
|
||||
final int? id;
|
||||
final String? name;
|
||||
final String? price;
|
||||
final String? manufactureDate;
|
||||
final String? description;
|
||||
final dynamic pictureUrl;
|
||||
final int? companyId;
|
||||
final int? serviceProviderServiceId;
|
||||
final String? serviceProviderServiceDescription;
|
||||
final bool? isActive;
|
||||
final bool? isAllowAppointment;
|
||||
final bool? isAppointmentCompanyLoc;
|
||||
final bool? isAppointmentCustomerLoc;
|
||||
final double? appointmentPricePercentage;
|
||||
bool? isUpdateOrSelected;
|
||||
|
||||
ItemData({
|
||||
this.id,
|
||||
this.name,
|
||||
this.price,
|
||||
this.manufactureDate,
|
||||
this.description,
|
||||
this.pictureUrl,
|
||||
this.companyId,
|
||||
this.serviceProviderServiceId,
|
||||
this.serviceProviderServiceDescription,
|
||||
this.isActive,
|
||||
this.isAllowAppointment,
|
||||
this.isAppointmentCompanyLoc,
|
||||
this.isAppointmentCustomerLoc,
|
||||
this.appointmentPricePercentage,
|
||||
this.isUpdateOrSelected,
|
||||
});
|
||||
|
||||
factory ItemData.fromJson(Map<String, dynamic> json) => ItemData(
|
||||
id: json["id"],
|
||||
name: json["name"],
|
||||
price: json["price"].toString(),
|
||||
manufactureDate: json["manufactureDate"],
|
||||
description: json["description"],
|
||||
pictureUrl: json["pictureUrl"],
|
||||
companyId: json["companyID"],
|
||||
serviceProviderServiceId: json["serviceProviderServiceID"],
|
||||
serviceProviderServiceDescription: json["serviceProviderServiceDescription"],
|
||||
isActive: json["isActive"],
|
||||
isAllowAppointment: json["isAllowAppointment"],
|
||||
isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"],
|
||||
isAppointmentCustomerLoc: json["isAppointmentCustomerLoc"],
|
||||
isUpdateOrSelected: false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"price": price,
|
||||
"manufactureDate": manufactureDate,
|
||||
"description": description,
|
||||
"pictureUrl": pictureUrl,
|
||||
"companyID": companyId,
|
||||
"serviceProviderServiceID": serviceProviderServiceId,
|
||||
"isActive": isActive,
|
||||
"isAllowAppointment": isAllowAppointment,
|
||||
"isAppointmentCompanyLoc": isAppointmentCompanyLoc,
|
||||
"isAppointmentCustomerLoc": isAppointmentCustomerLoc,
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
// To parse this JSON data, do
|
||||
//
|
||||
// final itemModel = itemModelFromJson(jsonString);
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
ItemModel itemModelFromJson(String str) => ItemModel.fromJson(json.decode(str));
|
||||
|
||||
String itemModelToJson(ItemModel data) => json.encode(data.toJson());
|
||||
|
||||
class ItemModel {
|
||||
final int? messageStatus;
|
||||
final int? totalItemsCount;
|
||||
final List<ItemData>? data;
|
||||
final String? message;
|
||||
|
||||
ItemModel({
|
||||
this.messageStatus,
|
||||
this.totalItemsCount,
|
||||
this.data,
|
||||
this.message,
|
||||
});
|
||||
|
||||
factory ItemModel.fromJson(Map<String, dynamic> json) => ItemModel(
|
||||
messageStatus: json["messageStatus"],
|
||||
totalItemsCount: json["totalItemsCount"],
|
||||
data: json["data"] == null ? [] : List<ItemData>.from(json["data"]!.map((x) => ItemData.fromJson(x))),
|
||||
message: json["message"],
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"messageStatus": messageStatus,
|
||||
"totalItemsCount": totalItemsCount,
|
||||
"data": data == null ? [] : List<dynamic>.from(data!.map((x) => x.toJson())),
|
||||
"message": message,
|
||||
};
|
||||
}
|
||||
|
||||
class ItemData {
|
||||
final int? id;
|
||||
final String? name;
|
||||
final String? price;
|
||||
final String? manufactureDate;
|
||||
final String? description;
|
||||
final dynamic pictureUrl;
|
||||
final int? companyId;
|
||||
final int? serviceProviderServiceId;
|
||||
final String? serviceProviderServiceDescription;
|
||||
final bool? isActive;
|
||||
final bool? isAllowAppointment;
|
||||
final bool? isAppointmentCompanyLoc;
|
||||
final bool? isAppointmentCustomerLoc;
|
||||
final double? appointmentPricePercentage;
|
||||
bool? isUpdateOrSelected;
|
||||
bool? isHomeSelected;
|
||||
|
||||
ItemData({
|
||||
this.id,
|
||||
this.name,
|
||||
this.price,
|
||||
this.manufactureDate,
|
||||
this.description,
|
||||
this.pictureUrl,
|
||||
this.companyId,
|
||||
this.serviceProviderServiceId,
|
||||
this.serviceProviderServiceDescription,
|
||||
this.isActive,
|
||||
this.isAllowAppointment,
|
||||
this.isAppointmentCompanyLoc,
|
||||
this.isAppointmentCustomerLoc,
|
||||
this.appointmentPricePercentage,
|
||||
this.isUpdateOrSelected,
|
||||
this.isHomeSelected,
|
||||
});
|
||||
|
||||
factory ItemData.fromJson(Map<String, dynamic> json) => ItemData(
|
||||
id: json["id"],
|
||||
name: json["name"],
|
||||
price: json["price"].toString(),
|
||||
manufactureDate: json["manufactureDate"],
|
||||
description: json["description"],
|
||||
pictureUrl: json["pictureUrl"],
|
||||
companyId: json["companyID"],
|
||||
serviceProviderServiceId: json["serviceProviderServiceID"],
|
||||
serviceProviderServiceDescription: json["serviceProviderServiceDescription"],
|
||||
isActive: json["isActive"],
|
||||
isAllowAppointment: json["isAllowAppointment"],
|
||||
isAppointmentCompanyLoc: json["isAppointmentCompanyLoc"],
|
||||
isAppointmentCustomerLoc: json["isAppointmentCustomerLoc"],
|
||||
isUpdateOrSelected: false,
|
||||
isHomeSelected: false,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"price": price,
|
||||
"manufactureDate": manufactureDate,
|
||||
"description": description,
|
||||
"pictureUrl": pictureUrl,
|
||||
"companyID": companyId,
|
||||
"serviceProviderServiceID": serviceProviderServiceId,
|
||||
"isActive": isActive,
|
||||
"isAllowAppointment": isAllowAppointment,
|
||||
"isAppointmentCompanyLoc": isAppointmentCompanyLoc,
|
||||
"isAppointmentCustomerLoc": isAppointmentCustomerLoc,
|
||||
};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ItemData{id: $id, name: $name, price: $price, manufactureDate: $manufactureDate, description: $description, pictureUrl: $pictureUrl, companyId: $companyId, serviceProviderServiceId: $serviceProviderServiceId, serviceProviderServiceDescription: $serviceProviderServiceDescription, isActive: $isActive, isAllowAppointment: $isAllowAppointment, isAppointmentCompanyLoc: $isAppointmentCompanyLoc, isAppointmentCustomerLoc: $isAppointmentCustomerLoc, appointmentPricePercentage: $appointmentPricePercentage, isUpdateOrSelected: $isUpdateOrSelected}';
|
||||
}
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
class SurahModel {
|
||||
int? totalItemsCount;
|
||||
int? statusCode;
|
||||
String? message;
|
||||
List<SurahModelData>? data;
|
||||
|
||||
SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
|
||||
SurahModel.fromJson(Map<String, dynamic> json) {
|
||||
totalItemsCount = json['totalItemsCount'];
|
||||
statusCode = json['statusCode'];
|
||||
message = json['message'];
|
||||
if (json['data'] != null) {
|
||||
data = [];
|
||||
json['data'].forEach((v) {
|
||||
data?.add(SurahModelData.fromJson(v));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['totalItemsCount'] = totalItemsCount;
|
||||
data['statusCode'] = statusCode;
|
||||
data['message'] = message;
|
||||
if (this.data != null) {
|
||||
data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class SurahModelData {
|
||||
int? id;
|
||||
int? surahID;
|
||||
String? nameAR;
|
||||
String? nameEN;
|
||||
int? numberOfAyahs;
|
||||
String? englishNameTranslation;
|
||||
int? revelationID;
|
||||
String? revelationType;
|
||||
int? startPageNo;
|
||||
int? endPageNo;
|
||||
|
||||
SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo});
|
||||
|
||||
SurahModelData.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
surahID = json['surahID'];
|
||||
nameAR = json['nameAR'];
|
||||
nameEN = json['nameEN'];
|
||||
numberOfAyahs = json['numberOfAyahs'];
|
||||
englishNameTranslation = json['englishNameTranslation'];
|
||||
revelationID = json['revelation_ID'];
|
||||
revelationType = json['revelationType'];
|
||||
startPageNo = json['startPageNo'];
|
||||
endPageNo = json['endPageNo'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
data['id'] = this.id;
|
||||
data['surahID'] = this.surahID;
|
||||
data['nameAR'] = this.nameAR;
|
||||
data['nameEN'] = this.nameEN;
|
||||
data['numberOfAyahs'] = this.numberOfAyahs;
|
||||
data['englishNameTranslation'] = this.englishNameTranslation;
|
||||
data['revelation_ID'] = this.revelationID;
|
||||
data['revelationType'] = this.revelationType;
|
||||
data['startPageNo'] = this.startPageNo;
|
||||
data['endPageNo'] = this.endPageNo;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
// // To parse this JSON data, do
|
||||
// //
|
||||
// // final account = accountFromJson(jsonString);
|
||||
//
|
||||
// import 'dart:convert';
|
||||
//
|
||||
// import 'package:mc_common_app/models/parent_list.dart';
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// Account accountFromJson(String str) => Account.fromJson(json.decode(str));
|
||||
//
|
||||
// String accountToJson(Account data) => json.encode(data.toJson());
|
||||
//
|
||||
// class Account {
|
||||
// Account({
|
||||
// required this.parentList,
|
||||
// required this.selectedItem,
|
||||
// });
|
||||
//
|
||||
// List<ParentList>? parentList;
|
||||
// int selectedItem;
|
||||
//
|
||||
// factory Account.fromJson(Map<String, dynamic> json) => Account(
|
||||
// parentList: json["parentList"] == null
|
||||
// ? null
|
||||
// : List<ParentList>.from(
|
||||
// json["parentList"].map((x) => ParentList.fromJson(x))),
|
||||
// selectedItem:
|
||||
// json["selectedItem"] == null ? null : json["selectedItem"],
|
||||
// );
|
||||
//
|
||||
// Map<String, dynamic> toJson() => {
|
||||
// "parentList": parentList == null
|
||||
// ? null
|
||||
// : List<dynamic>.from(parentList!.map((x) => x.toJson())),
|
||||
// "selectedItem": selectedItem == null ? null : selectedItem,
|
||||
// };
|
||||
//
|
||||
// Map<String, dynamic> toJsonData() => {
|
||||
// "selectedItem": selectedItem == null ? null : selectedItem,
|
||||
// };
|
||||
// }
|
||||
@ -0,0 +1,12 @@
|
||||
// class ConfigModel {
|
||||
// ConfigModel(this.endpoint, this.organizationName);
|
||||
//
|
||||
// String endpoint;
|
||||
//
|
||||
// String organizationName;
|
||||
//
|
||||
// factory ConfigModel.fromJson(Map<String, dynamic> json) =>
|
||||
// ConfigModel("", "");
|
||||
//
|
||||
// // Map<String, dynamic> toJson() => _$ConfigModelToJson(this);
|
||||
// }
|
||||
@ -0,0 +1,65 @@
|
||||
// class ContentInfoModel {
|
||||
// int? totalItemsCount;
|
||||
// int? statusCode;
|
||||
// String? message;
|
||||
// List<ContentInfoDataModel>? data;
|
||||
//
|
||||
// ContentInfoModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
//
|
||||
// ContentInfoModel.fromJson(Map<String, dynamic> json) {
|
||||
// totalItemsCount = json['totalItemsCount'];
|
||||
// statusCode = json['statusCode'];
|
||||
// message = json['message'];
|
||||
// if (json['data'] != null) {
|
||||
// data = [];
|
||||
// json['data'].forEach((v) {
|
||||
// data?.add(new ContentInfoDataModel.fromJson(v));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['totalItemsCount'] = this.totalItemsCount;
|
||||
// data['statusCode'] = this.statusCode;
|
||||
// data['message'] = this.message;
|
||||
// if (this.data != null) {
|
||||
// data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class ContentInfoDataModel {
|
||||
// int? contentInfoId;
|
||||
// int? contentTypeId;
|
||||
// String? content;
|
||||
// String? contentTypeNameEn;
|
||||
// String? contentTypeNameAr;
|
||||
// String? fileName;
|
||||
// String? exposeFilePath;
|
||||
//
|
||||
// ContentInfoDataModel({this.contentInfoId, this.contentTypeId, this.content, this.contentTypeNameEn, this.contentTypeNameAr, this.fileName, this.exposeFilePath});
|
||||
//
|
||||
// ContentInfoDataModel.fromJson(Map<String, dynamic> json) {
|
||||
// contentInfoId = json['contentInfoId'];
|
||||
// contentTypeId = json['contentTypeId'];
|
||||
// content = json['content'];
|
||||
// contentTypeNameEn = json['contentTypeNameEn'];
|
||||
// contentTypeNameAr = json['contentTypeNameAr'];
|
||||
// fileName = json['fileName'];
|
||||
// exposeFilePath = json['exposeFilePath'];
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['contentInfoId'] = this.contentInfoId;
|
||||
// data['contentTypeId'] = this.contentTypeId;
|
||||
// data['content'] = this.content;
|
||||
// data['contentTypeNameEn'] = this.contentTypeNameEn;
|
||||
// data['contentTypeNameAr'] = this.contentTypeNameAr;
|
||||
// data['fileName'] = this.fileName;
|
||||
// data['exposeFilePath'] = this.exposeFilePath;
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,62 @@
|
||||
// class MemberModel {
|
||||
// int? totalItemsCount;
|
||||
// int? statusCode;
|
||||
// String? message;
|
||||
// List<MemberDataModel>? data;
|
||||
//
|
||||
// MemberModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
//
|
||||
// MemberModel.fromJson(Map<String, dynamic> json) {
|
||||
// totalItemsCount = json['totalItemsCount'];
|
||||
// statusCode = json['statusCode'];
|
||||
// message = json['message'];
|
||||
// if (json['data'] != null) {
|
||||
// data = [];
|
||||
// json['data'].forEach((v) {
|
||||
// data?.add(new MemberDataModel.fromJson(v));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['totalItemsCount'] = this.totalItemsCount;
|
||||
// data['statusCode'] = this.statusCode;
|
||||
// data['message'] = this.message;
|
||||
// if (this.data != null) {
|
||||
// data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class MemberDataModel {
|
||||
// int? committeeId;
|
||||
// String? firstName;
|
||||
// String? lastName;
|
||||
// String? description;
|
||||
// String? picture;
|
||||
// int? orderNo;
|
||||
//
|
||||
// MemberDataModel({this.committeeId, this.firstName, this.lastName, this.description, this.picture, this.orderNo});
|
||||
//
|
||||
// MemberDataModel.fromJson(Map<String, dynamic> json) {
|
||||
// committeeId = json['committeeId'];
|
||||
// firstName = json['firstName'];
|
||||
// lastName = json['lastName'];
|
||||
// description = json['description'];
|
||||
// picture = json['picture'];
|
||||
// orderNo = json['orderNo'];
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['committeeId'] = this.committeeId;
|
||||
// data['firstName'] = this.firstName;
|
||||
// data['lastName'] = this.lastName;
|
||||
// data['description'] = this.description;
|
||||
// data['picture'] = this.picture;
|
||||
// data['orderNo'] = this.orderNo;
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,26 @@
|
||||
// class ParentList {
|
||||
// ParentList({
|
||||
// required this.dbId,
|
||||
// required this.text,
|
||||
// required this.path,
|
||||
// required this.isSelected,
|
||||
// });
|
||||
//
|
||||
// int dbId;
|
||||
// String text;
|
||||
// String path;
|
||||
// bool isSelected;
|
||||
//
|
||||
// factory ParentList.fromJson(Map<String, dynamic> json) => ParentList(
|
||||
// dbId: json["dbId"] == null ? null : json["dbId"],
|
||||
// text: json["text"] == null ? null : json["text"],
|
||||
// path: json["path"] == null ? null : json["path"],
|
||||
// isSelected: false,
|
||||
// );
|
||||
//
|
||||
// Map<String, dynamic> toJson() => {
|
||||
// "dbId": dbId == null ? null : dbId,
|
||||
// "text": text == null ? null : text,
|
||||
// "path": path == null ? null : path,
|
||||
// };
|
||||
// }
|
||||
@ -0,0 +1,34 @@
|
||||
// ///
|
||||
// /// This example was taken from
|
||||
// /// https://flutter.dev/docs/development/data-and-backend/json
|
||||
// ///
|
||||
//
|
||||
// /// This allows the `User` class to access private members in
|
||||
// /// the generated file. The value for this is *.g.dart, where
|
||||
// /// the star denotes the source file name.
|
||||
//
|
||||
// /// An annotation for the code generator to know that this class needs the
|
||||
// /// JSON serialization logic to be generated.
|
||||
//
|
||||
// class BackendResponse {
|
||||
// BackendResponse({required this.id, required this.isOk, required this.result});
|
||||
//
|
||||
// int id;
|
||||
// bool isOk;
|
||||
// dynamic result;
|
||||
//
|
||||
// /// A necessary factory constructor for creating a new User instance
|
||||
// /// from a map. Pass the map to the generated `_$UserFromJson()` constructor.
|
||||
// /// The constructor is named after the source class, in this case, User.
|
||||
// factory BackendResponse.fromJson(Map<String, dynamic> json) =>
|
||||
// BackendResponse(
|
||||
// id: 1,
|
||||
// isOk: false,
|
||||
// result: null,
|
||||
// );
|
||||
// //
|
||||
// // /// `toJson` is the convention for a class to declare support for serialization
|
||||
// // /// to JSON. The implementation simply calls the private, generated
|
||||
// // /// helper method `_$UserToJson`.
|
||||
// // Map<String, dynamic> toJson() => _$BackendResponseToJson(this);
|
||||
// }
|
||||
@ -0,0 +1,74 @@
|
||||
// class SurahModel {
|
||||
// int? totalItemsCount;
|
||||
// int? statusCode;
|
||||
// String? message;
|
||||
// List<SurahModelData>? data;
|
||||
//
|
||||
// SurahModel({this.totalItemsCount, this.statusCode, this.message, this.data});
|
||||
//
|
||||
// SurahModel.fromJson(Map<String, dynamic> json) {
|
||||
// totalItemsCount = json['totalItemsCount'];
|
||||
// statusCode = json['statusCode'];
|
||||
// message = json['message'];
|
||||
// if (json['data'] != null) {
|
||||
// data = [];
|
||||
// json['data'].forEach((v) {
|
||||
// data?.add(SurahModelData.fromJson(v));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['totalItemsCount'] = totalItemsCount;
|
||||
// data['statusCode'] = statusCode;
|
||||
// data['message'] = message;
|
||||
// if (this.data != null) {
|
||||
// data['data'] = this.data?.map((v) => v.toJson()).toList();
|
||||
// }
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// class SurahModelData {
|
||||
// int? id;
|
||||
// int? surahID;
|
||||
// String? nameAR;
|
||||
// String? nameEN;
|
||||
// int? numberOfAyahs;
|
||||
// String? englishNameTranslation;
|
||||
// int? revelationID;
|
||||
// String? revelationType;
|
||||
// int? startPageNo;
|
||||
// int? endPageNo;
|
||||
//
|
||||
// SurahModelData({this.id, this.surahID, this.nameAR, this.nameEN, this.numberOfAyahs, this.englishNameTranslation, this.revelationID, this.revelationType, this.startPageNo, this.endPageNo});
|
||||
//
|
||||
// SurahModelData.fromJson(Map<String, dynamic> json) {
|
||||
// id = json['id'];
|
||||
// surahID = json['surahID'];
|
||||
// nameAR = json['nameAR'];
|
||||
// nameEN = json['nameEN'];
|
||||
// numberOfAyahs = json['numberOfAyahs'];
|
||||
// englishNameTranslation = json['englishNameTranslation'];
|
||||
// revelationID = json['revelation_ID'];
|
||||
// revelationType = json['revelationType'];
|
||||
// startPageNo = json['startPageNo'];
|
||||
// endPageNo = json['endPageNo'];
|
||||
// }
|
||||
//
|
||||
// Map<String, dynamic> toJson() {
|
||||
// final Map<String, dynamic> data = new Map<String, dynamic>();
|
||||
// data['id'] = this.id;
|
||||
// data['surahID'] = this.surahID;
|
||||
// data['nameAR'] = this.nameAR;
|
||||
// data['nameEN'] = this.nameEN;
|
||||
// data['numberOfAyahs'] = this.numberOfAyahs;
|
||||
// data['englishNameTranslation'] = this.englishNameTranslation;
|
||||
// data['revelation_ID'] = this.revelationID;
|
||||
// data['revelationType'] = this.revelationType;
|
||||
// data['startPageNo'] = this.startPageNo;
|
||||
// data['endPageNo'] = this.endPageNo;
|
||||
// return data;
|
||||
// }
|
||||
// }
|
||||
@ -0,0 +1,162 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:mc_common_app/api/api_client.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/config/dependencies.dart';
|
||||
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
|
||||
import 'package:mc_common_app/models/general_models/m_response.dart';
|
||||
import 'package:mc_common_app/models/provider_branches_models/profile/services.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/schedule_model.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
|
||||
abstract class AppointmentRepo {
|
||||
Future<Services> getAllServices(String branchId);
|
||||
|
||||
Future<MResponse> createSchedule(Map map);
|
||||
|
||||
Future<MResponse> addServicesInSchedule(Map map);
|
||||
|
||||
Future<MResponse> updateSchedule(Map map);
|
||||
|
||||
Future<List<ScheduleData>> getSchedules(String branchId);
|
||||
|
||||
Future<MResponse> updateServicesInSchedule(Map map);
|
||||
|
||||
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
|
||||
required List<String> serviceItemIdsForHome,
|
||||
required List<String> serviceItemIdsForWorkshop,
|
||||
});
|
||||
|
||||
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID});
|
||||
|
||||
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction});
|
||||
}
|
||||
|
||||
class AppointmentRepoImp implements AppointmentRepo {
|
||||
@override
|
||||
Future<Services> getAllServices(String branchId) async {
|
||||
Map<String, dynamic> map = {"ProviderBranchID": branchId};
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
return await injector.get<ApiClient>().getJsonForObject((json) => Services.fromJson(json), ApiConsts.getServicesOfBranch, token: t, queryParameters: map);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MResponse> createSchedule(Map map) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createSchedule, map, token: t);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MResponse> addServicesInSchedule(Map map) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.createGroup, map, token: t);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ScheduleData>> getSchedules(String branchId) async {
|
||||
Map<String, dynamic> map = {"ServiceProviderBranchID": branchId};
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
|
||||
GenericRespModel adsGenericModel = await injector.get<ApiClient>().getJsonForObject(
|
||||
(json) => GenericRespModel.fromJson(json),
|
||||
ApiConsts.getSchedule,
|
||||
token: t,
|
||||
queryParameters: map,
|
||||
);
|
||||
|
||||
return List.generate(adsGenericModel.data.length, (index) => ScheduleData.fromJson(adsGenericModel.data[index]));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MResponse> updateSchedule(Map map) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateSchedule, map, token: t);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MResponse> updateServicesInSchedule(Map map) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
return await injector.get<ApiClient>().postJsonForObject((json) => MResponse.fromJson(json), ApiConsts.updateGroup, map, token: t);
|
||||
}
|
||||
|
||||
Future<List<ServiceAppointmentScheduleModel>> mergeServiceIntoAvailableSchedules({
|
||||
required List<String> serviceItemIdsForHome,
|
||||
required List<String> serviceItemIdsForWorkshop,
|
||||
}) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
var queryParameters = [
|
||||
{
|
||||
"appointmentType": 2,
|
||||
"ServiceItemIDs": serviceItemIdsForHome,
|
||||
},
|
||||
{
|
||||
"appointmentType": 1,
|
||||
"ServiceItemIDs": serviceItemIdsForWorkshop,
|
||||
}
|
||||
];
|
||||
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
|
||||
(json) => GenericRespModel.fromJson(json),
|
||||
ApiConsts.GetServiceItemAppointmentScheduleSlots,
|
||||
queryParameters,
|
||||
token: t,
|
||||
);
|
||||
if (adsGenericModel.data == null) {
|
||||
return [];
|
||||
}
|
||||
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleModel =
|
||||
List.generate(adsGenericModel.data.length, (index) => ServiceAppointmentScheduleModel.fromJson(adsGenericModel.data[index], isForAppointment: true));
|
||||
return serviceAppointmentScheduleModel;
|
||||
}
|
||||
|
||||
Future<GenericRespModel> createServiceAppointment({required List<ServiceAppointmentScheduleModel> schedules, required int serviceProviderID}) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
int customerId = AppState().getUser.data!.userInfo!.customerId ?? 0;
|
||||
|
||||
List<Map<String, dynamic>> mapList = [];
|
||||
schedules.forEach((schedule) {
|
||||
List<int> serviceItemIds = [];
|
||||
schedule.servicesListInAppointment!.forEach((service) {
|
||||
service.serviceItems!.forEach((item) {
|
||||
serviceItemIds.add(item.id!);
|
||||
});
|
||||
});
|
||||
mapList.add({
|
||||
"serviceSlotID": schedule.selectedCustomTimeDateSlotModel!.date!.slotId,
|
||||
"serviceProviderID": serviceProviderID,
|
||||
"customerID": customerId,
|
||||
"serviceItemID": serviceItemIds,
|
||||
});
|
||||
});
|
||||
|
||||
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
|
||||
(json) => GenericRespModel.fromJson(json),
|
||||
ApiConsts.ServiceProvidersAppointmentCreate,
|
||||
mapList,
|
||||
token: t,
|
||||
);
|
||||
|
||||
return adsGenericModel;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GenericRespModel> cancelOrRescheduleServiceAppointment({required int serviceAppointmentID, required int serviceSlotID, required int appointmentScheduleAction}) async {
|
||||
String t = AppState().getUser.data!.accessToken ?? "";
|
||||
|
||||
final payload = {
|
||||
"serviceAppointmentID": serviceAppointmentID,
|
||||
"serviceSlotID": serviceSlotID,
|
||||
"appointmentScheduleAction": appointmentScheduleAction,
|
||||
};
|
||||
|
||||
GenericRespModel adsGenericModel = await injector.get<ApiClient>().postJsonForObject(
|
||||
(json) => GenericRespModel.fromJson(json),
|
||||
ApiConsts.ServiceProviderAppointmentRescheduleCancelAppointment,
|
||||
payload,
|
||||
token: t,
|
||||
);
|
||||
|
||||
return adsGenericModel;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
import 'dart:io';
|
||||
import 'package:http/io_client.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/main.dart';
|
||||
import 'package:signalr_core/signalr_core.dart';
|
||||
|
||||
abstract class ChatRepo {
|
||||
Future<HubConnection> getHubConnection();
|
||||
}
|
||||
|
||||
class ChatRepoImp implements ChatRepo {
|
||||
@override
|
||||
Future<HubConnection> getHubConnection() async {
|
||||
final userId = AppState().getUser.data!.userInfo!.userId ?? "";
|
||||
final hubUrl = "https://ms.hmg.com/McHub?userID=$userId";
|
||||
logger.i("Connecting with Hub ($hubUrl)");
|
||||
|
||||
HubConnection hub;
|
||||
hub = HubConnectionBuilder()
|
||||
.withUrl(
|
||||
hubUrl,
|
||||
HttpConnectionOptions(
|
||||
client: IOClient(HttpClient()
|
||||
..badCertificateCallback = (x, y, z) => true),
|
||||
logging: (level, message) {
|
||||
print(message);
|
||||
},
|
||||
))
|
||||
.build();
|
||||
return hub;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:mc_common_app/api/api_client.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/config/dependencies.dart';
|
||||
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
|
||||
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/item_model.dart';
|
||||
|
||||
abstract class ProviderRepo {
|
||||
Future<List<BranchDetailModel>> getAllNearBranchAndServices();
|
||||
|
||||
Future<List<ItemData>> getServiceItems(int serviceId);
|
||||
|
||||
Future<ProviderProfileModel> getBranchAndServices(int providerId);
|
||||
}
|
||||
|
||||
class ProviderRepoImp implements ProviderRepo {
|
||||
ApiClient apiClient = injector.get<ApiClient>();
|
||||
AppState appState = injector.get<AppState>();
|
||||
|
||||
@override
|
||||
Future<List<BranchDetailModel>> getAllNearBranchAndServices() async {
|
||||
GenericRespModel adsGenericModel = await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.GetAllNearBranches, token: appState.getUser.data!.accessToken);
|
||||
List<BranchDetailModel> nearBranches = List.generate(adsGenericModel.data.length, (index) => BranchDetailModel.fromJson(adsGenericModel.data[index]));
|
||||
return nearBranches;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<ItemData>> getServiceItems(int serviceId) async {
|
||||
var queryParameters = {
|
||||
"ServiceProviderServiceID": serviceId.toString(),
|
||||
};
|
||||
|
||||
GenericRespModel adsGenericModel = await apiClient.getJsonForObject(
|
||||
(json) => GenericRespModel.fromJson(json),
|
||||
ApiConsts.getServiceItems,
|
||||
token: appState.getUser.data!.accessToken,
|
||||
queryParameters: queryParameters,
|
||||
);
|
||||
List<ItemData> serviceItems = List.generate(adsGenericModel.data.length, (index) => ItemData.fromJson(adsGenericModel.data[index]));
|
||||
return serviceItems;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ProviderProfileModel> getBranchAndServices(int providerId) async {
|
||||
var postParams = {"serviceProviderID": providerId.toString()};
|
||||
GenericRespModel adsGenericModel =
|
||||
await apiClient.getJsonForObject((json) => GenericRespModel.fromJson(json), ApiConsts.BranchesAndServices, token: appState.getUser.data!.accessToken, queryParameters: postParams);
|
||||
|
||||
return ProviderProfileModel.fromJson(adsGenericModel.data);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,691 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/config/routes.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
||||
import 'package:mc_common_app/models/general_models/enums_model.dart';
|
||||
import 'package:mc_common_app/models/general_models/generic_resp_model.dart';
|
||||
import 'package:mc_common_app/models/provider_branches_models/branch_detail_model.dart';
|
||||
import 'package:mc_common_app/models/provider_branches_models/provider_profile_model.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/item_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/service_model.dart';
|
||||
import 'package:mc_common_app/models/general_models/widgets_models.dart';
|
||||
import 'package:mc_common_app/repositories/appointment_repo.dart';
|
||||
import 'package:mc_common_app/repositories/common_repo.dart';
|
||||
import 'package:mc_common_app/repositories/provider_repo.dart';
|
||||
import 'package:mc_common_app/services/common_services.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/utils/navigator.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:mc_common_app/view_models/base_view_model.dart';
|
||||
import 'package:mc_common_app/view_models/dashboard_view_model_customer.dart';
|
||||
import 'package:mc_common_app/view_models/payment_view_model.dart';
|
||||
import 'package:mc_common_app/views/appointments/book_appointment_schedules_view.dart';
|
||||
import 'package:mc_common_app/views/appointments/widgets/appointment_service_pick_bottom_sheet.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/info_bottom_sheet.dart';
|
||||
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AppointmentsVM extends BaseVM {
|
||||
final CommonRepo commonRepo;
|
||||
final CommonAppServices commonServices;
|
||||
final ProviderRepo providerRepo;
|
||||
final AppointmentRepo scheduleRepo;
|
||||
|
||||
AppointmentsVM({required this.commonServices, required this.scheduleRepo, required this.providerRepo, required this.commonRepo});
|
||||
|
||||
bool isFetchingLists = false;
|
||||
|
||||
List<AppointmentListModel> myAppointments = [];
|
||||
List<AppointmentListModel> myUpComingAppointments = [];
|
||||
List<AppointmentListModel> myFilteredAppointments = [];
|
||||
List<FilterListModel> appointmentsFilterOptions = [];
|
||||
|
||||
// List<ScheduleData> availableSchedules = [];
|
||||
|
||||
bool isFetchingServices = false;
|
||||
|
||||
List<DropValue> branchCategories = [];
|
||||
|
||||
bool isHomeTapped = false;
|
||||
|
||||
List<ServiceAppointmentScheduleModel> serviceAppointmentScheduleList = [];
|
||||
|
||||
bool ifItemAlreadySelected(int id) {
|
||||
int indexFound = allSelectedItemsInAppointments.indexWhere((element) => element.id == id);
|
||||
if (indexFound != -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
List<ItemData> allSelectedItemsInAppointments = [];
|
||||
|
||||
Future<void> onItemsSelectedInService() async {
|
||||
if (currentServiceSelection != null) {
|
||||
int index = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
|
||||
|
||||
if (index == -1) {
|
||||
double totalPrice = 0.0;
|
||||
for (var element in currentServiceSelection!.serviceItems!) {
|
||||
totalPrice = totalPrice + double.parse(element.price ?? "0.0");
|
||||
}
|
||||
currentServiceSelection!.currentTotalServicePrice = totalPrice;
|
||||
servicesInCurrentAppointment.insert(0, currentServiceSelection!);
|
||||
}
|
||||
|
||||
resetCategorySelectionBottomSheet();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onBookAppointmentPressed(BuildContext context) async {
|
||||
Utils.showLoading(context);
|
||||
bool isSuccess = false;
|
||||
List<int> appointmentIdsList = [];
|
||||
try {
|
||||
GenericRespModel genericRespModel = await scheduleRepo.createServiceAppointment(
|
||||
schedules: serviceAppointmentScheduleList,
|
||||
serviceProviderID: selectedBranchModel!.serviceProviderId ?? 0,
|
||||
);
|
||||
|
||||
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
|
||||
Utils.hideLoading(context);
|
||||
Utils.showToast("${genericRespModel.message.toString()}");
|
||||
return;
|
||||
}
|
||||
if (genericRespModel.data != null) {
|
||||
genericRespModel.data.forEach((element) {
|
||||
if (element['appointmentID'] != 0) {
|
||||
appointmentIdsList.add(element['appointmentID']);
|
||||
isSuccess = true;
|
||||
} else {
|
||||
isSuccess = false;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
context.read<DashboardVmCustomer>().onNavbarTapped(1);
|
||||
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.booked);
|
||||
Utils.hideLoading(context);
|
||||
resetAfterBookingAppointment();
|
||||
if (isSuccess) {
|
||||
if (amountToPayForAppointment > 0) {
|
||||
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: appointmentIdsList);
|
||||
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
|
||||
} else {
|
||||
Utils.showToast("Your appointment has been booked successfully!");
|
||||
getMyAppointments();
|
||||
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Utils.showToast("${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> onConfirmAppointmentPressed({required BuildContext context, required appointmentId}) async {
|
||||
context.read<PaymentVM>().updateAppointmentIdsForPayment(ids: [appointmentId]);
|
||||
navigateWithName(context, AppRoutes.paymentMethodsView, arguments: PaymentTypes.appointment);
|
||||
}
|
||||
|
||||
Future<void> onCancelAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
|
||||
Utils.showLoading(context);
|
||||
try {
|
||||
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
|
||||
serviceAppointmentID: appointmentListModel.id ?? 0,
|
||||
serviceSlotID: appointmentListModel.serviceSlotID ?? 0,
|
||||
appointmentScheduleAction: 2, // 1 for Reschedule and 2 for Cancel
|
||||
);
|
||||
|
||||
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
|
||||
Utils.hideLoading(context);
|
||||
Utils.showToast("${genericRespModel.message.toString()}");
|
||||
return;
|
||||
}
|
||||
if (genericRespModel.data == 1) {
|
||||
context.read<DashboardVmCustomer>().onNavbarTapped(1);
|
||||
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
|
||||
Utils.showToast("${genericRespModel.message.toString()}");
|
||||
await getMyAppointments();
|
||||
Utils.hideLoading(context);
|
||||
getMyAppointments();
|
||||
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
|
||||
}
|
||||
} catch (e) {
|
||||
Utils.showToast("${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
void updateIsHomeTapped(bool value) {
|
||||
isHomeTapped = value;
|
||||
if (currentServiceSelection != null) {
|
||||
currentServiceSelection!.isHomeSelected = value;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
String pickedHomeLocation = "";
|
||||
|
||||
void updatePickedHomeLocation(String value) {
|
||||
pickedHomeLocation = value;
|
||||
pickHomeLocationError = "";
|
||||
if (currentServiceSelection != null) {
|
||||
currentServiceSelection!.homeLocation = value;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
SelectionModel branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
||||
|
||||
void updateProviderCategoryId(SelectionModel id) {
|
||||
branchSelectedCategoryId = id;
|
||||
getBranchServices(categoryId: branchSelectedCategoryId.selectedId);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
List<FilterListModel> providersFilterOptions = [];
|
||||
List<BranchDetailModel> nearbyBranches = [];
|
||||
BranchDetailModel? selectedBranchModel;
|
||||
|
||||
List<ServiceModel> branchServices = [];
|
||||
|
||||
List<ServiceModel> servicesInCurrentAppointment = [];
|
||||
ServiceModel? currentServiceSelection;
|
||||
|
||||
void updateBranchServiceId(SelectionModel id) async {
|
||||
branchSelectedServiceId = id;
|
||||
currentServiceSelection = branchServices.firstWhere((element) => element.serviceProviderServiceId == id.selectedId);
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void removeServiceInCurrentAppointment(int index) {
|
||||
int serviceId = servicesInCurrentAppointment.elementAt(index).serviceProviderServiceId ?? -1;
|
||||
allSelectedItemsInAppointments.removeWhere((element) => element.serviceProviderServiceId == serviceId);
|
||||
servicesInCurrentAppointment.removeAt(index);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
resetCategorySelectionBottomSheet() {
|
||||
selectedSubServicesCounter = 0;
|
||||
branchSelectedCategoryId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
||||
isHomeTapped = false;
|
||||
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
||||
currentServiceSelection = null;
|
||||
}
|
||||
|
||||
resetAfterBookingAppointment() {
|
||||
allSelectedItemsInAppointments.clear();
|
||||
// servicesInCurrentAppointment.clear();
|
||||
serviceAppointmentScheduleList.clear();
|
||||
}
|
||||
|
||||
List<EnumsModel> myAppointmentsEnum = [];
|
||||
|
||||
populateAppointmentsFilterList() async {
|
||||
appointmentsFilterOptions.clear();
|
||||
|
||||
myAppointmentsEnum = await commonRepo.getEnumTypeValues(enumTypeID: 13); //TODO: 13 is to get Appointments Filter Enums
|
||||
|
||||
for (int i = 0; i < myAppointmentsEnum.length; i++) {
|
||||
appointmentsFilterOptions.add(FilterListModel(title: myAppointmentsEnum[i].enumValueStr, isSelected: false, id: myAppointmentsEnum[i].enumValue));
|
||||
}
|
||||
appointmentsFilterOptions.insert(0, FilterListModel(title: "All Appointments", isSelected: true, id: 0));
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
applyFilterOnAppointmentsVM({required AppointmentStatusEnum appointmentStatusEnum}) {
|
||||
if (appointmentsFilterOptions.isEmpty) return;
|
||||
for (var value in appointmentsFilterOptions) {
|
||||
value.isSelected = false;
|
||||
}
|
||||
appointmentsFilterOptions[appointmentStatusEnum.getIdFromAppointmentStatusEnum()].isSelected = true;
|
||||
|
||||
if (appointmentStatusEnum.getIdFromAppointmentStatusEnum() == 0) {
|
||||
myFilteredAppointments = myAppointments;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
myFilteredAppointments = myAppointments.where((element) => element.appointmentStatusID! == appointmentStatusEnum.getIdFromAppointmentStatusEnum()).toList();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> getMyAppointments({bool isNeedToRebuild = false}) async {
|
||||
if (isNeedToRebuild) setState(ViewState.busy);
|
||||
|
||||
myAppointments = await commonRepo.getMyAppointments();
|
||||
myFilteredAppointments = myAppointments;
|
||||
myUpComingAppointments = myAppointments.where((element) => element.appointmentStatusEnum == AppointmentStatusEnum.booked).toList();
|
||||
setState(ViewState.idle);
|
||||
// applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.allAppointments);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
updateSelectedBranch(BranchDetailModel branchDetailModel) {
|
||||
selectedBranchModel = branchDetailModel;
|
||||
getBranchCategories();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
updateSelectedAppointmentDate({required int dateIndex, required int scheduleIndex}) {
|
||||
for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
|
||||
element.date!.isSelected = false;
|
||||
}
|
||||
|
||||
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.isSelected = true;
|
||||
serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex = dateIndex;
|
||||
final date = TimeSlotModel(
|
||||
date: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.date,
|
||||
slotId: serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![dateIndex].date!.slotId,
|
||||
isSelected: true,
|
||||
slot: "",
|
||||
);
|
||||
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel = CustomTimeDateSlotModel(date: date);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
updateSelectedAppointmentSlotByDate({required int scheduleIndex, required int slotIndex}) {
|
||||
for (var element in serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList!) {
|
||||
for (var element in element.availableSlots!) {
|
||||
element.isSelected = false;
|
||||
}
|
||||
}
|
||||
int index = serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!;
|
||||
serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots![slotIndex].isSelected = true;
|
||||
serviceAppointmentScheduleList[scheduleIndex].selectedCustomTimeDateSlotModel!.availableSlots = serviceAppointmentScheduleList[scheduleIndex].customTimeDateSlotList![index].availableSlots!;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
double amountToPayForAppointment = 0.0;
|
||||
double totalAmount = 0.0;
|
||||
|
||||
List<ItemData> serviceItemsFromApi = [];
|
||||
|
||||
ProviderProfileModel? providerProfileModel;
|
||||
|
||||
int selectedSubServicesCounter = 0;
|
||||
|
||||
onItemUpdateOrSelected(int index, bool selected, int itemId) {
|
||||
int serviceIndex = servicesInCurrentAppointment.indexWhere((element) => element.serviceId == currentServiceSelection!.serviceId!);
|
||||
// print("servicesInCurrentAppointment: ${servicesInCurrentAppointment.length}");
|
||||
// if (serviceIndex == -1) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
serviceItemsFromApi[index].isUpdateOrSelected = selected;
|
||||
serviceItemsFromApi[index].isHomeSelected = isHomeTapped;
|
||||
if (selected) {
|
||||
selectedSubServicesCounter = selectedSubServicesCounter + 1;
|
||||
selectSubServicesError = "";
|
||||
currentServiceSelection!.serviceItems!.add(serviceItemsFromApi[index]);
|
||||
allSelectedItemsInAppointments.add(serviceItemsFromApi[index]);
|
||||
for (var element in allSelectedItemsInAppointments) {
|
||||
if (!ifItemAlreadySelected(element.id!)) {
|
||||
servicesInCurrentAppointment[serviceIndex].serviceItems!.add(serviceItemsFromApi[index]);
|
||||
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
|
||||
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice + double.parse((serviceItemsFromApi[index].price) ?? "0.0");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!selected) {
|
||||
selectedSubServicesCounter = selectedSubServicesCounter - 1;
|
||||
currentServiceSelection!.serviceItems!.removeWhere((element) => element.id == itemId);
|
||||
allSelectedItemsInAppointments.removeWhere((element) => element.id == itemId);
|
||||
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice =
|
||||
servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice - double.parse((serviceItemsFromApi[index].price) ?? "0.0");
|
||||
servicesInCurrentAppointment[serviceIndex].serviceItems!.removeWhere((element) => element.id == itemId);
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
populateBranchesFilterList() {
|
||||
providersFilterOptions.clear();
|
||||
providersFilterOptions = [
|
||||
FilterListModel(title: "All Providers", isSelected: true, id: 0),
|
||||
FilterListModel(title: "Maintenance", isSelected: false, id: 1),
|
||||
FilterListModel(title: "Oil Service", isSelected: false, id: 2),
|
||||
FilterListModel(title: "Accessories", isSelected: false, id: 3),
|
||||
FilterListModel(title: "Tire Service", isSelected: false, id: 4),
|
||||
FilterListModel(title: "Dent and Paint", isSelected: false, id: 5),
|
||||
];
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
applyFilterOnProviders({required int index}) {
|
||||
if (providersFilterOptions.isEmpty) return;
|
||||
for (var value in providersFilterOptions) {
|
||||
value.isSelected = false;
|
||||
}
|
||||
providersFilterOptions[index].isSelected = true;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
getAllNearBranches({bool isNeedToRebuild = false}) async {
|
||||
//TODO: needs to lat,long into API
|
||||
nearbyBranches.clear();
|
||||
if (isNeedToRebuild) setState(ViewState.busy);
|
||||
nearbyBranches = await providerRepo.getAllNearBranchAndServices();
|
||||
setState(ViewState.idle);
|
||||
}
|
||||
|
||||
Future<List<ItemData>> getServiceItems(int serviceId) async {
|
||||
serviceItemsFromApi.clear();
|
||||
serviceItemsFromApi = await providerRepo.getServiceItems(serviceId);
|
||||
for (var item in serviceItemsFromApi) {
|
||||
if (ifItemAlreadySelected(item.id!)) {
|
||||
item.isUpdateOrSelected = true;
|
||||
}
|
||||
}
|
||||
setState(ViewState.idle);
|
||||
return serviceItemsFromApi;
|
||||
}
|
||||
|
||||
getBranchAndServices(int providerId) async {
|
||||
providerProfileModel = null;
|
||||
providerProfileModel = await providerRepo.getBranchAndServices(providerId);
|
||||
setState(ViewState.idle);
|
||||
}
|
||||
|
||||
String pickHomeLocationError = "";
|
||||
String selectSubServicesError = "";
|
||||
|
||||
SelectionModel branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
||||
|
||||
bool isCategoryAlreadyPresent(int id) {
|
||||
final contain = branchCategories.where((element) => element.id == id);
|
||||
if (contain.isEmpty) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void getBranchCategories() async {
|
||||
for (var value in selectedBranchModel!.branchServices!) {
|
||||
if (!isCategoryAlreadyPresent(value.categoryId!)) {
|
||||
branchCategories.add(DropValue(value.categoryId!, value.categoryName!, ""));
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
getBranchServices({required int categoryId}) async {
|
||||
branchSelectedServiceId = SelectionModel(selectedOption: "", selectedId: -1, errorValue: "");
|
||||
isHomeTapped = false;
|
||||
pickedHomeLocation = "";
|
||||
pickHomeLocationError = "";
|
||||
if (categoryId != -1) {
|
||||
isFetchingServices = true;
|
||||
branchServices = getFilteredBranchServices(categoryId: categoryId);
|
||||
isFetchingServices = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
List<ServiceModel> getFilteredBranchServices({required int categoryId}) {
|
||||
List<ServiceModel> filteredServices = selectedBranchModel!.branchServices!.where((element) => element.categoryId == categoryId).toList();
|
||||
return filteredServices;
|
||||
}
|
||||
|
||||
void updatePickHomeLocationError(String value) {
|
||||
pickHomeLocationError = value;
|
||||
// notifyListeners();
|
||||
}
|
||||
|
||||
bool isServiceSelectionValidated() {
|
||||
if (branchSelectedServiceId.selectedId == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isHomeTapped) {
|
||||
if (pickedHomeLocation == "") {
|
||||
updatePickHomeLocationError(GlobalConsts.homeLocationEmptyError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validateItemsSelection() {
|
||||
for (var value in serviceItemsFromApi) {
|
||||
if (value.isUpdateOrSelected!) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
selectSubServicesError = "Please select at least one sub service";
|
||||
notifyListeners();
|
||||
return false;
|
||||
}
|
||||
|
||||
String getTotalPrice(List<ServiceModel> serviceItems) {
|
||||
var totalPrice = 0.0;
|
||||
for (var element in serviceItems) {
|
||||
totalPrice = totalPrice + (element.currentTotalServicePrice);
|
||||
}
|
||||
return totalPrice.toString();
|
||||
}
|
||||
|
||||
void openTheAddServiceBottomSheet(BuildContext context, AppointmentsVM appointmentsVM) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
builder: (BuildContext context) {
|
||||
return AppointmentServicePickBottomSheet();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void priceBreakDownClicked(BuildContext context, ServiceModel selectedService) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: true,
|
||||
builder: (BuildContext context) {
|
||||
double totalKms = 15.3;
|
||||
return InfoBottomSheet(
|
||||
title: "Charges Breakdown".toText(fontSize: 24, isBold: true),
|
||||
description: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Services".toText(fontSize: 16, isBold: true),
|
||||
Column(
|
||||
children: List.generate(
|
||||
selectedService.serviceItems!.length,
|
||||
(index) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"${selectedService.serviceItems![index].name}".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||
"${selectedService.serviceItems![index].price} SAR".toText(fontSize: 12, isBold: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
"${selectedService.currentTotalServicePrice} SAR".toText(fontSize: 16, isBold: true),
|
||||
],
|
||||
),
|
||||
if (selectedService.isHomeSelected) ...[
|
||||
20.height,
|
||||
"Home Location".toText(fontSize: 16, isBold: true),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"${totalKms}km ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||
"${selectedService.rangePricePerKm} x $totalKms".toText(fontSize: 12, isBold: true),
|
||||
],
|
||||
),
|
||||
8.height,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
"${selectedService.rangePricePerKm ?? 0 * totalKms} SAR".toText(fontSize: 16, isBold: true),
|
||||
],
|
||||
),
|
||||
],
|
||||
30.height,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
"Total Amount ".toText(fontSize: 16, isBold: true),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
(selectedService.isHomeSelected
|
||||
? "${(selectedService.currentTotalServicePrice) + (double.parse((selectedService.rangePricePerKm ?? "0.0")) * totalKms)}"
|
||||
: "${selectedService.currentTotalServicePrice}")
|
||||
.toText(fontSize: 29, isBold: true),
|
||||
2.width,
|
||||
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
30.height,
|
||||
],
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
void onReviewButtonPressed(BuildContext context) {
|
||||
bool isValidated = false;
|
||||
|
||||
for (int i = 0; i < serviceAppointmentScheduleList.length; i++) {
|
||||
final schedule = serviceAppointmentScheduleList[i];
|
||||
if (schedule.selectedCustomTimeDateSlotModel == null) {
|
||||
isValidated = false;
|
||||
break;
|
||||
}
|
||||
if (schedule.selectedCustomTimeDateSlotModel!.date == null || !schedule.selectedCustomTimeDateSlotModel!.date!.isSelected) {
|
||||
isValidated = false;
|
||||
break;
|
||||
} else {
|
||||
if (schedule.selectedCustomTimeDateSlotModel!.availableSlots == null) {
|
||||
isValidated = false;
|
||||
break;
|
||||
} else {
|
||||
TimeSlotModel slot = schedule.selectedCustomTimeDateSlotModel!.availableSlots!.firstWhere((element) => element.isSelected);
|
||||
if (slot.date.isNotEmpty) {
|
||||
isValidated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isValidated) {
|
||||
Utils.showToast("You must select appointment time for each schedule's appointment.");
|
||||
return;
|
||||
}
|
||||
navigateWithName(context, AppRoutes.reviewAppointmentView);
|
||||
}
|
||||
|
||||
void onServicesNextPressed(BuildContext context) async {
|
||||
Utils.showLoading(context);
|
||||
|
||||
List<String> serviceItemIdsForHome = [];
|
||||
List<String> serviceItemIdsForWorkshop = [];
|
||||
for (var serviceItem in allSelectedItemsInAppointments) {
|
||||
if (serviceItem.isHomeSelected!) {
|
||||
serviceItemIdsForHome.add(serviceItem.id!.toString());
|
||||
} else {
|
||||
serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
||||
}
|
||||
}
|
||||
|
||||
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
|
||||
serviceItemIdsForHome: serviceItemIdsForHome,
|
||||
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
|
||||
);
|
||||
|
||||
if (serviceAppointmentScheduleList.isEmpty) {
|
||||
Utils.hideLoading(context);
|
||||
Utils.showToast("There are no available appointments for selected Items.");
|
||||
return;
|
||||
}
|
||||
totalAmount = 0.0;
|
||||
amountToPayForAppointment = 0.0;
|
||||
for (var schedule in serviceAppointmentScheduleList) {
|
||||
amountToPayForAppointment = amountToPayForAppointment + (schedule.amountToPay ?? 0.0);
|
||||
totalAmount = totalAmount + (schedule.amountTotal ?? 0.0);
|
||||
}
|
||||
Utils.hideLoading(context);
|
||||
|
||||
navigateWithName(context, AppRoutes.bookAppointmenSchedulesView, arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 1, appointmentId: 0)); // 1 For Creating an Appointment
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> onRescheduleAppointmentPressed({required BuildContext context, required AppointmentListModel appointmentListModel}) async {
|
||||
Utils.showLoading(context);
|
||||
|
||||
List<String> serviceItemIdsForHome = [];
|
||||
List<String> serviceItemIdsForWorkshop = [];
|
||||
for (var service in appointmentListModel.appointmentServicesList!) {
|
||||
for (var serviceItem in service.serviceItems!) {
|
||||
serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
||||
|
||||
// if (serviceItem.isHomeSelected ?? false) {
|
||||
// serviceItemIdsForHome.add(serviceItem.id!.toString());
|
||||
// } else {
|
||||
// serviceItemIdsForWorkshop.add(serviceItem.id!.toString());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
serviceAppointmentScheduleList = await scheduleRepo.mergeServiceIntoAvailableSchedules(
|
||||
serviceItemIdsForHome: serviceItemIdsForHome,
|
||||
serviceItemIdsForWorkshop: serviceItemIdsForWorkshop,
|
||||
);
|
||||
|
||||
if (serviceAppointmentScheduleList.isEmpty) {
|
||||
Utils.hideLoading(context);
|
||||
Utils.showToast("There are no available appointments for selected Items.");
|
||||
return;
|
||||
}
|
||||
Utils.hideLoading(context);
|
||||
|
||||
navigateWithName(
|
||||
context,
|
||||
AppRoutes.bookAppointmenSchedulesView,
|
||||
arguments: ScreenArgumentsForAppointmentDetailPage(routeFlag: 2, appointmentId: appointmentListModel.id ?? 0),
|
||||
); // 2 For Rescheduling an Appointment
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> onRescheduleAppointmentConfirmPressed({required BuildContext context, required int appointmentId, required int selectedSlotId}) async {
|
||||
Utils.showLoading(context);
|
||||
try {
|
||||
GenericRespModel genericRespModel = await scheduleRepo.cancelOrRescheduleServiceAppointment(
|
||||
serviceAppointmentID: appointmentId,
|
||||
serviceSlotID: selectedSlotId,
|
||||
appointmentScheduleAction: 1, // 1 for Reschedule and 2 for Cancel
|
||||
);
|
||||
|
||||
if (genericRespModel.messageStatus == 2 || genericRespModel.data == null) {
|
||||
Utils.hideLoading(context);
|
||||
Utils.showToast("${genericRespModel.message.toString()}");
|
||||
return;
|
||||
}
|
||||
if (genericRespModel.data == 1) {
|
||||
context.read<DashboardVmCustomer>().onNavbarTapped(1);
|
||||
applyFilterOnAppointmentsVM(appointmentStatusEnum: AppointmentStatusEnum.cancelled);
|
||||
Utils.showToast("${genericRespModel.message.toString()}");
|
||||
getMyAppointments();
|
||||
Utils.hideLoading(context);
|
||||
navigateReplaceWithNameUntilRoute(context, AppRoutes.dashboard);
|
||||
}
|
||||
} catch (e) {
|
||||
Utils.showToast("${e.toString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/main.dart';
|
||||
import 'package:mc_common_app/models/chat_models/cat_message_model.dart';
|
||||
import 'package:mc_common_app/repositories/chat_repo.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:signalr_core/signalr_core.dart';
|
||||
|
||||
class ChatVM extends ChangeNotifier {
|
||||
final ChatRepo chatRepo;
|
||||
|
||||
ChatVM({required this.chatRepo});
|
||||
|
||||
late HubConnection hubConnection;
|
||||
|
||||
List<ChatMessageModel> chatMessages = [];
|
||||
|
||||
String chatMessageText = "";
|
||||
|
||||
updateChatMessageText(String value) {
|
||||
chatMessageText = value;
|
||||
}
|
||||
|
||||
clearChatMessageText() {
|
||||
chatMessageText = "";
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> onNewMessageReceived({required List<ChatMessageModel> messages}) async {
|
||||
chatMessages.addAll(messages);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> buildHubConnection() async {
|
||||
// if (hubConnection.state != HubConnectionState.Connected) {
|
||||
try {
|
||||
hubConnection = await chatRepo.getHubConnection();
|
||||
await hubConnection.start();
|
||||
hubConnection.on("ReceiveMessageRequestOffer", (List<Object?>? arguments) {
|
||||
if (arguments == null || arguments.isEmpty) return;
|
||||
List<ChatMessageModel> chat = [];
|
||||
for (var message in arguments) {
|
||||
final chatMessage = ChatMessageModel.fromJson(message as Map<String, dynamic>);
|
||||
chat.add(chatMessage);
|
||||
}
|
||||
onNewMessageReceived(messages: chat);
|
||||
logger.i("I received ping : ${arguments.toString()}");
|
||||
});
|
||||
} catch (e) {
|
||||
logger.i("Error: ${e.toString()}");
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
// }
|
||||
}
|
||||
|
||||
Future<bool> onSendMessageForRequestOffer({
|
||||
required String receiverId,
|
||||
required ChatMessageTypeEnum chatMessageType,
|
||||
required String message,
|
||||
required int requestId,
|
||||
required String offerPrice,
|
||||
}) async {
|
||||
if (hubConnection.state != HubConnectionState.connected) {
|
||||
await buildHubConnection();
|
||||
}
|
||||
if (hubConnection.state == HubConnectionState.connected) {
|
||||
final providerId = AppState().getUser.data!.userInfo!.providerId;
|
||||
hubConnection.invoke(
|
||||
"SendMessageRequestOffer",
|
||||
args: <Object>[
|
||||
<String, dynamic>{
|
||||
"ReceiverUserID": receiverId,
|
||||
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
|
||||
"Message": message,
|
||||
"RequestID": requestId,
|
||||
"RequestOfferID": 0,
|
||||
"RequestOffer": <String, dynamic>{
|
||||
"RequestID": requestId,
|
||||
"Price": double.parse(offerPrice),
|
||||
"ServiceProviderID": providerId,
|
||||
"OfferStatus": RequestOfferStatusEnum.offer.getIdFromRequestOfferStatusEnum(),
|
||||
"Comment": message,
|
||||
},
|
||||
}
|
||||
],
|
||||
).catchError((e) {
|
||||
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
|
||||
Utils.showToast(e.toString());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<bool> onTextMessageSend({
|
||||
required String receiverId,
|
||||
required ChatMessageTypeEnum chatMessageType,
|
||||
required String message,
|
||||
required int requestId,
|
||||
required String offerPrice,
|
||||
}) async {
|
||||
if (message.isEmpty) return false;
|
||||
|
||||
if (hubConnection.state != HubConnectionState.connected) {
|
||||
await buildHubConnection();
|
||||
}
|
||||
if (hubConnection.state == HubConnectionState.connected) {
|
||||
final userId = AppState().getUser.data!.userInfo!.userId.toString();
|
||||
final name = AppState().getUser.data!.userInfo!.firstName.toString();
|
||||
hubConnection.invoke(
|
||||
"SendMessageRequestOffer",
|
||||
args: <Object>[
|
||||
<String, dynamic>{
|
||||
"ReceiverUserID": receiverId,
|
||||
"MessageType": chatMessageType.getIdFromChatMessageTypeEnum(),
|
||||
"Message": message,
|
||||
"RequestID": requestId,
|
||||
}
|
||||
],
|
||||
).catchError((e) {
|
||||
logger.i("error in invoking SendMessageRequestOffer: ${e.toString()}");
|
||||
Utils.showToast(e.toString());
|
||||
return false;
|
||||
});
|
||||
ChatMessageModel chatMessageModel = ChatMessageModel(
|
||||
messageType: chatMessageType.getIdFromChatMessageTypeEnum(),
|
||||
message: message,
|
||||
isMyMessage: true,
|
||||
requestID: requestId,
|
||||
senderName: name,
|
||||
senderUserID: userId,
|
||||
);
|
||||
|
||||
onNewMessageReceived(messages: [chatMessageModel]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import 'dart:io';
|
||||
import 'package:mc_common_app/classes/app_state.dart';
|
||||
import 'package:mc_common_app/generated/locale_keys.g.dart';
|
||||
import 'package:mc_common_app/models/user_models/image_response.dart';
|
||||
import 'package:mc_common_app/repositories/user_repo.dart';
|
||||
import 'package:mc_common_app/services/common_services.dart';
|
||||
import 'package:mc_common_app/utils/utils.dart';
|
||||
import 'package:mc_common_app/view_models/base_view_model.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
|
||||
class DashboardVmCustomer extends BaseVM {
|
||||
final CommonAppServices commonServices;
|
||||
final UserRepo userRepo;
|
||||
|
||||
DashboardVmCustomer({required this.commonServices, required this.userRepo});
|
||||
|
||||
String pickedImage = "";
|
||||
|
||||
int selectedNavbarBarIndex = 2;
|
||||
|
||||
void onNavbarTapped(int index) {
|
||||
selectedNavbarBarIndex = index;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void pickImageFromPhone(BuildContext context, int sourceFlag) async {
|
||||
final File? pickedImageFile = await commonServices.pickImageFromPhone(sourceFlag);
|
||||
if (pickedImageFile == null) {
|
||||
return;
|
||||
}
|
||||
int sizeInBytes = pickedImageFile.lengthSync();
|
||||
if (sizeInBytes > 1000) {
|
||||
Utils.showToast(LocaleKeys.fileLarger.tr());
|
||||
return;
|
||||
} else {
|
||||
String image64 = Utils.convertFileToBase64(pickedImageFile);
|
||||
|
||||
Utils.showLoading(context);
|
||||
ImageResponse response = await userRepo.updateUserImage(image64);
|
||||
Utils.hideLoading(context);
|
||||
Navigator.pop(context);
|
||||
if (response.messageStatus == 1) {
|
||||
Utils.showToast(LocaleKeys.imageUploaded.tr());
|
||||
AppState().getUser.data!.userInfo!.userImageUrl = response.data;
|
||||
} else {
|
||||
Utils.showToast(response.message ?? "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<ImageResponse> updateUserImage(String image) async {
|
||||
return await userRepo.updateUserImage(image);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/models/general_models/widgets_models.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/view_models/ad_view_model.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/search_entity_widget.dart';
|
||||
import 'package:mc_common_app/widgets/dropdown/dropdow_field.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AdsFilterView extends StatelessWidget {
|
||||
const AdsFilterView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Ads Filter",
|
||||
profileImageUrl: MyAssets.bnCar,
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
onBackButtonTapped: () {
|
||||
context.read<AdVM>().resetValues();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
body: Consumer<AdVM>(
|
||||
builder: (BuildContext context, AdVM adVM, Widget? child) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
context.read<AdVM>().resetValues();
|
||||
return true;
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
ListView(
|
||||
children: [
|
||||
20.height,
|
||||
SearchEntityWidget(
|
||||
title: "Search By Location",
|
||||
actionWidget: Builder(builder: (context) {
|
||||
List<DropValue> vehicleBrandsDrop = [];
|
||||
for (var element in adVM.vehicleCities) {
|
||||
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.cityName ?? "", ""));
|
||||
}
|
||||
return DropdownField(
|
||||
(DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
list: vehicleBrandsDrop,
|
||||
dropdownValue: adVM.vehicleCityId.selectedId != -1 ? DropValue(adVM.vehicleCityId.selectedId, adVM.vehicleCityId.selectedOption, "") : null,
|
||||
hint: "Select Location",
|
||||
errorValue: adVM.vehicleCityId.errorValue,
|
||||
);
|
||||
}),
|
||||
historyContent: adVM.vehicleLocationAdSearchHistory,
|
||||
onHistoryItemDeleted: (index) {
|
||||
adVM.removeVehicleLocationAdSearchHistory(index: index);
|
||||
},
|
||||
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleCityId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
),
|
||||
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
|
||||
SearchEntityWidget(
|
||||
title: "Search By Brand Name",
|
||||
actionWidget: Builder(builder: (context) {
|
||||
List<DropValue> vehicleBrandsDrop = [];
|
||||
for (var element in adVM.vehicleBrands) {
|
||||
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.vehicleBrandDescription ?? "", ""));
|
||||
}
|
||||
return DropdownField(
|
||||
(DropValue value) => adVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
list: vehicleBrandsDrop,
|
||||
dropdownValue: adVM.vehicleBrandId.selectedId != -1 ? DropValue(adVM.vehicleBrandId.selectedId, adVM.vehicleBrandId.selectedOption, "") : null,
|
||||
hint: "Select Vehicle Brand",
|
||||
errorValue: adVM.vehicleBrandId.errorValue,
|
||||
);
|
||||
}),
|
||||
historyContent: adVM.vehicleBrandsAdSearchHistory,
|
||||
onHistoryItemDeleted: (index) => adVM.removeVehicleBrandsAdSearchHistory(index: index),
|
||||
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleBrandId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
),
|
||||
const Divider(thickness: 1.2).paddingOnly(top: 7, bottom: 7),
|
||||
SearchEntityWidget(
|
||||
title: "Search By Year",
|
||||
actionWidget: Builder(builder: (context) {
|
||||
List<DropValue> vehicleBrandsDrop = [];
|
||||
for (var element in adVM.vehicleModelYears) {
|
||||
vehicleBrandsDrop.add(DropValue(element.id?.toInt() ?? 0, element.modelYear ?? "", ""));
|
||||
}
|
||||
return DropdownField(
|
||||
(DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
list: vehicleBrandsDrop,
|
||||
dropdownValue: adVM.vehicleModelYearId.selectedId != -1 ? DropValue(adVM.vehicleModelYearId.selectedId, adVM.vehicleModelYearId.selectedOption, "") : null,
|
||||
hint: "Select Year",
|
||||
errorValue: adVM.vehicleModelYearId.errorValue,
|
||||
);
|
||||
}),
|
||||
historyContent: adVM.vehicleYearAdSearchHistory,
|
||||
onHistoryItemDeleted: (index) => adVM.removeVehicleYearAdSearchHistory(index: index),
|
||||
onHistoryItemTapped: (DropValue value) => adVM.updateSelectionVehicleModelYearId(SelectionModel(selectedId: value.id, selectedOption: value.value), isForSearch: true),
|
||||
)
|
||||
],
|
||||
).expand(),
|
||||
Container(
|
||||
color: MyColors.white,
|
||||
child: Column(
|
||||
children: [
|
||||
5.height,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: "Search",
|
||||
onPressed: () {},
|
||||
backgroundColor: MyColors.darkPrimaryColor,
|
||||
txtColor: MyColors.white,
|
||||
fontSize: 18,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
10.height,
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
).horPaddingMain(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
|
||||
class AdsSearchFilterView extends StatelessWidget {
|
||||
const AdsSearchFilterView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Filter Ads",
|
||||
profileImageUrl: MyAssets.bnCar,
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,245 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/appointment_list_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/service_model.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/dialogs_and_bottomsheets.dart';
|
||||
import 'package:mc_common_app/utils/enums.dart';
|
||||
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/card_button_with_icon.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class AppointmentDetailView extends StatelessWidget {
|
||||
final AppointmentListModel appointmentListModel;
|
||||
|
||||
AppointmentDetailView({Key? key, required this.appointmentListModel}) : super(key: key);
|
||||
|
||||
Widget getBaseActionButtonWidget({required Color color, required String text, Color textColor = MyColors.white, required Function() onPressed}) {
|
||||
return Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: text,
|
||||
onPressed: onPressed,
|
||||
backgroundColor: color,
|
||||
txtColor: textColor,
|
||||
fontSize: 18,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBottomActionButton({required AppointmentStatusEnum appointmentStatusEnum, required BuildContext context}) {
|
||||
switch (appointmentStatusEnum) {
|
||||
case AppointmentStatusEnum.booked:
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
|
||||
12.width,
|
||||
getBaseActionButtonWidget(
|
||||
color: MyColors.greenColor,
|
||||
onPressed: () {
|
||||
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
||||
},
|
||||
text: "Confirm"),
|
||||
],
|
||||
),
|
||||
);
|
||||
case AppointmentStatusEnum.confirmed:
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
|
||||
],
|
||||
),
|
||||
);
|
||||
case AppointmentStatusEnum.arrived:
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "In Progress"),
|
||||
],
|
||||
),
|
||||
);
|
||||
case AppointmentStatusEnum.cancelled:
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
getBaseActionButtonWidget(color: MyColors.grey98Color.withOpacity(0.3), textColor: MyColors.lightTextColor, onPressed: () {}, text: "Cancelled"),
|
||||
],
|
||||
),
|
||||
);
|
||||
case AppointmentStatusEnum.allAppointments:
|
||||
return SizedBox();
|
||||
case AppointmentStatusEnum.rescheduled:
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
getBaseActionButtonWidget(color: MyColors.redColor, onPressed: () => appointmentCancelConfirmationSheet(context), text: "Cancel"),
|
||||
12.width,
|
||||
getBaseActionButtonWidget(
|
||||
color: MyColors.greenColor,
|
||||
onPressed: () {
|
||||
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
||||
},
|
||||
text: "Confirm"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void appointmentCancelConfirmationSheet(BuildContext context) {
|
||||
final appointmentsVm = context.read<AppointmentsVM>();
|
||||
return actionConfirmationBottomSheet(
|
||||
context: context,
|
||||
title: "Do you want to cancel this appointment?".toText(fontSize: 28, isBold: true, letterSpacing: -1.44),
|
||||
subtitle: "Your appointment will be cancelled and you cannot undo this action.",
|
||||
actionButtonYes: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: "Yes",
|
||||
fontSize: 15,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
appointmentsVm.onCancelAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
||||
},
|
||||
),
|
||||
),
|
||||
actionButtonNo: Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
isFilled: false,
|
||||
borderColor: MyColors.darkPrimaryColor,
|
||||
title: "No",
|
||||
txtColor: MyColors.darkPrimaryColor,
|
||||
fontSize: 15,
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
AppointmentsVM appointmentsVM = context.read<AppointmentsVM>();
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Appointment",
|
||||
profileImageUrl: MyAssets.bnCar,
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.only(bottom: 10, left: 21, right: 21),
|
||||
child: Stack(
|
||||
children: [
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
appointmentListModel.providerName!.toText(fontSize: 16, isBold: true),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
MyAssets.miniClockDark.buildSvg(
|
||||
height: 12,
|
||||
width: 12,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
5.width,
|
||||
"${appointmentListModel.duration ?? ""} ${appointmentListModel.appointmentDate!.toFormattedDateWithoutTime()}".toText(fontSize: 12, isBold: true, color: MyColors.lightTextColor),
|
||||
],
|
||||
),
|
||||
13.height,
|
||||
if (appointmentListModel.appointmentServicesList != null && appointmentListModel.appointmentServicesList!.isNotEmpty) ...[
|
||||
Column(
|
||||
children: List.generate(appointmentListModel.appointmentServicesList!.length, (index) {
|
||||
ServiceModel service = appointmentListModel.appointmentServicesList![index];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
// MyAssets.maintenanceIcon.buildSvg(
|
||||
// height: 10,
|
||||
// width: 10,
|
||||
// fit: BoxFit.fill,
|
||||
// ),
|
||||
// 10.width,
|
||||
"${index + 1}. ${service.providerServiceDescription}".toText(fontSize: 14, isBold: true),
|
||||
],
|
||||
),
|
||||
if (service.serviceItems != null && service.serviceItems!.isNotEmpty) ...[
|
||||
Column(
|
||||
children: List.generate(
|
||||
service.serviceItems!.length,
|
||||
(index) => "${service.serviceItems![index].name}".toText(
|
||||
textAlign: TextAlign.start,
|
||||
fontSize: 12,
|
||||
color: MyColors.lightTextColor,
|
||||
),
|
||||
),
|
||||
).paddingOnly(left: 15),
|
||||
],
|
||||
5.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
((service.currentTotalServicePrice).toString()).toText(fontSize: 25, isBold: true),
|
||||
2.width,
|
||||
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
|
||||
Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 30,
|
||||
)
|
||||
],
|
||||
).onPress(() => appointmentsVM.priceBreakDownClicked(context, service)),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
15.height,
|
||||
Row(
|
||||
children: [
|
||||
CardButtonWithIcon(
|
||||
title: "Reschedule Appointment",
|
||||
onCardTapped: () {
|
||||
context.read<AppointmentsVM>().onRescheduleAppointmentPressed(context: context, appointmentListModel: appointmentListModel);
|
||||
},
|
||||
icon: MyAssets.scheduleAppointmentIcon.buildSvg(),
|
||||
),
|
||||
if (appointmentListModel.appointmentStatusEnum == AppointmentStatusEnum.booked) ...[
|
||||
10.width,
|
||||
CardButtonWithIcon(
|
||||
title: "Pay for Appointment",
|
||||
onCardTapped: () {
|
||||
context.read<AppointmentsVM>().onConfirmAppointmentPressed(context: context, appointmentId: appointmentListModel.id);
|
||||
},
|
||||
icon: MyAssets.creditCardIcon.buildSvg(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
15.height,
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, allPading: 12),
|
||||
buildBottomActionButton(appointmentStatusEnum: appointmentListModel.appointmentStatusEnum!, context: context),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,162 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/models/appointments_models/service_schedule_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/service_model.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||
import 'package:mc_common_app/views/appointments/widgets/custom_calender_widget.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/time_slots.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ScreenArgumentsForAppointmentDetailPage {
|
||||
final int routeFlag; // 1 = coming from create appointment || 2 = coming from reschedule appointment
|
||||
final int appointmentId; // 1 = coming from create appointment || 2 = coming from reschedule appointment
|
||||
|
||||
ScreenArgumentsForAppointmentDetailPage({required this.routeFlag, required this.appointmentId});
|
||||
}
|
||||
|
||||
class BookAppointmentSchedulesView extends StatelessWidget {
|
||||
final ScreenArgumentsForAppointmentDetailPage screenArgumentsForAppointmentDetailPage;
|
||||
|
||||
BookAppointmentSchedulesView({Key? key, required this.screenArgumentsForAppointmentDetailPage}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Book Appointment",
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
onBackButtonTapped: () => Navigator.pop(context),
|
||||
),
|
||||
body: Consumer(
|
||||
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
21.height,
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: appointmentsVM.serviceAppointmentScheduleList.length,
|
||||
itemBuilder: (BuildContext context, int scheduleIndex) {
|
||||
ServiceAppointmentScheduleModel scheduleData = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex];
|
||||
return ExpansionTile(
|
||||
tilePadding: EdgeInsets.symmetric(horizontal: 21, vertical: 10),
|
||||
childrenPadding: EdgeInsets.only(left: 16, bottom: 10, right: 16),
|
||||
title: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: "Schedule ${scheduleIndex + 1}".toText(fontSize: 20, isBold: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||
("${scheduleData.appointmentType == 2 ? "Home" : "Workshop"}").toText(fontSize: 12, isBold: true).expand(),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
5.height,
|
||||
ListView.builder(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment!.length,
|
||||
itemBuilder: (BuildContext context, int serviceIndex) {
|
||||
ServiceModel selectedService = appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].servicesListInAppointment![serviceIndex];
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ("${serviceIndex + 1}. ${selectedService.providerServiceDescription}").toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
CustomCalenderAppointmentWidget(
|
||||
customTimeDateSlotList: scheduleData.customTimeDateSlotList ?? [],
|
||||
onDateSelected: (int dateIndex) {
|
||||
appointmentsVM.updateSelectedAppointmentDate(scheduleIndex: scheduleIndex, dateIndex: dateIndex);
|
||||
},
|
||||
selectedCustomTimeDateSlotModel: scheduleData.selectedCustomTimeDateSlotModel),
|
||||
if (appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex != null) ...[
|
||||
5.height,
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
("Available Slots").toText(fontSize: 14, isBold: true),
|
||||
],
|
||||
),
|
||||
5.height,
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: BuildTimeSlots(
|
||||
timeSlots: appointmentsVM.serviceAppointmentScheduleList[scheduleIndex]
|
||||
.customTimeDateSlotList![appointmentsVM.serviceAppointmentScheduleList[scheduleIndex].selectedDateIndex!].availableSlots ??
|
||||
[],
|
||||
onPressed: (slotIndex) {
|
||||
appointmentsVM.updateSelectedAppointmentSlotByDate(scheduleIndex: scheduleIndex, slotIndex: slotIndex);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
|
||||
},
|
||||
).expand(),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
txtColor: MyColors.black,
|
||||
maxHeight: 55,
|
||||
title: "Cancel",
|
||||
onPressed: () => Navigator.pop(context),
|
||||
backgroundColor: MyColors.greyButtonColor,
|
||||
),
|
||||
),
|
||||
12.width,
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: screenArgumentsForAppointmentDetailPage.routeFlag == 1 ? "Review" : "Confirm",
|
||||
onPressed: () {
|
||||
if (screenArgumentsForAppointmentDetailPage.routeFlag == 1) {
|
||||
appointmentsVM.onReviewButtonPressed(context);
|
||||
} else {
|
||||
appointmentsVM.onRescheduleAppointmentConfirmPressed(
|
||||
context: context,
|
||||
appointmentId: screenArgumentsForAppointmentDetailPage.appointmentId,
|
||||
selectedSlotId: appointmentsVM.serviceAppointmentScheduleList.first.selectedCustomTimeDateSlotModel!.date!.slotId,
|
||||
);
|
||||
}
|
||||
},
|
||||
backgroundColor: MyColors.darkPrimaryColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
).paddingAll(21)
|
||||
],
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/models/services_models/item_model.dart';
|
||||
import 'package:mc_common_app/models/services_models/service_model.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||
import 'package:mc_common_app/views/advertisement/custom_add_button.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class BookAppointmentServicesView extends StatelessWidget {
|
||||
BookAppointmentServicesView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Book Appointment",
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
onBackButtonTapped: () {
|
||||
context.read<AppointmentsVM>().resetAfterBookingAppointment();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
body: Consumer(
|
||||
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
21.height,
|
||||
CustomAddButton(
|
||||
needsBorder: true,
|
||||
bgColor: MyColors.white,
|
||||
onTap: () => appointmentsVM.openTheAddServiceBottomSheet(context, appointmentsVM),
|
||||
text: "Add Services",
|
||||
icon: Container(
|
||||
height: 24,
|
||||
width: 24,
|
||||
decoration: const BoxDecoration(shape: BoxShape.circle, color: MyColors.darkTextColor),
|
||||
child: const Icon(Icons.add, color: MyColors.white),
|
||||
),
|
||||
).horPaddingMain(),
|
||||
10.height,
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
itemCount: appointmentsVM.servicesInCurrentAppointment.length,
|
||||
itemBuilder: (BuildContext context, int serviceIndex) {
|
||||
ServiceModel serviceData = appointmentsVM.servicesInCurrentAppointment[serviceIndex];
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: (serviceData.serviceDescription ?? "").toText(fontSize: 15, isBold: true),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () => appointmentsVM.removeServiceInCurrentAppointment(serviceIndex),
|
||||
icon: Icon(Icons.delete_outline, color: MyColors.redColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
if (true) ...[
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Service Location: ".toText(fontSize: 12, color: MyColors.lightTextColor, isBold: true),
|
||||
(serviceData.isHomeSelected ? serviceData.homeLocation : "Workshop").toText(fontSize: 12, isBold: true).expand(),
|
||||
],
|
||||
),
|
||||
5.height,
|
||||
Column(
|
||||
children: List.generate(serviceData.serviceItems!.length, (itemIndex) {
|
||||
ItemData itemData = serviceData.serviceItems![itemIndex];
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"${itemData.name}: ".toText(fontSize: 13, color: MyColors.lightTextColor, isBold: true),
|
||||
("${itemData.price}").toText(fontSize: 13, isBold: true).expand(),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
8.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
((appointmentsVM.servicesInCurrentAppointment[serviceIndex].currentTotalServicePrice).toString()).toText(fontSize: 32, isBold: true),
|
||||
2.width,
|
||||
"SAR".toText(color: MyColors.lightTextColor, fontSize: 16, isBold: true).paddingOnly(bottom: 5),
|
||||
Icon(
|
||||
Icons.arrow_drop_down,
|
||||
size: 30,
|
||||
)
|
||||
],
|
||||
).onPress(() => appointmentsVM.priceBreakDownClicked(context, appointmentsVM.servicesInCurrentAppointment[serviceIndex])),
|
||||
],
|
||||
],
|
||||
).toWhiteContainer(width: double.infinity, allPading: 12, margin: const EdgeInsets.symmetric(horizontal: 21, vertical: 10));
|
||||
},
|
||||
).expand(),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
txtColor: MyColors.black,
|
||||
maxHeight: 55,
|
||||
title: "Cancel",
|
||||
onPressed: () {
|
||||
appointmentsVM.servicesInCurrentAppointment.clear();
|
||||
appointmentsVM.allSelectedItemsInAppointments.clear();
|
||||
Navigator.pop(context);
|
||||
},
|
||||
backgroundColor: MyColors.greyButtonColor,
|
||||
),
|
||||
),
|
||||
12.width,
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: "Next",
|
||||
onPressed: () {
|
||||
appointmentsVM.onServicesNextPressed(context);
|
||||
},
|
||||
backgroundColor: MyColors.darkPrimaryColor,
|
||||
),
|
||||
)
|
||||
],
|
||||
).paddingAll(21)
|
||||
],
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_common_app/classes/consts.dart';
|
||||
import 'package:mc_common_app/extensions/int_extensions.dart';
|
||||
import 'package:mc_common_app/extensions/string_extensions.dart';
|
||||
import 'package:mc_common_app/models/services_models/item_model.dart';
|
||||
import 'package:mc_common_app/theme/colors.dart';
|
||||
import 'package:mc_common_app/utils/navigator.dart';
|
||||
import 'package:mc_common_app/view_models/appointments_view_model.dart';
|
||||
import 'package:mc_common_app/views/appointments/widgets/service_item_with_price_checkbox.dart';
|
||||
import 'package:mc_common_app/widgets/button/show_fill_button.dart';
|
||||
import 'package:mc_common_app/widgets/common_widgets/app_bar.dart';
|
||||
import 'package:mc_common_app/widgets/extensions/extensions_widget.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class BookAppointmentsItemView extends StatelessWidget {
|
||||
const BookAppointmentsItemView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: "Select Items",
|
||||
isRemoveBackButton: false,
|
||||
isDrawerEnabled: false,
|
||||
actions: [MyAssets.searchIcon.buildSvg().paddingOnly(right: 21)],
|
||||
onBackButtonTapped: () => Navigator.pop(context),
|
||||
),
|
||||
body: Consumer(
|
||||
builder: (BuildContext context, AppointmentsVM appointmentsVM, Widget? child) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
height: 40,
|
||||
width: double.infinity,
|
||||
color: MyColors.darkTextColor,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: "${appointmentsVM.selectedSubServicesCounter} Item(s) Selected".toText(fontSize: 16, color: MyColors.white).horPaddingMain(),
|
||||
),
|
||||
16.height,
|
||||
Column(
|
||||
children: [
|
||||
"Few services are not available on home location. Change the location to workshop to full access the services".toText(fontSize: 12, isItalic: true, color: MyColors.lightTextColor),
|
||||
8.height,
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
"Change location or service: ".toText(fontSize: 14, isBold: true),
|
||||
"Edit".toText(fontSize: 14, isBold: true, isUnderLine: true, color: MyColors.adPendingStatusColor),
|
||||
5.width,
|
||||
MyAssets.icEdit.buildSvg(width: 17),
|
||||
],
|
||||
).onPress(() {}),
|
||||
16.height,
|
||||
Divider(),
|
||||
],
|
||||
).horPaddingMain(),
|
||||
appointmentsVM.serviceItemsFromApi.isEmpty
|
||||
? Expanded(child: Center(child: "No Items to show.".toText(fontSize: 16, color: MyColors.lightTextColor)))
|
||||
: ListView.separated(
|
||||
separatorBuilder: (BuildContext context, int index) => Divider(),
|
||||
itemCount: appointmentsVM.serviceItemsFromApi.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
ItemData itemData = appointmentsVM.serviceItemsFromApi[index];
|
||||
return ServiceItemWithPriceCheckBox(
|
||||
description: itemData.description ?? "Some description about the sub-services",
|
||||
title: itemData.name!,
|
||||
isSelected: itemData.isUpdateOrSelected!,
|
||||
onSelection: (bool value) {
|
||||
print("itemId: ${itemData.id}");
|
||||
appointmentsVM.onItemUpdateOrSelected(index, !itemData.isUpdateOrSelected!, itemData.id!);
|
||||
},
|
||||
priceWidget: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
// TODO: This Price will be decided according to the service selected
|
||||
itemData.price!.split(".").first.toText(fontSize: 30, isBold: true),
|
||||
" SAR".toText(fontSize: 15, isBold: true, color: MyColors.lightTextColor).paddingOnly(bottom: 5),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
).expand(),
|
||||
Column(
|
||||
children: [
|
||||
Divider(
|
||||
height: 1,
|
||||
thickness: 0.7,
|
||||
),
|
||||
8.height,
|
||||
if (appointmentsVM.selectSubServicesError != "")
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
appointmentsVM.selectSubServicesError.toText(fontSize: 14, color: Colors.red),
|
||||
],
|
||||
).paddingOnly(right: 10),
|
||||
8.height,
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ShowFillButton(
|
||||
txtColor: MyColors.black,
|
||||
maxHeight: 55,
|
||||
title: "Cancel",
|
||||
onPressed: () {
|
||||
appointmentsVM.resetCategorySelectionBottomSheet();
|
||||
pop(context);
|
||||
},
|
||||
backgroundColor: MyColors.greyButtonColor,
|
||||
),
|
||||
),
|
||||
12.width,
|
||||
Expanded(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return ShowFillButton(
|
||||
maxHeight: 55,
|
||||
title: "Next",
|
||||
onPressed: () async {
|
||||
bool resp = appointmentsVM.validateItemsSelection();
|
||||
if (resp) {
|
||||
appointmentsVM.onItemsSelectedInService();
|
||||
Navigator.pop(context);
|
||||
}
|
||||
// bool resp = appointmentsVM.validateItemsSelection();
|
||||
// if (resp) {
|
||||
// Utils.showLoading(context);
|
||||
// await appointmentsVM.mergeServiceIntoAvailableSchedules();
|
||||
// appointmentsVM.resetCategorySelectionBottomSheet();
|
||||
// Utils.hideLoading(context);
|
||||
// Navigator.of(context).pushReplacementNamed(AppRoutes.bookAppointmenServicesView);
|
||||
// }
|
||||
},
|
||||
backgroundColor: !appointmentsVM.isServiceSelectionValidated() ? MyColors.lightTextColor.withOpacity(0.6) : MyColors.darkPrimaryColor,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
).horPaddingMain(),
|
||||
16.height,
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue