239 lines
7.2 KiB
Dart
239 lines
7.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:gap/gap.dart';
|
|
import 'package:pluto_grid/pluto_grid.dart';
|
|
|
|
import '../../../../core/utils/extensions.dart';
|
|
import '../../../../shared/widgets/confirm_dialog.dart';
|
|
|
|
class UserManagementScreen extends ConsumerStatefulWidget {
|
|
const UserManagementScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<UserManagementScreen> createState() =>
|
|
_UserManagementScreenState();
|
|
}
|
|
|
|
class _UserManagementScreenState extends ConsumerState<UserManagementScreen> {
|
|
late PlutoGridStateManager stateManager;
|
|
|
|
// Mock 데이터
|
|
final List<Map<String, dynamic>> _mockUsers = List.generate(
|
|
20,
|
|
(i) => {
|
|
'id': '${i + 1}',
|
|
'name': '사용자 ${i + 1}',
|
|
'email': 'user${i + 1}@example.com',
|
|
'role': i == 0 ? 'admin' : 'user',
|
|
'status': i % 5 == 0 ? '비활성' : '활성',
|
|
'created_at': '2025-01-${(i + 1).toString().padLeft(2, '0')}',
|
|
},
|
|
);
|
|
|
|
List<PlutoColumn> get _columns => [
|
|
PlutoColumn(
|
|
title: 'ID',
|
|
field: 'id',
|
|
type: PlutoColumnType.text(),
|
|
width: 60,
|
|
enableEditingMode: false,
|
|
),
|
|
PlutoColumn(
|
|
title: '이름',
|
|
field: 'name',
|
|
type: PlutoColumnType.text(),
|
|
width: 150,
|
|
),
|
|
PlutoColumn(
|
|
title: '이메일',
|
|
field: 'email',
|
|
type: PlutoColumnType.text(),
|
|
width: 250,
|
|
),
|
|
PlutoColumn(
|
|
title: '역할',
|
|
field: 'role',
|
|
type: PlutoColumnType.select(['admin', 'user']),
|
|
width: 100,
|
|
),
|
|
PlutoColumn(
|
|
title: '상태',
|
|
field: 'status',
|
|
type: PlutoColumnType.select(['활성', '비활성']),
|
|
width: 100,
|
|
),
|
|
PlutoColumn(
|
|
title: '가입일',
|
|
field: 'created_at',
|
|
type: PlutoColumnType.text(),
|
|
width: 150,
|
|
enableEditingMode: false,
|
|
),
|
|
];
|
|
|
|
List<PlutoRow> get _rows => _mockUsers
|
|
.map(
|
|
(user) => PlutoRow(
|
|
cells: {
|
|
'id': PlutoCell(value: user['id']),
|
|
'name': PlutoCell(value: user['name']),
|
|
'email': PlutoCell(value: user['email']),
|
|
'role': PlutoCell(value: user['role']),
|
|
'status': PlutoCell(value: user['status']),
|
|
'created_at': PlutoCell(value: user['created_at']),
|
|
},
|
|
),
|
|
)
|
|
.toList();
|
|
|
|
void _showCreateUserDialog() {
|
|
final nameController = TextEditingController();
|
|
final emailController = TextEditingController();
|
|
|
|
showDialog<void>(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('새 사용자 추가'),
|
|
content: SizedBox(
|
|
width: 400,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextField(
|
|
controller: nameController,
|
|
decoration: const InputDecoration(
|
|
labelText: '이름',
|
|
hintText: '사용자 이름 입력',
|
|
),
|
|
),
|
|
const Gap(16),
|
|
TextField(
|
|
controller: emailController,
|
|
decoration: const InputDecoration(
|
|
labelText: '이메일',
|
|
hintText: 'email@example.com',
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: const Text('취소'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () {
|
|
// TODO: API 연동
|
|
Navigator.pop(context);
|
|
if (mounted) {
|
|
context.showSnackBar('사용자가 추가되었습니다');
|
|
}
|
|
},
|
|
child: const Text('추가'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _deleteUser(PlutoRow row) async {
|
|
final confirmed = await ConfirmDialog.show(
|
|
context,
|
|
title: '사용자 삭제',
|
|
message: '정말로 이 사용자를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.',
|
|
confirmLabel: '삭제',
|
|
isDestructive: true,
|
|
);
|
|
|
|
if (confirmed == true) {
|
|
stateManager.removeRows([row]);
|
|
if (mounted) {
|
|
context.showSnackBar('사용자가 삭제되었습니다');
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// 헤더
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
'사용자 관리',
|
|
style: context.textTheme.headlineMedium?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const Gap(4),
|
|
Text(
|
|
'사용자를 조회하고 관리하세요',
|
|
style: context.textTheme.bodyMedium?.copyWith(
|
|
color: context.colorScheme.onSurfaceVariant,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
FilledButton.icon(
|
|
onPressed: _showCreateUserDialog,
|
|
icon: const Icon(Icons.person_add),
|
|
label: const Text('새 사용자'),
|
|
),
|
|
],
|
|
),
|
|
const Gap(24),
|
|
|
|
// 데이터 그리드
|
|
Expanded(
|
|
child: Card(
|
|
clipBehavior: Clip.antiAlias,
|
|
child: PlutoGrid(
|
|
columns: _columns,
|
|
rows: _rows,
|
|
onLoaded: (event) {
|
|
stateManager = event.stateManager;
|
|
},
|
|
onRowDoubleTap: (event) {
|
|
// TODO: 사용자 상세 정보 다이얼로그
|
|
},
|
|
configuration: PlutoGridConfiguration(
|
|
style: PlutoGridStyleConfig(
|
|
gridBackgroundColor:
|
|
context.colorScheme.surface,
|
|
rowColor: context.colorScheme.surface,
|
|
activatedColor:
|
|
context.colorScheme.primaryContainer,
|
|
activatedBorderColor: context.colorScheme.primary,
|
|
gridBorderColor:
|
|
context.colorScheme.outlineVariant,
|
|
borderColor:
|
|
context.colorScheme.outlineVariant,
|
|
cellTextStyle:
|
|
context.textTheme.bodyMedium!,
|
|
columnTextStyle:
|
|
context.textTheme.titleSmall!.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
columnSize: const PlutoGridColumnSizeConfig(
|
|
autoSizeMode: PlutoAutoSizeMode.scale,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|