214 lines
5.9 KiB
Dart
214 lines
5.9 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:marco/helpers/widgets/my_text.dart';
|
||
import 'package:marco/helpers/widgets/avatar.dart';
|
||
import 'package:marco/helpers/widgets/my_spacing.dart';
|
||
import 'package:marco/model/directory/contact_bucket_list_model.dart';
|
||
import 'package:marco/helpers/utils/base_bottom_sheet.dart';
|
||
|
||
class TeamMembersBottomSheet {
|
||
static void show(
|
||
BuildContext context,
|
||
ContactBucket bucket,
|
||
List<dynamic> members, {
|
||
bool canEdit = false,
|
||
VoidCallback? onEdit,
|
||
}) {
|
||
final ownerId = bucket.createdBy.id;
|
||
|
||
// Ensure owner is listed first
|
||
members.sort((a, b) {
|
||
if (a.id == ownerId) return -1;
|
||
if (b.id == ownerId) return 1;
|
||
return 0;
|
||
});
|
||
|
||
showModalBottomSheet(
|
||
context: context,
|
||
isScrollControlled: true,
|
||
backgroundColor: Colors.transparent,
|
||
builder: (_) {
|
||
return BaseBottomSheet(
|
||
title: 'Bucket Details',
|
||
onCancel: () => Navigator.pop(context),
|
||
onSubmit: () {}, // Not used, but required
|
||
showButtons: false,
|
||
child: _TeamContent(
|
||
bucket: bucket,
|
||
members: members,
|
||
canEdit: canEdit,
|
||
onEdit: onEdit,
|
||
ownerId: ownerId,
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|
||
|
||
class _TeamContent extends StatelessWidget {
|
||
final ContactBucket bucket;
|
||
final List<dynamic> members;
|
||
final bool canEdit;
|
||
final VoidCallback? onEdit;
|
||
final String ownerId;
|
||
|
||
const _TeamContent({
|
||
required this.bucket,
|
||
required this.members,
|
||
required this.canEdit,
|
||
this.onEdit,
|
||
required this.ownerId,
|
||
});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Column(
|
||
children: [
|
||
_buildHeader(),
|
||
_buildInfo(),
|
||
_buildMembersTitle(),
|
||
MySpacing.height(8),
|
||
SizedBox(
|
||
height: 300,
|
||
child: _buildMemberList(),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
|
||
Widget _buildHeader() {
|
||
return Padding(
|
||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: MyText.titleMedium(bucket.name, fontWeight: 700),
|
||
),
|
||
if (canEdit)
|
||
IconButton(
|
||
onPressed: onEdit,
|
||
icon: const Icon(Icons.edit, color: Colors.red),
|
||
tooltip: 'Edit Bucket',
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildInfo() {
|
||
return Padding(
|
||
padding: const EdgeInsets.only(bottom: 12),
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
if (bucket.description.isNotEmpty)
|
||
Padding(
|
||
padding: const EdgeInsets.only(bottom: 6),
|
||
child: MyText.bodySmall(
|
||
bucket.description,
|
||
color: Colors.grey[700],
|
||
),
|
||
),
|
||
Row(
|
||
children: [
|
||
const Icon(Icons.contacts_outlined, size: 14, color: Colors.grey),
|
||
const SizedBox(width: 4),
|
||
MyText.labelSmall(
|
||
'${bucket.numberOfContacts} contact(s)',
|
||
fontWeight: 600,
|
||
color: Colors.red,
|
||
),
|
||
const SizedBox(width: 12),
|
||
const Icon(Icons.ios_share_outlined, size: 14, color: Colors.grey),
|
||
const SizedBox(width: 4),
|
||
MyText.labelSmall(
|
||
'Shared with (${members.length})',
|
||
fontWeight: 600,
|
||
color: Colors.indigo,
|
||
),
|
||
],
|
||
),
|
||
MySpacing.height(8),
|
||
Row(
|
||
children: [
|
||
const Icon(Icons.edit_outlined, size: 14, color: Colors.grey),
|
||
const SizedBox(width: 4),
|
||
MyText.labelSmall(
|
||
canEdit ? 'Can be edited by you' : 'You don’t have edit access',
|
||
fontWeight: 600,
|
||
color: canEdit ? Colors.green : Colors.grey,
|
||
),
|
||
],
|
||
),
|
||
MySpacing.height(12),
|
||
const Divider(thickness: 1),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildMembersTitle() {
|
||
return Align(
|
||
alignment: Alignment.centerLeft,
|
||
child: MyText.labelLarge('Shared with', fontWeight: 700, color: Colors.black),
|
||
);
|
||
}
|
||
|
||
Widget _buildMemberList() {
|
||
if (members.isEmpty) {
|
||
return Center(
|
||
child: MyText.bodySmall(
|
||
"No team members found.",
|
||
fontWeight: 600,
|
||
color: Colors.grey,
|
||
),
|
||
);
|
||
}
|
||
|
||
return ListView.separated(
|
||
itemCount: members.length,
|
||
separatorBuilder: (_, __) => const SizedBox(height: 6),
|
||
itemBuilder: (context, index) {
|
||
final member = members[index];
|
||
final firstName = member.firstName ?? '';
|
||
final lastName = member.lastName ?? '';
|
||
final isOwner = member.id == ownerId;
|
||
|
||
return ListTile(
|
||
dense: true,
|
||
contentPadding: EdgeInsets.zero,
|
||
leading: Avatar(firstName: firstName, lastName: lastName, size: 32),
|
||
title: Row(
|
||
children: [
|
||
Expanded(
|
||
child: MyText.bodyMedium(
|
||
'${firstName.isNotEmpty ? firstName : 'Unnamed'} ${lastName.isNotEmpty ? lastName : ''}',
|
||
fontWeight: 600,
|
||
),
|
||
),
|
||
if (isOwner)
|
||
Container(
|
||
margin: const EdgeInsets.only(left: 6),
|
||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||
decoration: BoxDecoration(
|
||
color: Colors.red.shade50,
|
||
borderRadius: BorderRadius.circular(4),
|
||
),
|
||
child: MyText.labelSmall(
|
||
"Owner",
|
||
fontWeight: 600,
|
||
color: Colors.red,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
subtitle: MyText.bodySmall(
|
||
member.jobRole ?? '',
|
||
color: Colors.grey.shade600,
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
}
|