refactor: 코드베이스 정리 및 에러 처리 개선

- API 클라이언트 및 인증 인터셉터 에러 처리 강화
- 의존성 주입 실패 시에도 앱 실행 가능하도록 개선
- 사용하지 않는 레거시 UI 컴포넌트 및 화면 제거
- pubspec.yaml 의존성 업데이트

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-25 18:15:21 +09:00
parent 71b7b7f40b
commit ad2c699ff7
39 changed files with 193 additions and 4134 deletions

View File

@@ -1,696 +0,0 @@
import 'package:flutter/material.dart';
import 'package:superport/screens/equipment/controllers/equipment_list_controller.dart';
import 'package:superport/screens/equipment/widgets/equipment_table.dart';
import 'package:superport/utils/equipment_display_helper.dart';
import 'package:superport/services/mock_data_service.dart';
import 'package:superport/screens/common/theme_tailwind.dart';
import 'package:superport/screens/common/main_layout.dart';
import 'package:superport/utils/constants.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/screens/common/widgets/pagination.dart';
// 장비 목록 화면 (UI만 담당, 상태/로직/헬퍼/위젯 분리)
class EquipmentListScreen extends StatefulWidget {
final String currentRoute;
const EquipmentListScreen({super.key, this.currentRoute = Routes.equipment});
@override
State<EquipmentListScreen> createState() => _EquipmentListScreenState();
}
class _EquipmentListScreenState extends State<EquipmentListScreen> {
late final EquipmentListController _controller;
bool _showDetailedColumns = true;
final ScrollController _horizontalScrollController = ScrollController();
final ScrollController _verticalScrollController = ScrollController();
int _currentPage = 1;
final int _pageSize = 10;
String _searchKeyword = '';
String _appliedSearchKeyword = '';
@override
void initState() {
super.initState();
_controller = EquipmentListController(dataService: MockDataService());
_controller.loadData();
WidgetsBinding.instance.addPostFrameCallback((_) {
_adjustColumnsForScreenSize();
});
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_setDefaultFilterByRoute();
}
@override
void didUpdateWidget(EquipmentListScreen oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.currentRoute != widget.currentRoute) {
_setDefaultFilterByRoute();
}
}
@override
void dispose() {
_horizontalScrollController.dispose();
_verticalScrollController.dispose();
super.dispose();
}
// 라우트에 따라 기본 필터 설정
void _setDefaultFilterByRoute() {
String? newFilter;
if (widget.currentRoute == Routes.equipmentInList) {
newFilter = EquipmentStatus.in_;
} else if (widget.currentRoute == Routes.equipmentOutList) {
newFilter = EquipmentStatus.out;
} else if (widget.currentRoute == Routes.equipmentRentList) {
newFilter = EquipmentStatus.rent;
} else if (widget.currentRoute == Routes.equipment) {
newFilter = null;
}
if ((newFilter != _controller.selectedStatusFilter) ||
widget.currentRoute != Routes.equipment) {
setState(() {
_controller.selectedStatusFilter = newFilter;
_controller.loadData();
});
}
}
// 화면 크기에 따라 컬럼 표시 조정
void _adjustColumnsForScreenSize() {
final width = MediaQuery.of(context).size.width;
setState(() {
_showDetailedColumns = width > 900;
});
}
// 상태 필터 변경
void _onStatusFilterChanged(String? status) {
setState(() {
_controller.changeStatusFilter(status);
});
}
// 장비 선택/해제
void _onEquipmentSelected(int? id, String status, bool? isSelected) {
setState(() {
_controller.selectEquipment(id, status, isSelected);
});
}
// 출고 처리 버튼 핸들러
void _handleOutEquipment() async {
if (_controller.getSelectedInStockCount() == 0) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('출고할 장비를 선택해주세요.')));
return;
}
// 선택된 장비들의 요약 정보를 가져와서 출고 폼으로 전달
final selectedEquipmentsSummary =
_controller.getSelectedEquipmentsSummary();
final result = await Navigator.pushNamed(
context,
Routes.equipmentOutAdd,
arguments: {'selectedEquipments': selectedEquipmentsSummary},
);
if (result == true) {
setState(() {
_controller.loadData();
});
}
}
// 대여 처리 버튼 핸들러
void _handleRentEquipment() async {
if (_controller.getSelectedInStockCount() == 0) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('대여할 장비를 선택해주세요.')));
return;
}
// 선택된 장비들의 요약 정보를 가져와서 대여 폼으로 전달
final selectedEquipmentsSummary =
_controller.getSelectedEquipmentsSummary();
// 현재는 대여 기능이 준비되지 않았으므로 간단히 스낵바 표시
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'${selectedEquipmentsSummary.length}개 장비 대여 기능은 준비 중입니다.',
),
),
);
}
// 폐기 처리 버튼 핸들러
void _handleDisposeEquipment() {
if (_controller.getSelectedInStockCount() == 0) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('폐기할 장비를 선택해주세요.')));
return;
}
// 선택된 장비들의 요약 정보를 가져옴
final selectedEquipmentsSummary =
_controller.getSelectedEquipmentsSummary();
showDialog(
context: context,
builder:
(context) => AlertDialog(
title: const Text('폐기 확인'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'선택한 ${selectedEquipmentsSummary.length}개 장비를 폐기하시겠습니까?',
),
const SizedBox(height: 16),
const Text(
'폐기할 장비 목록:',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
...selectedEquipmentsSummary.map((equipmentData) {
final equipment = equipmentData['equipment'] as Equipment;
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
'${equipment.manufacturer} ${equipment.name} (${equipment.quantity}개)',
style: const TextStyle(fontSize: 14),
),
);
}).toList(),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('취소'),
),
TextButton(
onPressed: () {
// 여기에 폐기 로직 추가 예정
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('폐기 기능은 준비 중입니다.')),
);
Navigator.pop(context);
},
child: const Text('폐기'),
),
],
),
);
}
// 카테고리 축약 표기 함수 (예: 컴... > 태... > 안드로...)
String _shortenCategory(String category) {
if (category.length <= 2) return category;
return category.substring(0, 2) + '...';
}
// 카테고리 툴팁 위젯 (UI만 담당, 축약 표기 적용)
Widget _buildCategoryWithTooltip(UnifiedEquipment equipment) {
final fullCategory = EquipmentDisplayHelper.formatCategory(
equipment.equipment.category,
equipment.equipment.subCategory,
equipment.equipment.subSubCategory,
);
// 축약 표기 적용
final shortCategory = [
_shortenCategory(equipment.equipment.category),
_shortenCategory(equipment.equipment.subCategory),
_shortenCategory(equipment.equipment.subSubCategory),
].join(' > ');
return Tooltip(message: fullCategory, child: Text(shortCategory));
}
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
final maxContentWidth = screenWidth > 1200 ? 1200.0 : screenWidth - 32;
String screenTitle = '장비 목록';
if (widget.currentRoute == Routes.equipmentInList) {
screenTitle = '입고된 장비';
} else if (widget.currentRoute == Routes.equipmentOutList) {
screenTitle = '출고된 장비';
} else if (widget.currentRoute == Routes.equipmentRentList) {
screenTitle = '대여된 장비';
}
final int totalCount = _controller.equipments.length;
final List<UnifiedEquipment> filteredEquipments =
_appliedSearchKeyword.isEmpty
? _controller.equipments
: _controller.equipments.where((e) {
final keyword = _appliedSearchKeyword.toLowerCase();
// 모든 주요 필드에서 검색
return [
e.equipment.manufacturer,
e.equipment.name,
e.equipment.category,
e.equipment.subCategory,
e.equipment.subSubCategory,
e.equipment.serialNumber ?? '',
e.equipment.barcode ?? '',
e.equipment.remark ?? '',
e.equipment.warrantyLicense ?? '',
e.notes ?? '',
].any((field) => field.toLowerCase().contains(keyword));
}).toList();
final int filteredCount = filteredEquipments.length;
final int startIndex = (_currentPage - 1) * _pageSize;
final int endIndex =
(startIndex + _pageSize) > filteredCount
? filteredCount
: (startIndex + _pageSize);
final pagedEquipments = filteredEquipments.sublist(startIndex, endIndex);
// 선택된 장비 개수
final int selectedCount = _controller.getSelectedEquipmentCount();
final int selectedInCount = _controller.getSelectedInStockCount();
final int selectedOutCount = _controller.getSelectedEquipmentCountByStatus(
EquipmentStatus.out,
);
final int selectedRentCount = _controller.getSelectedEquipmentCountByStatus(
EquipmentStatus.rent,
);
return MainLayout(
title: screenTitle,
currentRoute: widget.currentRoute,
actions: [
IconButton(
icon: Icon(
_showDetailedColumns ? Icons.view_column : Icons.view_compact,
color: Colors.grey,
),
tooltip: _showDetailedColumns ? '간소화된 보기' : '상세 보기',
onPressed: () {
setState(() {
_showDetailedColumns = !_showDetailedColumns;
});
},
),
IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
setState(() {
_controller.loadData();
_currentPage = 1;
});
},
color: Colors.grey,
),
],
child: Container(
width: maxContentWidth,
padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Text(
screenTitle,
style: AppThemeTailwind.headingStyle,
),
),
if (selectedCount > 0)
Container(
padding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 16,
),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(4),
),
child: Text(
'$selectedCount개 선택됨',
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
if (widget.currentRoute == Routes.equipmentInList)
Row(
children: [
ElevatedButton.icon(
onPressed:
selectedInCount > 0 ? _handleOutEquipment : null,
icon: const Icon(
Icons.exit_to_app,
color: Colors.white,
),
label: const Text(
'출고',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
disabledBackgroundColor: Colors.blue.withOpacity(0.5),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
ElevatedButton.icon(
onPressed: () async {
final result = await Navigator.pushNamed(
context,
Routes.equipmentInAdd,
);
if (result == true) {
setState(() {
_controller.loadData();
_currentPage = 1;
});
}
},
icon: const Icon(Icons.add, color: Colors.white),
label: const Text(
'입고',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 16),
SizedBox(
width: 220,
child: Row(
children: [
Expanded(
child: TextField(
decoration: const InputDecoration(
hintText: '장비 검색',
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(),
isDense: true,
contentPadding: EdgeInsets.symmetric(
vertical: 8,
horizontal: 12,
),
),
onChanged: (value) {
setState(() {
_searchKeyword = value;
});
},
onSubmitted: (value) {
setState(() {
_appliedSearchKeyword = value;
_currentPage = 1;
});
},
),
),
const SizedBox(width: 4),
IconButton(
icon: const Icon(Icons.arrow_forward),
tooltip: '검색',
onPressed: () {
setState(() {
_appliedSearchKeyword = _searchKeyword;
_currentPage = 1;
});
},
),
],
),
),
],
),
// 출고 목록 화면일 때 버튼들
if (widget.currentRoute == Routes.equipmentOutList)
Row(
children: [
ElevatedButton.icon(
onPressed:
selectedOutCount > 0
? () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('재입고 기능은 준비 중입니다.'),
),
);
}
: null,
icon: const Icon(
Icons.assignment_return,
color: Colors.white,
),
label: const Text(
'재입고',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
disabledBackgroundColor: Colors.green.withOpacity(
0.5,
),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
ElevatedButton.icon(
onPressed:
selectedOutCount > 0
? () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('수리 요청 기능은 준비 중입니다.'),
),
);
}
: null,
icon: const Icon(Icons.build, color: Colors.white),
label: const Text(
'수리 요청',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
disabledBackgroundColor: Colors.orange.withOpacity(
0.5,
),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
],
),
// 대여 목록 화면일 때 버튼들
if (widget.currentRoute == Routes.equipmentRentList)
Row(
children: [
ElevatedButton.icon(
onPressed:
selectedRentCount > 0
? () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('대여 반납 기능은 준비 중입니다.'),
),
);
}
: null,
icon: const Icon(
Icons.keyboard_return,
color: Colors.white,
),
label: const Text(
'반납',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
disabledBackgroundColor: Colors.green.withOpacity(
0.5,
),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
ElevatedButton.icon(
onPressed:
selectedRentCount > 0
? () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('대여 연장 기능은 준비 중입니다.'),
),
);
}
: null,
icon: const Icon(Icons.date_range, color: Colors.white),
label: const Text(
'연장',
style: TextStyle(color: Colors.white),
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
disabledBackgroundColor: Colors.blue.withOpacity(0.5),
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
const SizedBox(height: 8),
Expanded(
child:
pagedEquipments.isEmpty
? const Center(child: Text('장비 정보가 없습니다.'))
: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: maxContentWidth,
),
child: EquipmentTable(
equipments: pagedEquipments,
selectedEquipmentIds:
_controller.selectedEquipmentIds,
showDetailedColumns: _showDetailedColumns,
onEquipmentSelected: _onEquipmentSelected,
getOutEquipmentInfo:
_controller.getOutEquipmentInfo,
buildCategoryWithTooltip: _buildCategoryWithTooltip,
// 수정 버튼 동작: 입고 폼(수정 모드)로 이동
onEdit: (id, status) async {
if (status == EquipmentStatus.in_) {
final result = await Navigator.pushNamed(
context,
Routes.equipmentInEdit,
arguments: id,
);
if (result == true) {
setState(() {
_controller.loadData();
});
}
} else {
// 출고/대여 등은 별도 폼으로 이동 필요시 구현
}
},
// 삭제 버튼 동작: 삭제 다이얼로그 및 삭제 처리
onDelete: (id, status) {
showDialog(
context: context,
builder:
(context) => AlertDialog(
title: const Text('삭제 확인'),
content: const Text('이 장비 정보를 삭제하시겠습니까?'),
actions: [
TextButton(
onPressed:
() => Navigator.pop(context),
child: const Text('취소'),
),
TextButton(
onPressed: () {
setState(() {
// 입고/출고 상태에 따라 삭제 처리
if (status ==
EquipmentStatus.in_) {
MockDataService()
.deleteEquipmentIn(id);
} else if (status ==
EquipmentStatus.out) {
MockDataService()
.deleteEquipmentOut(id);
}
_controller.loadData();
});
Navigator.pop(context);
},
child: const Text('삭제'),
),
],
),
);
},
getSelectedInStockCount:
_controller.getSelectedInStockCount,
),
),
),
),
if (totalCount > _pageSize)
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Pagination(
totalCount: filteredCount,
currentPage: _currentPage,
pageSize: _pageSize,
onPageChanged: (page) {
setState(() {
_currentPage = page;
});
},
),
),
],
),
),
);
}
}

