marco.pms.mobileapp/lib/helpers/widgets/team_members_bottom_sheet.dart
2025-07-15 17:34:36 +05:30

227 lines
9.5 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/material.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/avatar.dart';
import 'package:marco/model/directory/contact_bucket_list_model.dart';
class TeamMembersBottomSheet {
static void show(
BuildContext context,
ContactBucket bucket,
List<dynamic> members, {
bool canEdit = false,
VoidCallback? onEdit,
}) {
// Ensure the owner is at the top of the list
final ownerId = bucket.createdBy.id;
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,
isDismissible: true,
enableDrag: true,
builder: (context) {
return SafeArea(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: DraggableScrollableSheet(
expand: false,
initialChildSize: 0.7,
minChildSize: 0.5,
maxChildSize: 0.95,
builder: (context, scrollController) {
return Column(
children: [
const SizedBox(height: 6),
Container(
width: 36,
height: 4,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(height: 10),
MyText.titleMedium(
'Bucket Details',
fontWeight: 700,
),
const SizedBox(height: 12),
// Header with title and edit
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
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',
),
],
),
),
// Info
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
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,
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8),
child: 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 dont have edit access',
fontWeight: 600,
color: canEdit ? Colors.green : Colors.grey,
),
],
),
),
const SizedBox(height: 8),
const Divider(thickness: 1),
const SizedBox(height: 6),
MyText.labelLarge(
'Shared with',
fontWeight: 700,
color: Colors.black,
),
],
),
),
const SizedBox(height: 4),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: members.isEmpty
? Center(
child: MyText.bodySmall(
"No team members found.",
fontWeight: 600,
color: Colors.grey,
),
)
: ListView.separated(
controller: scrollController,
itemCount: members.length,
separatorBuilder: (_, __) =>
const SizedBox(height: 4),
itemBuilder: (context, index) {
final member = members[index];
final firstName = member.firstName ?? '';
final lastName = member.lastName ?? '';
final isOwner =
member.id == bucket.createdBy.id;
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,
),
);
},
),
),
),
const SizedBox(height: 8),
],
);
},
),
),
);
},
);
}
}