marco.pms.mobileapp/lib/helpers/widgets/team_members_bottom_sheet.dart

215 lines
6.7 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/helpers/widgets/my_spacing.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,
}) {
final ownerId = bucket.createdBy.id;
// Ensure owner is 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,
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.75,
minChildSize: 0.55,
maxChildSize: 0.95,
builder: (context, scrollController) {
return Column(
children: [
MySpacing.height(8),
_buildGrabHandle(),
MySpacing.height(10),
MyText.titleMedium('Bucket Details', fontWeight: 700),
MySpacing.height(12),
_buildHeader(bucket, canEdit, onEdit),
_buildInfo(bucket, members.length, canEdit),
MySpacing.height(6),
_buildMembersTitle(),
MySpacing.height(4),
Expanded(child: _buildMemberList(members, ownerId, scrollController)),
MySpacing.height(8),
],
);
},
),
),
);
},
);
}
static Widget _buildGrabHandle() {
return Container(
width: 36,
height: 4,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(2),
),
);
}
static Widget _buildHeader(ContactBucket bucket, bool canEdit, VoidCallback? onEdit) {
return 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',
),
],
),
);
}
static Widget _buildInfo(ContactBucket bucket, int totalMembers, bool canEdit) {
return 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 ($totalMembers)',
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 dont have edit access',
fontWeight: 600,
color: canEdit ? Colors.green : Colors.grey,
),
],
),
MySpacing.height(8),
const Divider(thickness: 1),
],
),
);
}
static Widget _buildMembersTitle() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: MyText.labelLarge('Shared with', fontWeight: 700, color: Colors.black),
);
}
static Widget _buildMemberList(List<dynamic> members, String ownerId, ScrollController scrollController) {
if (members.isEmpty) {
return Center(
child: MyText.bodySmall(
"No team members found.",
fontWeight: 600,
color: Colors.grey,
),
);
}
return ListView.separated(
controller: scrollController,
itemCount: members.length,
padding: const EdgeInsets.symmetric(horizontal: 16),
separatorBuilder: (_, __) => const SizedBox(height: 4),
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,
),
);
},
);
}
}