first app design

This commit is contained in:
root
2026-05-24 02:35:37 -04:00
parent c842eed601
commit d04c8ce437
138 changed files with 9672 additions and 0 deletions
+40
View File
@@ -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,
);
}
+54
View File
@@ -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,
);
}
+70
View File
@@ -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,
);
}
+223
View File
@@ -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>),
);
}
+137
View File
@@ -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,
);
}
+81
View File
@@ -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,
);
}