Files
mobile-app/lib/features/agents/data/models/agent_profile.dart

239 lines
6.9 KiB
Dart
Raw Normal View History

import 'package:real_estate_mobile/features/agents/data/models/agent_type.dart';
class AgentProfile {
final String id;
2026-02-24 22:35:16 +05:30
final String? userId;
final String firstName;
final String lastName;
2026-02-24 22:35:16 +05:30
final String? headline;
final String? bio;
final String? avatar;
2026-02-24 22:35:16 +05:30
final String? companyName;
final String? phone;
final String? website;
final String? city;
final String? state;
final String? country;
2026-02-24 22:35:16 +05:30
final double? averageRating;
final int totalReviews;
final bool isVerified;
final bool isFeatured;
2026-02-24 22:35:16 +05:30
final bool isActive;
final AgentType? agentType;
2026-02-24 22:35:16 +05:30
final AgentUser? user;
final List<AgentFieldValue> fieldValues;
const AgentProfile({
required this.id,
2026-02-24 22:35:16 +05:30
this.userId,
required this.firstName,
required this.lastName,
2026-02-24 22:35:16 +05:30
this.headline,
this.bio,
this.avatar,
2026-02-24 22:35:16 +05:30
this.companyName,
this.phone,
this.website,
this.city,
this.state,
this.country,
2026-02-24 22:35:16 +05:30
this.averageRating,
this.totalReviews = 0,
this.isVerified = false,
this.isFeatured = false,
2026-02-24 22:35:16 +05:30
this.isActive = true,
this.agentType,
2026-02-24 22:35:16 +05:30
this.user,
this.fieldValues = const [],
});
String get fullName => '$firstName $lastName'.trim();
2026-02-24 22:35:16 +05:30
/// Get avatar URL — check agent avatar first, then user avatar
String? get avatarUrl => avatar ?? user?.avatar;
String get location {
// Direct fields first
if (city != null && state != null) return '$city, $state';
if (city != null) return city!;
if (state != null) return state!;
// Fallback: extract from fieldValues (matches web getLocationString)
String? fvCity;
String? fvState;
for (final fv in fieldValues) {
final slug = fv.fieldSlug.toLowerCase();
if (slug == 'city' || slug == 'city_name') {
fvCity = _extractFieldString(fv);
} else if (slug == 'state' || slug == 'state_name') {
fvState = _extractFieldString(fv);
}
}
final parts = [fvCity, fvState].where((s) => s != null && s.isNotEmpty);
if (parts.isNotEmpty) return parts.join(', ');
return '';
}
/// Extract a display string from a field value (handles jsonValue arrays).
static String? _extractFieldString(AgentFieldValue fv) {
if (fv.jsonValue is List && (fv.jsonValue as List).isNotEmpty) {
final val = (fv.jsonValue as List).first;
if (val is String && val.isNotEmpty) {
return val
.split('_')
.map((w) => w.isNotEmpty
? '${w[0].toUpperCase()}${w.substring(1).toLowerCase()}'
: '')
.join(' ');
}
}
if (fv.textValue != null && fv.textValue!.isNotEmpty) return fv.textValue;
return null;
}
2026-02-24 22:35:16 +05:30
/// Get experience from field values
String get experienceText {
2026-02-24 22:35:16 +05:30
for (final fv in fieldValues) {
if (fv.fieldSlug.contains('experience') ||
fv.fieldName.toLowerCase().contains('experience')) {
if (fv.textValue != null) return fv.textValue!;
if (fv.numberValue != null) {
return '${fv.numberValue!.toInt()}+ years in real estate.';
2026-02-24 22:35:16 +05:30
}
}
}
return '';
}
/// Get specializations / expertise from field values.
/// Matches web's getExpertiseTags slugs.
2026-02-24 22:35:16 +05:30
List<String> get specializations {
final tags = <String>[];
const expertiseSlugs = [
'about_me_expertise',
'expertise_areas',
'specializations',
'areas_of_expertise',
'expertise',
'specialization',
'property_type',
'loan_type',
];
2026-02-24 22:35:16 +05:30
for (final fv in fieldValues) {
final slug = fv.fieldSlug.toLowerCase();
if (!expertiseSlugs.any((s) => slug.contains(s))) continue;
if (fv.jsonValue is List) {
for (final v in (fv.jsonValue as List)) {
final s = v.toString().trim();
if (s.isEmpty) continue;
final display = s
.split('_')
.map((w) => w.isNotEmpty
? '${w[0].toUpperCase()}${w.substring(1).toLowerCase()}'
: '')
.join(' ');
if (!tags.contains(display)) tags.add(display);
2026-02-24 22:35:16 +05:30
}
} else if (fv.textValue != null && fv.textValue!.trim().isNotEmpty) {
final display = fv.textValue!.trim();
if (!tags.contains(display)) tags.add(display);
2026-02-24 22:35:16 +05:30
}
}
return tags;
}
factory AgentProfile.fromJson(Map<String, dynamic> json) {
return AgentProfile(
id: json['id'] as String,
2026-02-24 22:35:16 +05:30
userId: json['userId'] as String?,
firstName: json['firstName'] as String? ?? '',
lastName: json['lastName'] as String? ?? '',
2026-02-24 22:35:16 +05:30
headline: json['headline'] as String?,
bio: json['bio'] as String?,
avatar: json['avatar'] as String?,
2026-02-24 22:35:16 +05:30
companyName: json['companyName'] as String?,
phone: json['phone'] as String?,
website: json['website'] as String?,
city: json['city'] as String?,
state: json['state'] as String?,
country: json['country'] as String?,
2026-02-24 22:35:16 +05:30
averageRating: (json['averageRating'] as num?)?.toDouble(),
totalReviews: json['totalReviews'] as int? ?? 0,
isVerified: json['isVerified'] as bool? ?? false,
isFeatured: json['isFeatured'] as bool? ?? false,
2026-02-24 22:35:16 +05:30
isActive: json['isActive'] as bool? ?? true,
agentType: json['agentType'] != null
? AgentType.fromJson(json['agentType'] as Map<String, dynamic>)
: null,
2026-02-24 22:35:16 +05:30
user: json['user'] != null
? AgentUser.fromJson(json['user'] as Map<String, dynamic>)
: null,
fieldValues: (json['fieldValues'] as List<dynamic>?)
?.map((e) => AgentFieldValue.fromJson(e as Map<String, dynamic>))
.toList() ??
const [],
);
}
2026-02-24 22:35:16 +05:30
}
class AgentUser {
final String id;
final String email;
final String? avatar;
const AgentUser({
required this.id,
required this.email,
this.avatar,
});
2026-02-24 22:35:16 +05:30
factory AgentUser.fromJson(Map<String, dynamic> json) {
return AgentUser(
id: json['id'] as String,
email: json['email'] as String? ?? '',
avatar: json['avatar'] as String?,
);
}
}
class AgentFieldValue {
final String id;
2026-02-24 22:35:16 +05:30
final String fieldSlug;
final String fieldName;
final String fieldType;
final String? textValue;
final num? numberValue;
final bool? booleanValue;
final dynamic jsonValue;
final String? dateValue;
const AgentFieldValue({
required this.id,
2026-02-24 22:35:16 +05:30
required this.fieldSlug,
required this.fieldName,
required this.fieldType,
this.textValue,
this.numberValue,
this.booleanValue,
this.jsonValue,
this.dateValue,
});
factory AgentFieldValue.fromJson(Map<String, dynamic> json) {
return AgentFieldValue(
2026-02-24 22:35:16 +05:30
id: json['id'] as String? ?? '',
fieldSlug: json['fieldSlug'] as String? ?? '',
fieldName: json['fieldName'] as String? ?? '',
fieldType: json['fieldType'] as String? ?? '',
textValue: json['textValue'] as String?,
numberValue: json['numberValue'] as num?,
booleanValue: json['booleanValue'] as bool?,
jsonValue: json['jsonValue'],
dateValue: json['dateValue'] as String?,
);
}
}