fix: invalidate agent cache on profile update and add expandable list support for expertise and certifications
This commit is contained in:
@@ -8,6 +8,8 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
import 'package:real_estate_mobile/features/agents/presentation/providers/agent_detail_provider.dart';
|
||||||
|
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||||
import 'package:real_estate_mobile/features/profile/data/profile_repository.dart';
|
import 'package:real_estate_mobile/features/profile/data/profile_repository.dart';
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -385,6 +387,14 @@ class _AgentEditProfileScreenState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate the agent detail provider so the dashboard refetches
|
||||||
|
// field values after save (was showing stale cached data).
|
||||||
|
final userId = ref.read(authProvider).user?.id;
|
||||||
|
if (userId != null) {
|
||||||
|
ref.invalidate(agentDetailProvider(userId));
|
||||||
|
}
|
||||||
|
ref.invalidate(_editProfileDataProvider);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
|
|||||||
@@ -869,11 +869,15 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> {
|
|||||||
color: AppColors.primaryDark)),
|
color: AppColors.primaryDark)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_buildTagsWrap(state.expertiseYears
|
_buildTagsWrap(
|
||||||
.map((e) => e['years']!.isNotEmpty
|
state.expertiseYears
|
||||||
? '${e['area']} – ${e['years']}'
|
.map((e) => e['years']!.isNotEmpty
|
||||||
: e['area']!)
|
? '${e['area']} – ${e['years']}'
|
||||||
.toList(), sectionKey: 'expertise'),
|
: e['area']!)
|
||||||
|
.toList(),
|
||||||
|
sectionKey: 'expertise',
|
||||||
|
initialCount: 4,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
if (state.certifications.isNotEmpty) ...[
|
if (state.certifications.isNotEmpty) ...[
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -887,47 +891,87 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> {
|
|||||||
color: AppColors.primaryDark)),
|
color: AppColors.primaryDark)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
...state.certifications.map((cert) => Padding(
|
_buildCertificationsList(state.certifications),
|
||||||
padding: const EdgeInsets.only(bottom: 12, left: 8),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
const Text('\u2022 ',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: AppColors.primaryDark)),
|
|
||||||
Expanded(
|
|
||||||
child: Text(cert['name']!,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'SourceSerif4',
|
|
||||||
fontSize: 14,
|
|
||||||
color: AppColors.primaryDark)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (cert['org']!.isNotEmpty)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16),
|
|
||||||
child: Opacity(
|
|
||||||
opacity: 0.5,
|
|
||||||
child: Text(cert['org']!,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'SourceSerif4',
|
|
||||||
fontSize: 14,
|
|
||||||
color: AppColors.primaryDark)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Certifications list with "+N More" (initial 2, matching web)
|
||||||
|
Widget _buildCertificationsList(List<Map<String, String>> certs) {
|
||||||
|
const initialCount = 2;
|
||||||
|
final sectionKey = 'certifications';
|
||||||
|
final isExpanded = _expandedTagSections.contains(sectionKey);
|
||||||
|
final display = isExpanded ? certs : certs.take(initialCount).toList();
|
||||||
|
final remaining = certs.length - initialCount;
|
||||||
|
|
||||||
|
Widget certRow(Map<String, String> cert) => Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 12, left: 8),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
const Text('\u2022 ',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14, color: AppColors.primaryDark)),
|
||||||
|
Expanded(
|
||||||
|
child: Text(cert['name']!,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
color: AppColors.primaryDark)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if ((cert['org'] ?? '').isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 16),
|
||||||
|
child: Opacity(
|
||||||
|
opacity: 0.5,
|
||||||
|
child: Text(cert['org']!,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
color: AppColors.primaryDark)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
...display.map(certRow),
|
||||||
|
if (remaining > 0)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 8, top: 4),
|
||||||
|
child: GestureDetector(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onTap: () => setState(() {
|
||||||
|
if (isExpanded) {
|
||||||
|
_expandedTagSections.remove(sectionKey);
|
||||||
|
} else {
|
||||||
|
_expandedTagSections.add(sectionKey);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
child: Text(
|
||||||
|
isExpanded ? 'Show Less' : '+$remaining More',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildExperienceRow(String label, String value) {
|
Widget _buildExperienceRow(String label, String value) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -959,10 +1003,15 @@ class _AgentHomeContentState extends ConsumerState<_AgentHomeContent> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTagsWrap(List<String> tags, {required String sectionKey}) {
|
Widget _buildTagsWrap(
|
||||||
|
List<String> tags, {
|
||||||
|
required String sectionKey,
|
||||||
|
int initialCount = 6,
|
||||||
|
}) {
|
||||||
final isExpanded = _expandedTagSections.contains(sectionKey);
|
final isExpanded = _expandedTagSections.contains(sectionKey);
|
||||||
final displayTags = isExpanded ? tags : tags.take(6).toList();
|
final displayTags =
|
||||||
final remaining = tags.length - 6;
|
isExpanded ? tags : tags.take(initialCount).toList();
|
||||||
|
final remaining = tags.length - initialCount;
|
||||||
|
|
||||||
return Wrap(
|
return Wrap(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
|
|||||||
Reference in New Issue
Block a user