import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:superport/models/company_model.dart'; import 'package:superport/services/company_service.dart'; import 'package:superport/screens/common/theme_shadcn.dart'; import 'package:superport/screens/common/components/shadcn_components.dart'; import 'package:superport/core/utils/error_handler.dart'; /// 본사와 지점 관리를 위한 개선된 다이얼로그 위젯 /// 새로운 계층형 Company 구조 기반 (Clean Architecture) class CompanyBranchDialog extends StatefulWidget { final Company mainCompany; const CompanyBranchDialog({super.key, required this.mainCompany}); @override State createState() => _CompanyBranchDialogState(); } class _CompanyBranchDialogState extends State { late final CompanyService _companyService; List _branches = []; bool _isLoading = true; String? _error; @override void initState() { super.initState(); _companyService = GetIt.instance(); _loadBranches(); } /// 지점 목록 로드 (SRP - 데이터 로딩 단일 책임) Future _loadBranches() async { try { setState(() { _isLoading = true; _error = null; }); // 전체 회사 목록에서 현재 본사의 지점들 필터링 final allCompanies = await ErrorHandler.handleApiCall( () => _companyService.getCompanies( page: 1, perPage: 1000, // 충분히 큰 수로 전체 조회 ), onError: (failure) => throw failure, ); if (allCompanies != null) { // parentCompanyId가 현재 본사 ID인 항목들만 필터링 _branches = allCompanies.items .where((company) => company.parentCompanyId == widget.mainCompany.id) .toList(); } } catch (e) { if (mounted) { setState(() { _error = e.toString(); }); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } /// 지점 추가 화면 이동 void _addBranch() { Navigator.pushNamed( context, '/company/branch/add', arguments: { 'parentCompanyId': widget.mainCompany.id, 'parentCompanyName': widget.mainCompany.name, }, ).then((result) { if (result == true) { _loadBranches(); // 지점 목록 새로고침 } }); } /// 지점 수정 화면 이동 void _editBranch(Company branch) { Navigator.pushNamed( context, '/company/branch/edit', arguments: { 'companyId': branch.id, 'parentCompanyId': widget.mainCompany.id, 'parentCompanyName': widget.mainCompany.name, }, ).then((result) { if (result == true) { _loadBranches(); // 지점 목록 새로고침 } }); } /// 지점 삭제 Future _deleteBranch(Company branch) async { final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('지점 삭제'), content: Text('${branch.name} 지점을 삭제하시겠습니까?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('취소'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('삭제'), ), ], ), ); if (confirmed == true) { try { await ErrorHandler.handleApiCall( () => _companyService.deleteCompany(branch.id!), onError: (failure) => throw failure, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('${branch.name} 지점이 삭제되었습니다.'), backgroundColor: Colors.green, ), ); _loadBranches(); // 지점 목록 새로고침 } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('삭제 실패: $e'), backgroundColor: Colors.red, ), ); } } } } /// 본사 정보 카드 구성 Widget _buildHeadquartersCard() { return ShadcnCard( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ ShadcnBadge( text: '본사', variant: ShadcnBadgeVariant.companyHeadquarters, size: ShadcnBadgeSize.small, ), const SizedBox(width: 12), Text( widget.mainCompany.name, style: ShadcnTheme.headingH5.copyWith( fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 8), _buildCompanyInfo(widget.mainCompany), ], ), ), ); } /// 지점 정보 카드 구성 Widget _buildBranchCard(Company branch) { return ShadcnCard( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ ShadcnBadge( text: '지점', variant: ShadcnBadgeVariant.companyBranch, size: ShadcnBadgeSize.small, ), const SizedBox(width: 12), Text( branch.name, style: ShadcnTheme.headingH5.copyWith( fontWeight: FontWeight.bold, ), ), ], ), Row( children: [ IconButton( icon: const Icon(Icons.edit, size: 20), onPressed: () => _editBranch(branch), tooltip: '지점 수정', ), IconButton( icon: const Icon(Icons.delete, size: 20), onPressed: () => _deleteBranch(branch), tooltip: '지점 삭제', ), ], ), ], ), const SizedBox(height: 8), _buildCompanyInfo(branch), ], ), ), ); } /// 회사 정보 공통 구성 (SRP - 정보 표시 단일 책임) Widget _buildCompanyInfo(Company company) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (company.address.toString().isNotEmpty) ...[ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon( Icons.location_on_outlined, size: 16, color: ShadcnTheme.muted, ), const SizedBox(width: 8), Expanded( child: Text( company.address.toString(), style: ShadcnTheme.bodySmall, ), ), ], ), const SizedBox(height: 4), ], if (company.contactName?.isNotEmpty == true) ...[ Row( children: [ Icon( Icons.person_outline, size: 16, color: ShadcnTheme.muted, ), const SizedBox(width: 8), Text( company.contactName!, style: ShadcnTheme.bodySmall, ), if (company.contactPosition?.isNotEmpty == true) ...[ Text( ' (${company.contactPosition})', style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.muted, ), ), ], ], ), const SizedBox(height: 4), ], if (company.contactPhone?.isNotEmpty == true || company.contactEmail?.isNotEmpty == true) ...[ Row( children: [ Icon( Icons.contact_phone_outlined, size: 16, color: ShadcnTheme.muted, ), const SizedBox(width: 8), Text( company.contactPhone ?? '', style: ShadcnTheme.bodySmall, ), if (company.contactEmail?.isNotEmpty == true) ...[ Text( ' | ${company.contactEmail}', style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.muted, ), ), ], ], ), ], ], ); } @override Widget build(BuildContext context) { final maxDialogHeight = MediaQuery.of(context).size.height * 0.8; final maxDialogWidth = MediaQuery.of(context).size.width * 0.7; return Dialog( child: ConstrainedBox( constraints: BoxConstraints( maxHeight: maxDialogHeight, maxWidth: maxDialogWidth, ), child: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // 헤더 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( '본사 및 지점 관리', style: ShadcnTheme.headingH4.copyWith( fontWeight: FontWeight.bold, ), ), Row( children: [ ElevatedButton.icon( onPressed: _addBranch, icon: const Icon(Icons.add, size: 16), label: const Text('지점 추가'), style: ElevatedButton.styleFrom( backgroundColor: ShadcnTheme.primary, foregroundColor: Colors.white, minimumSize: const Size(100, 36), ), ), const SizedBox(width: 8), IconButton( icon: const Icon(Icons.close), onPressed: () => Navigator.pop(context), tooltip: '닫기', ), ], ), ], ), const SizedBox(height: 24), // 콘텐츠 Expanded( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _error != null ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.error_outline, size: 48, color: ShadcnTheme.destructive, ), const SizedBox(height: 16), Text( '데이터 로드 실패', style: ShadcnTheme.headingH5, ), const SizedBox(height: 8), Text( _error!, style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.muted, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), ElevatedButton( onPressed: _loadBranches, child: const Text('다시 시도'), ), ], ), ) : SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 본사 정보 _buildHeadquartersCard(), const SizedBox(height: 16), // 지점 목록 if (_branches.isNotEmpty) ...[ Text( '지점 목록 (${_branches.length}개)', style: ShadcnTheme.headingH5.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), ..._branches.map((branch) => Padding( padding: const EdgeInsets.only(bottom: 12), child: _buildBranchCard(branch), )), ] else ...[ Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: ShadcnTheme.muted.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: ShadcnTheme.border, style: BorderStyle.solid, ), ), child: Column( children: [ Icon( Icons.domain_outlined, size: 48, color: ShadcnTheme.muted, ), const SizedBox(height: 12), Text( '등록된 지점이 없습니다', style: ShadcnTheme.bodyMedium.copyWith( color: ShadcnTheme.muted, ), ), const SizedBox(height: 8), Text( '지점 추가 버튼을 클릭하여 첫 지점을 등록해보세요', style: ShadcnTheme.bodySmall.copyWith( color: ShadcnTheme.muted, ), textAlign: TextAlign.center, ), ], ), ), ], ], ), ), ), ], ), ), ), ); } }