766 lines
23 KiB
Dart
766 lines
23 KiB
Dart
part of '../../app/app.dart';
|
|
|
|
class SpecimenRegisterScreen extends StatefulWidget {
|
|
const SpecimenRegisterScreen({
|
|
super.key,
|
|
required this.token,
|
|
required this.baseUrl,
|
|
required this.master,
|
|
required this.title,
|
|
required this.total,
|
|
required this.user,
|
|
required this.notificationCount,
|
|
});
|
|
|
|
final String token;
|
|
final String baseUrl;
|
|
final String master;
|
|
final String title;
|
|
final int total;
|
|
final Map<String, dynamic> user;
|
|
final int notificationCount;
|
|
|
|
@override
|
|
State<SpecimenRegisterScreen> createState() => _SpecimenRegisterScreenState();
|
|
}
|
|
|
|
class _SpecimenRegisterScreenState extends State<SpecimenRegisterScreen> {
|
|
late final ApiClient _api;
|
|
late Future<Map<String, dynamic>> _future;
|
|
final _search = TextEditingController();
|
|
static const _allSpecimens = '__all_specimens__';
|
|
static const _allStatuses = '__all_statuses__';
|
|
static const int _pageSize = 10;
|
|
String _specimen = _allSpecimens;
|
|
String _status = _allStatuses;
|
|
int _page = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_api = ApiClient(baseUrl: widget.baseUrl, token: widget.token);
|
|
_future = _load();
|
|
_search.addListener(_onSearchChanged);
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_search.removeListener(_onSearchChanged);
|
|
_search.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<Map<String, dynamic>> _load() {
|
|
return _api.get('api/mobile/books/${widget.master}/examinations');
|
|
}
|
|
|
|
void _reload() {
|
|
setState(() {
|
|
_page = 0;
|
|
_future = _load();
|
|
});
|
|
}
|
|
|
|
void _onSearchChanged() {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_page = 0;
|
|
});
|
|
}
|
|
|
|
Future<void> _openCriticalValues() async {
|
|
await Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (_) =>
|
|
CriticalValuesScreen(token: widget.token, baseUrl: widget.baseUrl),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showProfile() {
|
|
showModalBottomSheet<void>(
|
|
context: context,
|
|
showDragHandle: true,
|
|
builder: (context) => SafeArea(
|
|
child: Padding(
|
|
padding: const EdgeInsets.fromLTRB(20, 4, 20, 20),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
CircleAvatar(
|
|
radius: 28,
|
|
backgroundColor: const Color(0xFF0F766E),
|
|
child: Text(
|
|
_initials(widget.user['nama']?.toString() ?? 'SP'),
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 14),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
widget.user['nama']?.toString() ?? '-',
|
|
style: Theme.of(context).textTheme.titleMedium
|
|
?.copyWith(fontWeight: FontWeight.w900),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
'${widget.user['username'] ?? '-'} • ${widget.user['previlage'] ?? '-'}',
|
|
style: const TextStyle(color: Colors.black54),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(height: 18),
|
|
FilledButton.icon(
|
|
onPressed: () async {
|
|
await SessionStore.clear();
|
|
if (!context.mounted) return;
|
|
Navigator.of(context).pushAndRemoveUntil(
|
|
MaterialPageRoute(builder: (_) => const LoginScreen()),
|
|
(_) => false,
|
|
);
|
|
},
|
|
icon: const Icon(Icons.logout),
|
|
label: const Text('Logout'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
String _initials(String name) {
|
|
final parts = name
|
|
.trim()
|
|
.split(RegExp(r'\s+'))
|
|
.where((part) => part.isNotEmpty)
|
|
.toList();
|
|
if (parts.isEmpty) {
|
|
return 'SP';
|
|
}
|
|
return parts.take(2).map((part) => part[0].toUpperCase()).join();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: SafeArea(
|
|
child: FutureBuilder<Map<String, dynamic>>(
|
|
future: _future,
|
|
builder: (context, snapshot) {
|
|
final items = asList(snapshot.data?['items']);
|
|
final filtered = _filtered(items);
|
|
final specimens = _specimenOptions(items);
|
|
final statuses = _statusOptions(items);
|
|
final maxPage = filtered.isEmpty
|
|
? 0
|
|
: (filtered.length - 1) ~/ _pageSize;
|
|
final page = _page.clamp(0, maxPage);
|
|
final start = filtered.isEmpty ? 0 : page * _pageSize;
|
|
final end = filtered.isEmpty
|
|
? 0
|
|
: (start + _pageSize).clamp(0, filtered.length);
|
|
final visible = filtered.sublist(start, end);
|
|
return ListView(
|
|
padding: const EdgeInsets.fromLTRB(18, 12, 18, 24),
|
|
children: [
|
|
_SpecimenHeader(
|
|
title: widget.title,
|
|
total: filtered.length,
|
|
user: widget.user,
|
|
notificationCount: widget.notificationCount,
|
|
onNotifications: _openCriticalValues,
|
|
onProfile: _showProfile,
|
|
),
|
|
const SizedBox(height: 24),
|
|
_FilterDropdown(
|
|
label: 'Jenis Spesimen',
|
|
value: _specimen,
|
|
icon: Icons.science_outlined,
|
|
options: specimens,
|
|
onChanged: (value) => setState(() {
|
|
_specimen = value;
|
|
_status = _allStatuses;
|
|
_page = 0;
|
|
}),
|
|
),
|
|
const SizedBox(height: 18),
|
|
_FilterDropdown(
|
|
label: 'Status Pengerjaan',
|
|
value: _status,
|
|
icon: Icons.assignment_outlined,
|
|
options: statuses,
|
|
onChanged: (value) => setState(() {
|
|
_status = value;
|
|
_page = 0;
|
|
}),
|
|
),
|
|
const SizedBox(height: 22),
|
|
Text(
|
|
'Cari Spesimen',
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.w900,
|
|
color: const Color(0xFF080D3D),
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
_SearchBlock(search: _search),
|
|
const SizedBox(height: 24),
|
|
const Divider(),
|
|
const SizedBox(height: 18),
|
|
_RegisterTitle(title: widget.title, total: filtered.length),
|
|
const SizedBox(height: 14),
|
|
if (snapshot.connectionState != ConnectionState.done)
|
|
const SizedBox(
|
|
height: 180,
|
|
child: Center(child: CircularProgressIndicator()),
|
|
)
|
|
else if (snapshot.hasError)
|
|
ErrorView(message: _message(snapshot.error), onRetry: _reload)
|
|
else if (filtered.isEmpty)
|
|
const EmptyPanel(text: 'Tidak ada sampel.')
|
|
else ...[
|
|
...visible.map(
|
|
(item) => SpecimenSampleCard(
|
|
item: asMap(item),
|
|
token: widget.token,
|
|
baseUrl: widget.baseUrl,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
_SpecimenPager(
|
|
start: start + 1,
|
|
end: end,
|
|
total: filtered.length,
|
|
canPrevious: page > 0,
|
|
canNext: page < maxPage,
|
|
onPrevious: () => setState(() => _page = page - 1),
|
|
onNext: () => setState(() => _page = page + 1),
|
|
),
|
|
],
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
bottomNavigationBar: NavigationBar(
|
|
selectedIndex: 1,
|
|
onDestinationSelected: (index) {
|
|
if (index == 0) {
|
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
}
|
|
if (index == 2) {
|
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
|
}
|
|
},
|
|
destinations: const [
|
|
NavigationDestination(
|
|
icon: Icon(Icons.home_outlined),
|
|
label: 'Beranda',
|
|
),
|
|
NavigationDestination(icon: Icon(Icons.search), label: 'Cari Sampel'),
|
|
NavigationDestination(
|
|
icon: Icon(Icons.person_outline),
|
|
label: 'Profil',
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
List<dynamic> _filtered(List<dynamic> items) {
|
|
final query = _search.text.trim().toLowerCase();
|
|
return items.where((raw) {
|
|
final item = asMap(raw);
|
|
final specimenValue = _specimenValue(item);
|
|
final specimenOk =
|
|
_specimen == _allSpecimens || specimenValue == _specimen;
|
|
final statusOk =
|
|
_status == _allStatuses || item['status']?.toString() == _status;
|
|
final searchOk =
|
|
query.isEmpty ||
|
|
[
|
|
item['nofoto'],
|
|
item['noregister'],
|
|
item['nmpasien'],
|
|
item['reques'],
|
|
item['kd_spesimen'],
|
|
item['nm_spesimen'],
|
|
item['status'],
|
|
].whereType<Object>().join(' ').toLowerCase().contains(query);
|
|
return specimenOk && statusOk && searchOk;
|
|
}).toList();
|
|
}
|
|
|
|
List<_FilterOption> _specimenOptions(List<dynamic> items) {
|
|
final values = <String, String>{};
|
|
for (final raw in items) {
|
|
final item = asMap(raw);
|
|
final value = _specimenValue(item);
|
|
final label = item['nm_spesimen']?.toString() ?? '';
|
|
if (value.isNotEmpty && label.isNotEmpty) {
|
|
values.putIfAbsent(value, () => label);
|
|
}
|
|
}
|
|
final options =
|
|
values.entries
|
|
.map((entry) => _FilterOption(value: entry.key, label: entry.value))
|
|
.toList()
|
|
..sort((a, b) => a.label.compareTo(b.label));
|
|
return [
|
|
const _FilterOption(value: _allSpecimens, label: 'Semua Spesimen'),
|
|
...options,
|
|
];
|
|
}
|
|
|
|
List<_FilterOption> _statusOptions(List<dynamic> items) {
|
|
final filteredBySpecimen = items.where((raw) {
|
|
final item = asMap(raw);
|
|
return _specimen == _allSpecimens || _specimenValue(item) == _specimen;
|
|
});
|
|
final values =
|
|
filteredBySpecimen
|
|
.map((item) => asMap(item)['status']?.toString() ?? '')
|
|
.where((value) => value.isNotEmpty)
|
|
.toSet()
|
|
.toList()
|
|
..sort();
|
|
return [
|
|
const _FilterOption(value: _allStatuses, label: 'Semua Status'),
|
|
...values.map((value) => _FilterOption(value: value, label: value)),
|
|
];
|
|
}
|
|
|
|
String _specimenValue(Map<String, dynamic> item) {
|
|
final code = item['kd_spesimen']?.toString() ?? '';
|
|
if (code.isNotEmpty) {
|
|
return code;
|
|
}
|
|
return item['nm_spesimen']?.toString() ?? '';
|
|
}
|
|
}
|
|
|
|
class _FilterOption {
|
|
const _FilterOption({required this.value, required this.label});
|
|
|
|
final String value;
|
|
final String label;
|
|
}
|
|
|
|
class _SpecimenHeader extends StatelessWidget {
|
|
const _SpecimenHeader({
|
|
required this.title,
|
|
required this.total,
|
|
required this.user,
|
|
required this.notificationCount,
|
|
required this.onNotifications,
|
|
required this.onProfile,
|
|
});
|
|
|
|
final String title;
|
|
final int total;
|
|
final Map<String, dynamic> user;
|
|
final int notificationCount;
|
|
final VoidCallback onNotifications;
|
|
final VoidCallback onProfile;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
children: [
|
|
IconButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
icon: const Icon(Icons.arrow_back),
|
|
),
|
|
const SizedBox(width: 6),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Flexible(
|
|
child: Text(
|
|
title,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: Theme.of(context).textTheme.headlineSmall
|
|
?.copyWith(
|
|
fontWeight: FontWeight.w900,
|
|
color: const Color(0xFF080D3D),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 10),
|
|
BadgeLabel(text: '$total', color: const Color(0xFF6D28D9)),
|
|
],
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
'Catatan & Register',
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
color: const Color(0xFF47517A),
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
IconButton(
|
|
onPressed: onNotifications,
|
|
icon: const Icon(Icons.notifications_none_rounded, size: 30),
|
|
color: const Color(0xFF063B60),
|
|
tooltip: 'Notifikasi nilai kritis',
|
|
),
|
|
if (notificationCount > 0)
|
|
Positioned(
|
|
top: 6,
|
|
right: 6,
|
|
child: Container(
|
|
padding: const EdgeInsets.all(5),
|
|
constraints: const BoxConstraints(minWidth: 20),
|
|
decoration: const BoxDecoration(
|
|
color: Color(0xFFFF1D25),
|
|
shape: BoxShape.circle,
|
|
),
|
|
child: Text(
|
|
notificationCount > 99 ? '99+' : '$notificationCount',
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 11,
|
|
fontWeight: FontWeight.w800,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
const SizedBox(width: 14),
|
|
InkWell(
|
|
borderRadius: BorderRadius.circular(24),
|
|
onTap: onProfile,
|
|
child: CircleAvatar(
|
|
backgroundColor: const Color(0xFF12BFA5),
|
|
child: Text(
|
|
_initials(user['nama']?.toString() ?? 'SP'),
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
String _initials(String name) {
|
|
final parts = name
|
|
.trim()
|
|
.split(RegExp(r'\s+'))
|
|
.where((part) => part.isNotEmpty)
|
|
.toList();
|
|
if (parts.isEmpty) {
|
|
return 'SP';
|
|
}
|
|
return parts.take(2).map((part) => part[0].toUpperCase()).join();
|
|
}
|
|
}
|
|
|
|
class _FilterDropdown extends StatelessWidget {
|
|
const _FilterDropdown({
|
|
required this.label,
|
|
required this.value,
|
|
required this.icon,
|
|
required this.options,
|
|
required this.onChanged,
|
|
});
|
|
|
|
final String label;
|
|
final String value;
|
|
final IconData icon;
|
|
final List<_FilterOption> options;
|
|
final ValueChanged<String> onChanged;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final values = options.map((option) => option.value).toSet();
|
|
final effectiveValue = values.contains(value) ? value : options.first.value;
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
label,
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
color: const Color(0xFF080D3D),
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
DropdownButtonFormField<String>(
|
|
initialValue: effectiveValue,
|
|
isExpanded: true,
|
|
selectedItemBuilder: (context) => options
|
|
.map(
|
|
(option) => Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
option.label,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
)
|
|
.toList(),
|
|
decoration: InputDecoration(
|
|
prefixIcon: Icon(icon, color: const Color(0xFF6D28D9)),
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
borderSide: const BorderSide(color: Color(0xFFA875FF)),
|
|
),
|
|
),
|
|
items: options
|
|
.map(
|
|
(option) => DropdownMenuItem(
|
|
value: option.value,
|
|
child: Text(option.label, overflow: TextOverflow.ellipsis),
|
|
),
|
|
)
|
|
.toList(),
|
|
onChanged: (value) => onChanged(value ?? options.first.value),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SearchBlock extends StatelessWidget {
|
|
const _SearchBlock({required this.search});
|
|
|
|
final TextEditingController search;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
children: [
|
|
TextField(
|
|
controller: search,
|
|
textInputAction: TextInputAction.done,
|
|
decoration: InputDecoration(
|
|
prefixIcon: const Icon(Icons.search),
|
|
hintText: 'Ketik No. Sampel, No. RM, atau Nama Pasien',
|
|
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Align(
|
|
alignment: Alignment.centerLeft,
|
|
child: BadgeLabel(
|
|
text: 'Pencarian: No. Sampel / No. RM / Nama',
|
|
color: const Color(0xFF6D28D9),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SpecimenPager extends StatelessWidget {
|
|
const _SpecimenPager({
|
|
required this.start,
|
|
required this.end,
|
|
required this.total,
|
|
required this.canPrevious,
|
|
required this.canNext,
|
|
required this.onPrevious,
|
|
required this.onNext,
|
|
});
|
|
|
|
final int start;
|
|
final int end;
|
|
final int total;
|
|
final bool canPrevious;
|
|
final bool canNext;
|
|
final VoidCallback onPrevious;
|
|
final VoidCallback onNext;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
'$start-$end dari $total sampel',
|
|
style: const TextStyle(
|
|
color: Color(0xFF47517A),
|
|
fontWeight: FontWeight.w800,
|
|
),
|
|
),
|
|
),
|
|
const Text(
|
|
'Tampilkan',
|
|
style: TextStyle(
|
|
color: Color(0xFF47517A),
|
|
fontWeight: FontWeight.w800,
|
|
),
|
|
),
|
|
const SizedBox(width: 10),
|
|
BadgeLabel(text: '10', color: const Color(0xFF667095)),
|
|
const SizedBox(width: 8),
|
|
IconButton.filledTonal(
|
|
onPressed: canPrevious ? onPrevious : null,
|
|
icon: const Icon(Icons.chevron_left_rounded),
|
|
),
|
|
const SizedBox(width: 8),
|
|
IconButton.filledTonal(
|
|
onPressed: canNext ? onNext : null,
|
|
icon: const Icon(Icons.chevron_right_rounded),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _RegisterTitle extends StatelessWidget {
|
|
const _RegisterTitle({required this.title, required this.total});
|
|
|
|
final String title;
|
|
final int total;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Row(
|
|
children: [
|
|
const Icon(Icons.menu_book_rounded, color: Color(0xFF6D28D9)),
|
|
const SizedBox(width: 10),
|
|
Expanded(
|
|
child: Text(
|
|
'BUKU REGISTER ${title.toUpperCase()}',
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
color: const Color(0xFF6D28D9),
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
),
|
|
Text(
|
|
'$total',
|
|
style: const TextStyle(
|
|
color: Color(0xFF667095),
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class SpecimenSampleCard extends StatelessWidget {
|
|
const SpecimenSampleCard({
|
|
super.key,
|
|
required this.item,
|
|
required this.token,
|
|
required this.baseUrl,
|
|
});
|
|
|
|
final Map<String, dynamic> item;
|
|
final String token;
|
|
final String baseUrl;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Card(
|
|
margin: const EdgeInsets.only(bottom: 12),
|
|
elevation: 0,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
side: const BorderSide(color: Color(0xFFE1E8F5)),
|
|
),
|
|
child: InkWell(
|
|
borderRadius: BorderRadius.circular(12),
|
|
onTap: () => _openDetail(context, item, token, baseUrl),
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Expanded(
|
|
flex: 6,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
item['nofoto']?.toString() ?? '-',
|
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
color: const Color(0xFF080D3D),
|
|
fontWeight: FontWeight.w900,
|
|
),
|
|
),
|
|
const SizedBox(height: 6),
|
|
BadgeLabel(
|
|
text: item['reques']?.toString() ?? '-',
|
|
color: const Color(0xFF0891B2),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
item['nmpasien']?.toString() ?? '-',
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: const TextStyle(
|
|
color: Color(0xFF47517A),
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
Text(
|
|
'No.RM ${item['noregister'] ?? '-'}',
|
|
style: const TextStyle(
|
|
color: Color(0xFF47517A),
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Container(width: 1, height: 96, color: const Color(0xFFE1E8F5)),
|
|
const SizedBox(width: 14),
|
|
Expanded(
|
|
flex: 4,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text(
|
|
'Status :',
|
|
style: TextStyle(
|
|
color: Color(0xFF667095),
|
|
fontWeight: FontWeight.w800,
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
StatusPill(status: item['status']?.toString() ?? 'NEW'),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|