View File

@@ -1,236 +0,0 @@
import 'package:flutter/material.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/screens/equipment/widgets/equipment_status_chip.dart';
import 'package:superport/screens/equipment/widgets/equipment_out_info.dart';
import 'package:superport/utils/equipment_display_helper.dart';
// 장비 목록 테이블 위젯 (SRP, 재사용성 강화)
class EquipmentTable extends StatelessWidget {
final List<UnifiedEquipment> equipments;
final Set<String> selectedEquipmentIds;
final bool showDetailedColumns;
final void Function(int? id, String status, bool? isSelected)
onEquipmentSelected;
final String Function(int equipmentId, String infoType) getOutEquipmentInfo;
final Widget Function(UnifiedEquipment equipment) buildCategoryWithTooltip;
final void Function(int id, String status) onEdit;
final void Function(int id, String status) onDelete;
final int Function() getSelectedInStockCount;
const EquipmentTable({
super.key,
required this.equipments,
required this.selectedEquipmentIds,
required this.showDetailedColumns,
required this.onEquipmentSelected,
required this.getOutEquipmentInfo,
required this.buildCategoryWithTooltip,
required this.onEdit,
required this.onDelete,
required this.getSelectedInStockCount,
});
// 출고 정보(간소화 모드) 위젯
Widget _buildCompactOutInfo(int equipmentId) {
final company = getOutEquipmentInfo(equipmentId, 'company');
final manager = getOutEquipmentInfo(equipmentId, 'manager');
final license = getOutEquipmentInfo(equipmentId, 'license');
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
EquipmentOutInfoIcon(infoType: 'company', text: company),
const SizedBox(height: 2),
EquipmentOutInfoIcon(infoType: 'manager', text: manager),
const SizedBox(height: 2),
EquipmentOutInfoIcon(infoType: 'license', text: license),
],
);
}
// 카테고리 툴팁 위젯 (UI만 담당, 축약 표기 적용)
Widget _buildCategoryWithTooltip(UnifiedEquipment equipment) {
// 한글 라벨로 표기
final fullCategory =
'대분류: ${equipment.equipment.category} / 중분류: ${equipment.equipment.subCategory} / 소분류: ${equipment.equipment.subSubCategory}';
final shortCategory = [
_shortenCategory(equipment.equipment.category),
_shortenCategory(equipment.equipment.subCategory),
_shortenCategory(equipment.equipment.subSubCategory),
].join(' > ');
return Tooltip(message: fullCategory, child: Text(shortCategory));
}
// 카테고리 축약 표기 함수 (예: 컴...)
String _shortenCategory(String category) {
if (category.length <= 2) return category;
return category.substring(0, 2) + '...';
}
@override
Widget build(BuildContext context) {
return DataTable(
headingRowHeight: 48,
dataRowMinHeight: 48,
dataRowMaxHeight: 60,
columnSpacing: 10,
horizontalMargin: 16,
columns: [
const DataColumn(label: SizedBox(width: 32, child: Text('선택'))),
const DataColumn(label: SizedBox(width: 32, child: Text('번호'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 60, child: Text('제조사'))),
const DataColumn(label: SizedBox(width: 90, child: Text('장비명'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 110, child: Text('분류'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 60, child: Text('장비 유형'))),
if (showDetailedColumns)
const DataColumn(label: SizedBox(width: 70, child: Text('시리얼번호'))),
const DataColumn(label: SizedBox(width: 38, child: Text('수량'))),
const DataColumn(label: SizedBox(width: 80, child: Text('변경 일자'))),
const DataColumn(label: SizedBox(width: 44, child: Text('상태'))),
if (showDetailedColumns) ...[
const DataColumn(label: SizedBox(width: 90, child: Text('출고 회사'))),
const DataColumn(label: SizedBox(width: 60, child: Text('담당자'))),
const DataColumn(label: SizedBox(width: 60, child: Text('라이센스'))),
] else
const DataColumn(label: SizedBox(width: 110, child: Text('출고 정보'))),
const DataColumn(label: SizedBox(width: 60, child: Text('관리'))),
],
rows:
equipments.asMap().entries.map((entry) {
final index = entry.key;
final equipment = entry.value;
final bool isInStock = equipment.status == 'I';
final bool isOutStock = equipment.status == 'O';
return DataRow(
color: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) =>
index % 2 == 0 ? Colors.grey[50] : null,
),
cells: [
DataCell(
Checkbox(
value: selectedEquipmentIds.contains(
'${equipment.id}:${equipment.status}',
),
onChanged:
(isSelected) => onEquipmentSelected(
equipment.id,
equipment.status,
isSelected,
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
DataCell(Text('${index + 1}')),
if (showDetailedColumns)
DataCell(
Text(
EquipmentDisplayHelper.formatManufacturer(
equipment.equipment.manufacturer,
),
),
),
DataCell(
Text(
EquipmentDisplayHelper.formatEquipmentName(
equipment.equipment.name,
),
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
if (showDetailedColumns)
DataCell(buildCategoryWithTooltip(equipment)),
if (showDetailedColumns)
DataCell(
Text(
equipment.status == 'I' &&
equipment is UnifiedEquipment &&
equipment.type != null
? equipment.type!
: '-',
),
),
if (showDetailedColumns)
DataCell(
Text(
EquipmentDisplayHelper.formatSerialNumber(
equipment.equipment.serialNumber,
),
),
),
DataCell(
Text(
'${equipment.equipment.quantity}',
textAlign: TextAlign.center,
),
),
DataCell(
Text(EquipmentDisplayHelper.formatDate(equipment.date)),
),
DataCell(EquipmentStatusChip(status: equipment.status)),
if (showDetailedColumns) ...[
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'company')
: '-',
),
),
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'manager')
: '-',
),
),
DataCell(
Text(
isOutStock
? getOutEquipmentInfo(equipment.id!, 'license')
: '-',
),
),
] else
DataCell(
isOutStock
? _buildCompactOutInfo(equipment.id!)
: const Text('-'),
),
DataCell(
Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(
Icons.edit,
color: Colors.blue,
size: 20,
),
constraints: const BoxConstraints(),
padding: const EdgeInsets.all(5),
onPressed:
() => onEdit(equipment.id!, equipment.status),
),
IconButton(
icon: const Icon(
Icons.delete,
color: Colors.red,
size: 20,
),
constraints: const BoxConstraints(),
padding: const EdgeInsets.all(5),
onPressed:
() => onDelete(equipment.id!, equipment.status),
),
],
),
),
],
);
}).toList(),
);
}
}