add dashboard to phone app

This commit is contained in:
root
2026-05-25 05:10:43 -04:00
parent d04c8ce437
commit 277db06d26
67 changed files with 7872 additions and 570 deletions
+1 -1
View File
@@ -193,7 +193,7 @@ class MarketplaceOffer {
String get discountLabel {
switch (type) {
case 'PERCENTAGE':
return '${discountValue}% off';
return '$discountValue% off';
case 'FIXED_AMOUNT':
return '\$${(discountValue / 100).toStringAsFixed(0)} off';
case 'FREE_DAY':
+31
View File
@@ -0,0 +1,31 @@
class AppNotification {
final String id;
final String type;
final String title;
final String body;
final bool isRead;
final DateTime createdAt;
final Map<String, dynamic>? data;
const AppNotification({
required this.id,
required this.type,
required this.title,
required this.body,
required this.isRead,
required this.createdAt,
this.data,
});
factory AppNotification.fromJson(Map<String, dynamic> json) =>
AppNotification(
id: json['id'] as String,
type: json['type'] as String? ?? '',
title: json['title'] as String? ?? '',
body: json['body'] as String? ?? '',
isRead: json['isRead'] as bool? ?? false,
createdAt: DateTime.parse(
json['createdAt'] as String? ?? DateTime.now().toIso8601String()),
data: json['data'] as Map<String, dynamic>?,
);
}
+68
View File
@@ -0,0 +1,68 @@
class CompanyOffer {
final String id;
final String title;
final String? description;
final String type; // PERCENTAGE | FIXED_AMOUNT | FREE_DAY | SPECIAL_RATE
final int discountValue;
final String? promoCode;
final bool isActive;
final bool isPublic;
final bool isFeatured;
final DateTime validFrom;
final DateTime validUntil;
final int? maxRedemptions;
final int redemptionCount;
final List<String> categories;
const CompanyOffer({
required this.id,
required this.title,
this.description,
required this.type,
required this.discountValue,
this.promoCode,
required this.isActive,
required this.isPublic,
required this.isFeatured,
required this.validFrom,
required this.validUntil,
this.maxRedemptions,
required this.redemptionCount,
required this.categories,
});
String get discountLabel {
switch (type) {
case 'PERCENTAGE':
return '$discountValue% off';
case 'FIXED_AMOUNT':
return '\$${(discountValue / 100).toStringAsFixed(0)} off';
case 'FREE_DAY':
return '$discountValue free day${discountValue == 1 ? '' : 's'}';
case 'SPECIAL_RATE':
return 'Special rate';
default:
return 'Offer';
}
}
factory CompanyOffer.fromJson(Map<String, dynamic> json) => CompanyOffer(
id: json['id'] as String,
title: json['title'] as String,
description: json['description'] as String?,
type: json['type'] as String? ?? 'PERCENTAGE',
discountValue: json['discountValue'] as int? ?? 0,
promoCode: json['promoCode'] as String?,
isActive: json['isActive'] as bool? ?? true,
isPublic: json['isPublic'] as bool? ?? false,
isFeatured: json['isFeatured'] as bool? ?? false,
validFrom: DateTime.parse(json['validFrom'] as String),
validUntil: DateTime.parse(json['validUntil'] as String),
maxRedemptions: json['maxRedemptions'] as int?,
redemptionCount: json['redemptionCount'] as int? ?? 0,
categories: (json['categories'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
[],
);
}
+62
View File
@@ -0,0 +1,62 @@
class ReportSummary {
final int totalReservations;
final double rentalRevenue;
final double totalPaid;
final double totalOutstanding;
final List<ReportItem> items;
const ReportSummary({
required this.totalReservations,
required this.rentalRevenue,
required this.totalPaid,
required this.totalOutstanding,
required this.items,
});
factory ReportSummary.fromJson(Map<String, dynamic> json) => ReportSummary(
totalReservations: json['totalReservations'] as int? ?? 0,
rentalRevenue: (json['rentalRevenue'] as num?)?.toDouble() ?? 0,
totalPaid: (json['totalPaid'] as num?)?.toDouble() ?? 0,
totalOutstanding:
(json['totalOutstanding'] as num?)?.toDouble() ?? 0,
items: (json['reservations'] as List<dynamic>? ?? [])
.map((e) => ReportItem.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
class ReportItem {
final String id;
final String? customerName;
final String? vehicleName;
final DateTime startDate;
final DateTime endDate;
final double totalAmount;
final String status;
final String paymentStatus;
final String? source;
const ReportItem({
required this.id,
this.customerName,
this.vehicleName,
required this.startDate,
required this.endDate,
required this.totalAmount,
required this.status,
required this.paymentStatus,
this.source,
});
factory ReportItem.fromJson(Map<String, dynamic> json) => ReportItem(
id: json['id'] as String,
customerName: json['customerName'] as String?,
vehicleName: json['vehicleName'] as String?,
startDate: DateTime.parse(json['startDate'] as String),
endDate: DateTime.parse(json['endDate'] as String),
totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? 0,
status: json['status'] as String? ?? '',
paymentStatus: json['paymentStatus'] as String? ?? '',
source: json['source'] as String?,
);
}
+6
View File
@@ -11,6 +11,8 @@ class Reservation {
final CustomerSummary? customer;
final DateTime createdAt;
final String? source;
final String? contractNumber;
final String? invoiceNumber;
const Reservation({
required this.id,
@@ -25,6 +27,8 @@ class Reservation {
this.customer,
required this.createdAt,
this.source,
this.contractNumber,
this.invoiceNumber,
});
int get days => endDate.difference(startDate).inDays;
@@ -49,6 +53,8 @@ class Reservation {
createdAt: DateTime.parse(
json['createdAt'] as String? ?? DateTime.now().toIso8601String()),
source: json['source'] as String?,
contractNumber: json['contractNumber'] as String?,
invoiceNumber: json['invoiceNumber'] as String?,
);
}
+63
View File
@@ -0,0 +1,63 @@
class BrandSettings {
final String displayName;
final String? tagline;
final String? publicEmail;
final String? publicPhone;
final String? publicCity;
final String? publicCountry;
final String? websiteUrl;
final String? whatsappNumber;
final String? logoUrl;
final String primaryColor;
final bool isListedOnMarketplace;
final String? defaultLocale;
final String? defaultCurrency;
const BrandSettings({
required this.displayName,
this.tagline,
this.publicEmail,
this.publicPhone,
this.publicCity,
this.publicCountry,
this.websiteUrl,
this.whatsappNumber,
this.logoUrl,
required this.primaryColor,
required this.isListedOnMarketplace,
this.defaultLocale,
this.defaultCurrency,
});
factory BrandSettings.fromJson(Map<String, dynamic> json) => BrandSettings(
displayName: json['displayName'] as String? ?? '',
tagline: json['tagline'] as String?,
publicEmail: json['publicEmail'] as String?,
publicPhone: json['publicPhone'] as String?,
publicCity: json['publicCity'] as String?,
publicCountry: json['publicCountry'] as String?,
websiteUrl: json['websiteUrl'] as String?,
whatsappNumber: json['whatsappNumber'] as String?,
logoUrl: json['logoUrl'] as String?,
primaryColor: json['primaryColor'] as String? ?? '#1A56DB',
isListedOnMarketplace:
json['isListedOnMarketplace'] as bool? ?? false,
defaultLocale: json['defaultLocale'] as String?,
defaultCurrency: json['defaultCurrency'] as String?,
);
Map<String, dynamic> toJson() => {
'displayName': displayName,
if (tagline != null) 'tagline': tagline,
if (publicEmail != null) 'publicEmail': publicEmail,
if (publicPhone != null) 'publicPhone': publicPhone,
if (publicCity != null) 'publicCity': publicCity,
if (publicCountry != null) 'publicCountry': publicCountry,
if (websiteUrl != null) 'websiteUrl': websiteUrl,
if (whatsappNumber != null) 'whatsappNumber': whatsappNumber,
'primaryColor': primaryColor,
'isListedOnMarketplace': isListedOnMarketplace,
if (defaultLocale != null) 'defaultLocale': defaultLocale,
if (defaultCurrency != null) 'defaultCurrency': defaultCurrency,
};
}
+3
View File
@@ -12,6 +12,7 @@ class Vehicle {
final int? seats;
final String? transmission;
final String? fuelType;
final String? color;
final bool isPublished;
const Vehicle({
@@ -28,6 +29,7 @@ class Vehicle {
this.seats,
this.transmission,
this.fuelType,
this.color,
required this.isPublished,
});
@@ -52,6 +54,7 @@ class Vehicle {
seats: json['seats'] as int?,
transmission: json['transmission'] as String?,
fuelType: json['fuelType'] as String?,
color: json['color'] as String?,
isPublished: json['isPublished'] as bool? ?? false,
);
}