// Version: 1.0 - 担当従業員編集ダイアログ(リッチ実装) import 'package:flutter/material.dart'; import '../models/employee.dart'; /// 従業員用のリッチな編集ダイアログ class EmployeeEditDialog extends StatefulWidget { final String title; final Employee? initialData; // null = 新規作成 /// 保存時のコールバック(Employee のデータを返す) final void Function(Employee)? onSave; const EmployeeEditDialog({ super.key, required this.title, this.initialData, this.onSave, }); @override State createState() => _EmployeeEditDialogState(); } class _EmployeeEditDialogState extends State { late TextEditingController nameController; late TextEditingController emailController; late TextEditingController telController; late TextEditingController departmentController; late TextEditingController roleController; @override void initState() { super.initState(); final data = widget.initialData; if (data == null) { nameController = TextEditingController(text: ''); emailController = TextEditingController(text: ''); telController = TextEditingController(text: ''); departmentController = TextEditingController(text: ''); roleController = TextEditingController(text: ''); } else { nameController = TextEditingController(text: data.name); emailController = TextEditingController(text: data.email); telController = TextEditingController(text: data.tel); departmentController = TextEditingController(text: data.department); roleController = TextEditingController(text: data.role); } } @override void dispose() { nameController.dispose(); emailController.dispose(); telController.dispose(); departmentController.dispose(); roleController.dispose(); super.dispose(); } /// リッチな入力フィールドビルダー(共通) Widget _buildRichTextField({ required String label, required TextEditingController controller, { TextInputType? keyboardType, IconData? icon, String hint = '', }) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 13, color: Colors.grey.shade700, ), ), const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Theme.of(context).cardColor.withOpacity(0.3), border: Border.all(color: Theme.of(context).dividerColor), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ if (icon != null) Icon(icon, size: 16, color: Theme.of(context).primaryColor), const SizedBox(width: 8), Expanded( child: TextField( controller: controller, keyboardType: keyboardType, style: const TextStyle(fontSize: 14), decoration: InputDecoration( hintText: hint.isEmpty ? null : hint, border: InputBorder.none, contentPadding: EdgeInsets.zero, ), ), ), ], ), ), ], ), ); } /// ダイアログ表示用 static メソッド static Future show({ required BuildContext context, required String title, required Employee? initialData, required void Function(Employee) onSave, }) async { final dialog = EmployeeEditDialog( title: title, initialData: initialData, ); // ダイアログをビルドして表示 showDialog( context: context, builder: (ctx) => dialog._build(context), ); } @override Widget build(BuildContext context) { return Dialog( backgroundColor: Colors.white, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Container( constraints: const BoxConstraints(maxWidth: 420), padding: const EdgeInsets.all(16), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // タイトルバー Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Theme.of(context).primaryColor.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(Icons.person, size: 24, color: Theme.of(context).primaryColor), ), const SizedBox(width: 12), Expanded(child: Text( widget.title, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), )), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.grey.shade200, borderRadius: BorderRadius.circular(8), ), child: Text( widget.initialData == null ? '新規' : '編集', style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), ), ), IconButton( icon: Icon(Icons.close, color: Colors.grey), onPressed: () => Navigator.pop(context), ), ], ), const SizedBox(height: 16), // ヒントテキスト Center( child: Text( widget.initialData == null ? '担当者情報を登録してください' : '担当者情報を更新してください', style: TextStyle( fontSize: 12, color: Colors.grey.shade500, fontStyle: FontStyle.italic, ), ), ), const SizedBox(height: 16), // ヒーダーセクション Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).primaryColor.withOpacity(0.05), borderRadius: BorderRadius.circular(12), border: Border.all(color: Theme.of(context).dividerColor), ), child: Row( children: [ Icon(Icons.business, size: 20, color: Theme.of(context).primaryColor), const SizedBox(width: 8), Expanded( child: Text( '担当者情報を入力してください', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 14), ), ), ], ), ), const SizedBox(height: 16), // リッチな編集フォーム Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ──────────────── 基本情報 ──────────────── Text( '■ 基本情報', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor, letterSpacing: 0.5, ), ), const SizedBox(height: 12), // 名前フィールド _buildRichTextField( label: '氏名 *', controller: nameController, keyboardType: TextInputType.name, icon: Icons.person, hint: '山田太郎', ), // メールアドレスフィールド _buildRichTextField( label: 'E メール *', controller: emailController, keyboardType: TextInputType.emailAddress, icon: Icons.email, hint: 'tanaka@company.com', ), // 電話番号フィールド _buildRichTextField( label: '電話番号 *', controller: telController, keyboardType: TextInputType.phone, icon: Icons.phone, hint: '03-1234-5678', ), const Divider(height: 24), // ──────────────── 部署情報 ──────────────── Text( '■ 部署・役職', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor, letterSpacing: 0.5, ), ), const SizedBox(height: 12), // 部門フィールド _buildRichTextField( label: '部署 *', controller: departmentController, keyboardType: TextInputType.text, icon: Icons.business, hint: '営業部', ), // 役職フィールド _buildRichTextField( label: '役職 *', controller: roleController, keyboardType: TextInputType.text, icon: Icons.badge, hint: '営業担当', ), ], ), const SizedBox(height: 16), // アクションボタン(Flex で配置) Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () => Navigator.pop(context), icon: Icon(Icons.close, size: 18), label: const Text(' キャンセル ', style: TextStyle(fontSize: 14)), style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), side: BorderSide(color: Colors.grey.shade300), ), ), ), const SizedBox(width: 8), Expanded( child: ElevatedButton.icon( onPressed: () { if (widget.onSave != null) { final employee = Employee( id: widget.initialData?.id ?? -1, name: nameController.text.isEmpty ? widget.initialData?.name ?? '未入力' : nameController.text, email: emailController.text.isEmpty ? widget.initialData?.email ?? '未入力' : emailController.text, tel: telController.text.isEmpty ? widget.initialData?.tel ?? '未入力' : telController.text, department: departmentController.text.isEmpty ? widget.initialData?.department ?? '未入力' : departmentController.text, role: roleController.text.isEmpty ? widget.initialData?.role ?? '未入力' : roleController.text, ); widget.onSave(employee); } }, icon: Icon(Icons.save, size: 18), label: const Text(' 保存 ', style: TextStyle(fontSize: 14)), style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), backgroundColor: Theme.of(context).primaryColor, foregroundColor: Colors.white, ), ), ), ], ), ), ], ), ), ), ); } /// 公開用ビルドメソッド(static メソッドから使用) Widget _build(BuildContext context) { return this; } }