first app design
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
class DashboardMetrics {
|
||||
final int totalReservations;
|
||||
final int activeReservations;
|
||||
final double totalRevenue;
|
||||
final int totalVehicles;
|
||||
final int availableVehicles;
|
||||
final int totalCustomers;
|
||||
final double occupancyRate;
|
||||
|
||||
const DashboardMetrics({
|
||||
required this.totalReservations,
|
||||
required this.activeReservations,
|
||||
required this.totalRevenue,
|
||||
required this.totalVehicles,
|
||||
required this.availableVehicles,
|
||||
required this.totalCustomers,
|
||||
required this.occupancyRate,
|
||||
});
|
||||
|
||||
factory DashboardMetrics.fromJson(Map<String, dynamic> json) =>
|
||||
DashboardMetrics(
|
||||
totalReservations: json['totalReservations'] as int? ?? 0,
|
||||
activeReservations: json['activeReservations'] as int? ?? 0,
|
||||
totalRevenue: (json['totalRevenue'] as num?)?.toDouble() ?? 0,
|
||||
totalVehicles: json['totalVehicles'] as int? ?? 0,
|
||||
availableVehicles: json['availableVehicles'] as int? ?? 0,
|
||||
totalCustomers: json['totalCustomers'] as int? ?? 0,
|
||||
occupancyRate: (json['occupancyRate'] as num?)?.toDouble() ?? 0,
|
||||
);
|
||||
|
||||
factory DashboardMetrics.empty() => const DashboardMetrics(
|
||||
totalReservations: 0,
|
||||
activeReservations: 0,
|
||||
totalRevenue: 0,
|
||||
totalVehicles: 0,
|
||||
availableVehicles: 0,
|
||||
totalCustomers: 0,
|
||||
occupancyRate: 0,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
class Employee {
|
||||
final String id;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String email;
|
||||
final String role;
|
||||
final bool isActive;
|
||||
final String? companyId;
|
||||
|
||||
const Employee({
|
||||
required this.id,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.email,
|
||||
required this.role,
|
||||
required this.isActive,
|
||||
this.companyId,
|
||||
});
|
||||
|
||||
String get fullName => '$firstName $lastName';
|
||||
|
||||
factory Employee.fromJson(Map<String, dynamic> json) => Employee(
|
||||
id: json['id'] as String,
|
||||
firstName: json['firstName'] as String,
|
||||
lastName: json['lastName'] as String,
|
||||
email: json['email'] as String,
|
||||
role: json['role'] as String,
|
||||
isActive: json['isActive'] as bool? ?? true,
|
||||
companyId: json['companyId'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
class Renter {
|
||||
final String id;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String email;
|
||||
|
||||
const Renter({
|
||||
required this.id,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.email,
|
||||
});
|
||||
|
||||
String get fullName => '$firstName $lastName';
|
||||
|
||||
factory Renter.fromJson(Map<String, dynamic> json) => Renter(
|
||||
id: json['id'] as String,
|
||||
firstName: json['firstName'] as String,
|
||||
lastName: json['lastName'] as String,
|
||||
email: json['email'] as String,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
class Customer {
|
||||
final String id;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String? email;
|
||||
final String? phone;
|
||||
final String licenseStatus;
|
||||
final bool isFlagged;
|
||||
final String? flagReason;
|
||||
final DateTime? dateOfBirth;
|
||||
final String? nationality;
|
||||
final DateTime createdAt;
|
||||
|
||||
const Customer({
|
||||
required this.id,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
this.email,
|
||||
this.phone,
|
||||
required this.licenseStatus,
|
||||
required this.isFlagged,
|
||||
this.flagReason,
|
||||
this.dateOfBirth,
|
||||
this.nationality,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
String get fullName => '$firstName $lastName';
|
||||
|
||||
factory Customer.fromJson(Map<String, dynamic> json) => Customer(
|
||||
id: json['id'] as String,
|
||||
firstName: json['firstName'] as String,
|
||||
lastName: json['lastName'] as String,
|
||||
email: json['email'] as String?,
|
||||
phone: json['phone'] as String?,
|
||||
licenseStatus: json['licenseStatus'] as String? ?? 'PENDING',
|
||||
isFlagged: json['isFlagged'] as bool? ?? false,
|
||||
flagReason: json['flagReason'] as String?,
|
||||
dateOfBirth: json['dateOfBirth'] != null
|
||||
? DateTime.tryParse(json['dateOfBirth'] as String)
|
||||
: null,
|
||||
nationality: json['nationality'] as String?,
|
||||
createdAt: DateTime.parse(
|
||||
json['createdAt'] as String? ?? DateTime.now().toIso8601String()),
|
||||
);
|
||||
}
|
||||
|
||||
class CustomerListResponse {
|
||||
final List<Customer> data;
|
||||
final int total;
|
||||
final int page;
|
||||
final int pageSize;
|
||||
|
||||
const CustomerListResponse({
|
||||
required this.data,
|
||||
required this.total,
|
||||
required this.page,
|
||||
required this.pageSize,
|
||||
});
|
||||
|
||||
factory CustomerListResponse.fromJson(Map<String, dynamic> json) =>
|
||||
CustomerListResponse(
|
||||
data: (json['data'] as List<dynamic>)
|
||||
.map((e) => Customer.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
total: json['total'] as int? ?? 0,
|
||||
page: json['page'] as int? ?? 1,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
class CompanyBrand {
|
||||
final String displayName;
|
||||
final String? logoUrl;
|
||||
final String subdomain;
|
||||
final double? marketplaceRating;
|
||||
final String primaryColor;
|
||||
|
||||
const CompanyBrand({
|
||||
required this.displayName,
|
||||
this.logoUrl,
|
||||
required this.subdomain,
|
||||
this.marketplaceRating,
|
||||
required this.primaryColor,
|
||||
});
|
||||
|
||||
factory CompanyBrand.fromJson(Map<String, dynamic> json) => CompanyBrand(
|
||||
displayName: json['displayName'] as String? ?? '',
|
||||
logoUrl: json['logoUrl'] as String?,
|
||||
subdomain: json['subdomain'] as String? ?? '',
|
||||
marketplaceRating:
|
||||
(json['marketplaceRating'] as num?)?.toDouble(),
|
||||
primaryColor: json['primaryColor'] as String? ?? '#1A56DB',
|
||||
);
|
||||
}
|
||||
|
||||
class MarketplaceCompany {
|
||||
final String id;
|
||||
final CompanyBrand brand;
|
||||
|
||||
const MarketplaceCompany({required this.id, required this.brand});
|
||||
|
||||
factory MarketplaceCompany.fromJson(Map<String, dynamic> json) =>
|
||||
MarketplaceCompany(
|
||||
id: json['id'] as String,
|
||||
brand: CompanyBrand.fromJson(
|
||||
json['brand'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
|
||||
class MarketplaceVehicle {
|
||||
final String id;
|
||||
final String companyId;
|
||||
final String make;
|
||||
final String model;
|
||||
final int year;
|
||||
final String? color;
|
||||
final String licensePlate;
|
||||
final String category;
|
||||
final int seats;
|
||||
final String transmission;
|
||||
final String fuelType;
|
||||
final List<String> features;
|
||||
// dailyRate comes in cents from the API
|
||||
final int dailyRateCents;
|
||||
final String status;
|
||||
final List<String> photos;
|
||||
final int? mileage;
|
||||
final bool isPublished;
|
||||
final MarketplaceCompany company;
|
||||
final bool availability;
|
||||
final String availabilityStatus;
|
||||
final DateTime? nextAvailableAt;
|
||||
|
||||
const MarketplaceVehicle({
|
||||
required this.id,
|
||||
required this.companyId,
|
||||
required this.make,
|
||||
required this.model,
|
||||
required this.year,
|
||||
this.color,
|
||||
required this.licensePlate,
|
||||
required this.category,
|
||||
required this.seats,
|
||||
required this.transmission,
|
||||
required this.fuelType,
|
||||
required this.features,
|
||||
required this.dailyRateCents,
|
||||
required this.status,
|
||||
required this.photos,
|
||||
this.mileage,
|
||||
required this.isPublished,
|
||||
required this.company,
|
||||
required this.availability,
|
||||
required this.availabilityStatus,
|
||||
this.nextAvailableAt,
|
||||
});
|
||||
|
||||
String get displayName => '$year $make $model';
|
||||
String? get primaryPhoto => photos.isNotEmpty ? photos.first : null;
|
||||
// Convert cents to dollars for display
|
||||
double get dailyRate => dailyRateCents / 100;
|
||||
String get companySlug => company.brand.subdomain;
|
||||
|
||||
factory MarketplaceVehicle.fromJson(Map<String, dynamic> json) =>
|
||||
MarketplaceVehicle(
|
||||
id: json['id'] as String,
|
||||
companyId: json['companyId'] as String,
|
||||
make: json['make'] as String,
|
||||
model: json['model'] as String,
|
||||
year: json['year'] as int,
|
||||
color: json['color'] as String?,
|
||||
licensePlate: json['licensePlate'] as String,
|
||||
category: json['category'] as String? ?? 'ECONOMY',
|
||||
seats: json['seats'] as int? ?? 5,
|
||||
transmission: json['transmission'] as String? ?? 'MANUAL',
|
||||
fuelType: json['fuelType'] as String? ?? 'GASOLINE',
|
||||
features: (json['features'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
[],
|
||||
dailyRateCents: json['dailyRate'] as int? ?? 0,
|
||||
status: json['status'] as String? ?? 'AVAILABLE',
|
||||
photos: (json['photos'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
[],
|
||||
mileage: json['mileage'] as int?,
|
||||
isPublished: json['isPublished'] as bool? ?? false,
|
||||
company: MarketplaceCompany.fromJson(
|
||||
json['company'] as Map<String, dynamic>),
|
||||
availability: json['availability'] as bool? ?? true,
|
||||
availabilityStatus:
|
||||
json['availabilityStatus'] as String? ?? 'AVAILABLE',
|
||||
nextAvailableAt: json['nextAvailableAt'] != null
|
||||
? DateTime.tryParse(json['nextAvailableAt'] as String)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
class MarketplaceSearchResult {
|
||||
final List<MarketplaceVehicle> data;
|
||||
final int total;
|
||||
final int page;
|
||||
final int pageSize;
|
||||
|
||||
const MarketplaceSearchResult({
|
||||
required this.data,
|
||||
required this.total,
|
||||
required this.page,
|
||||
required this.pageSize,
|
||||
});
|
||||
|
||||
factory MarketplaceSearchResult.fromJson(Map<String, dynamic> json) {
|
||||
final raw = json['data'] ?? json;
|
||||
if (raw is List) {
|
||||
return MarketplaceSearchResult(
|
||||
data: raw
|
||||
.map((e) =>
|
||||
MarketplaceVehicle.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
total: json['total'] as int? ?? raw.length,
|
||||
page: json['page'] as int? ?? 1,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
);
|
||||
}
|
||||
return MarketplaceSearchResult(
|
||||
data: (json['data'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
MarketplaceVehicle.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
total: json['total'] as int? ?? 0,
|
||||
page: json['page'] as int? ?? 1,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MarketplaceOffer {
|
||||
final String id;
|
||||
final String title;
|
||||
final String? description;
|
||||
final String? imageUrl;
|
||||
final String type;
|
||||
final int discountValue;
|
||||
final String? promoCode;
|
||||
final bool isFeatured;
|
||||
final DateTime validUntil;
|
||||
final MarketplaceCompany company;
|
||||
|
||||
const MarketplaceOffer({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.description,
|
||||
this.imageUrl,
|
||||
required this.type,
|
||||
required this.discountValue,
|
||||
this.promoCode,
|
||||
required this.isFeatured,
|
||||
required this.validUntil,
|
||||
required this.company,
|
||||
});
|
||||
|
||||
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(s)';
|
||||
case 'SPECIAL_RATE':
|
||||
return 'Special rate';
|
||||
default:
|
||||
return 'Offer';
|
||||
}
|
||||
}
|
||||
|
||||
factory MarketplaceOffer.fromJson(Map<String, dynamic> json) =>
|
||||
MarketplaceOffer(
|
||||
id: json['id'] as String,
|
||||
title: json['title'] as String,
|
||||
description: json['description'] as String?,
|
||||
imageUrl: json['imageUrl'] as String?,
|
||||
type: json['type'] as String,
|
||||
discountValue: json['discountValue'] as int? ?? 0,
|
||||
promoCode: json['promoCode'] as String?,
|
||||
isFeatured: json['isFeatured'] as bool? ?? false,
|
||||
validUntil:
|
||||
DateTime.parse(json['validUntil'] as String),
|
||||
company: MarketplaceCompany.fromJson(
|
||||
json['company'] as Map<String, dynamic>),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
class Reservation {
|
||||
final String id;
|
||||
final String status;
|
||||
final DateTime startDate;
|
||||
final DateTime endDate;
|
||||
final double totalAmount;
|
||||
final String paymentStatus;
|
||||
final String? vehicleId;
|
||||
final String? customerId;
|
||||
final VehicleSummary? vehicle;
|
||||
final CustomerSummary? customer;
|
||||
final DateTime createdAt;
|
||||
final String? source;
|
||||
|
||||
const Reservation({
|
||||
required this.id,
|
||||
required this.status,
|
||||
required this.startDate,
|
||||
required this.endDate,
|
||||
required this.totalAmount,
|
||||
required this.paymentStatus,
|
||||
this.vehicleId,
|
||||
this.customerId,
|
||||
this.vehicle,
|
||||
this.customer,
|
||||
required this.createdAt,
|
||||
this.source,
|
||||
});
|
||||
|
||||
int get days => endDate.difference(startDate).inDays;
|
||||
|
||||
factory Reservation.fromJson(Map<String, dynamic> json) => Reservation(
|
||||
id: json['id'] as String,
|
||||
status: json['status'] as String,
|
||||
startDate: DateTime.parse(json['startDate'] as String),
|
||||
endDate: DateTime.parse(json['endDate'] as String),
|
||||
totalAmount: (json['totalAmount'] as num?)?.toDouble() ?? 0,
|
||||
paymentStatus: json['paymentStatus'] as String? ?? 'PENDING',
|
||||
vehicleId: json['vehicleId'] as String?,
|
||||
customerId: json['customerId'] as String?,
|
||||
vehicle: json['vehicle'] != null
|
||||
? VehicleSummary.fromJson(
|
||||
json['vehicle'] as Map<String, dynamic>)
|
||||
: null,
|
||||
customer: json['customer'] != null
|
||||
? CustomerSummary.fromJson(
|
||||
json['customer'] as Map<String, dynamic>)
|
||||
: null,
|
||||
createdAt: DateTime.parse(
|
||||
json['createdAt'] as String? ?? DateTime.now().toIso8601String()),
|
||||
source: json['source'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
class VehicleSummary {
|
||||
final String id;
|
||||
final String make;
|
||||
final String model;
|
||||
final int year;
|
||||
final String licensePlate;
|
||||
final List<String> photos;
|
||||
|
||||
const VehicleSummary({
|
||||
required this.id,
|
||||
required this.make,
|
||||
required this.model,
|
||||
required this.year,
|
||||
required this.licensePlate,
|
||||
required this.photos,
|
||||
});
|
||||
|
||||
String get displayName => '$year $make $model';
|
||||
String? get primaryPhoto => photos.isNotEmpty ? photos.first : null;
|
||||
|
||||
factory VehicleSummary.fromJson(Map<String, dynamic> json) => VehicleSummary(
|
||||
id: json['id'] as String,
|
||||
make: json['make'] as String,
|
||||
model: json['model'] as String,
|
||||
year: json['year'] as int,
|
||||
licensePlate: json['licensePlate'] as String,
|
||||
photos: (json['photos'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
class CustomerSummary {
|
||||
final String id;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final String? email;
|
||||
final String? phone;
|
||||
|
||||
const CustomerSummary({
|
||||
required this.id,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
this.email,
|
||||
this.phone,
|
||||
});
|
||||
|
||||
String get fullName => '$firstName $lastName';
|
||||
|
||||
factory CustomerSummary.fromJson(Map<String, dynamic> json) =>
|
||||
CustomerSummary(
|
||||
id: json['id'] as String,
|
||||
firstName: json['firstName'] as String,
|
||||
lastName: json['lastName'] as String,
|
||||
email: json['email'] as String?,
|
||||
phone: json['phone'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
class ReservationListResponse {
|
||||
final List<Reservation> data;
|
||||
final int total;
|
||||
final int page;
|
||||
final int pageSize;
|
||||
|
||||
const ReservationListResponse({
|
||||
required this.data,
|
||||
required this.total,
|
||||
required this.page,
|
||||
required this.pageSize,
|
||||
});
|
||||
|
||||
factory ReservationListResponse.fromJson(Map<String, dynamic> json) =>
|
||||
ReservationListResponse(
|
||||
data: (json['data'] as List<dynamic>)
|
||||
.map((e) => Reservation.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
total: json['total'] as int? ?? 0,
|
||||
page: json['page'] as int? ?? 1,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
class Vehicle {
|
||||
final String id;
|
||||
final String make;
|
||||
final String model;
|
||||
final int year;
|
||||
final String licensePlate;
|
||||
final double dailyRate;
|
||||
final String status;
|
||||
final String category;
|
||||
final List<String> photos;
|
||||
final int? mileage;
|
||||
final int? seats;
|
||||
final String? transmission;
|
||||
final String? fuelType;
|
||||
final bool isPublished;
|
||||
|
||||
const Vehicle({
|
||||
required this.id,
|
||||
required this.make,
|
||||
required this.model,
|
||||
required this.year,
|
||||
required this.licensePlate,
|
||||
required this.dailyRate,
|
||||
required this.status,
|
||||
required this.category,
|
||||
required this.photos,
|
||||
this.mileage,
|
||||
this.seats,
|
||||
this.transmission,
|
||||
this.fuelType,
|
||||
required this.isPublished,
|
||||
});
|
||||
|
||||
String get displayName => '$year $make $model';
|
||||
|
||||
String? get primaryPhoto => photos.isNotEmpty ? photos.first : null;
|
||||
|
||||
factory Vehicle.fromJson(Map<String, dynamic> json) => Vehicle(
|
||||
id: json['id'] as String,
|
||||
make: json['make'] as String,
|
||||
model: json['model'] as String,
|
||||
year: json['year'] as int,
|
||||
licensePlate: json['licensePlate'] as String,
|
||||
dailyRate: (json['dailyRate'] as num).toDouble(),
|
||||
status: json['status'] as String? ?? 'AVAILABLE',
|
||||
category: json['category'] as String? ?? 'ECONOMY',
|
||||
photos: (json['photos'] as List<dynamic>?)
|
||||
?.map((e) => e as String)
|
||||
.toList() ??
|
||||
[],
|
||||
mileage: json['mileage'] as int?,
|
||||
seats: json['seats'] as int?,
|
||||
transmission: json['transmission'] as String?,
|
||||
fuelType: json['fuelType'] as String?,
|
||||
isPublished: json['isPublished'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
class VehicleListResponse {
|
||||
final List<Vehicle> data;
|
||||
final int total;
|
||||
final int page;
|
||||
final int pageSize;
|
||||
|
||||
const VehicleListResponse({
|
||||
required this.data,
|
||||
required this.total,
|
||||
required this.page,
|
||||
required this.pageSize,
|
||||
});
|
||||
|
||||
factory VehicleListResponse.fromJson(Map<String, dynamic> json) =>
|
||||
VehicleListResponse(
|
||||
data: (json['data'] as List<dynamic>)
|
||||
.map((e) => Vehicle.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
total: json['total'] as int? ?? 0,
|
||||
page: json['page'] as int? ?? 1,
|
||||
pageSize: json['pageSize'] as int? ?? 20,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user