| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import 'package:flutter/material.dart';
- import '../../core/i18n/app_localizations.dart';
- import '../../core/theme/app_colors.dart';
- import '../models/user_model.dart';
- class ApprovalActions extends StatefulWidget {
- final String status;
- final UserRole userRole;
- final VoidCallback onApprove;
- final VoidCallback onReject;
- final VoidCallback? onEdit;
- final VoidCallback? onWithdraw;
- final bool isSubmitting;
- const ApprovalActions({
- super.key,
- required this.status,
- required this.userRole,
- required this.onApprove,
- required this.onReject,
- this.onEdit,
- this.onWithdraw,
- this.isSubmitting = false,
- });
- @override
- State<ApprovalActions> createState() => _ApprovalActionsState();
- }
- class _ApprovalActionsState extends State<ApprovalActions> {
- final _opinionCtrl = TextEditingController();
- Future<void> _showOpinionDialog(String action) async {
- final l10n = AppLocalizations.of(context);
- final result = await showDialog<bool>(
- context: context,
- builder: (ctx) => AlertDialog(
- title: Text(
- action == 'approve'
- ? l10n.get('confirmApprove')
- : l10n.get('confirmReject'),
- ),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- l10n.getString(
- 'confirmAction',
- args: {
- 'action': action == 'approve'
- ? l10n.get('approve')
- : l10n.get('reject'),
- },
- ),
- ),
- const SizedBox(height: 12),
- TextField(
- controller: _opinionCtrl,
- maxLines: 3,
- decoration: InputDecoration(
- hintText: l10n.get('approvalComment'),
- border: OutlineInputBorder(
- borderRadius: BorderRadius.circular(8),
- ),
- ),
- ),
- ],
- ),
- actions: [
- TextButton(
- onPressed: () => Navigator.pop(ctx, false),
- child: Text(l10n.get('cancel')),
- ),
- TextButton(
- onPressed: () => Navigator.pop(ctx, true),
- child: Text(
- l10n.get('confirm'),
- style: TextStyle(
- color: action == 'approve'
- ? AppColors.primary
- : AppColors.danger,
- ),
- ),
- ),
- ],
- ),
- );
- if (result == true) {
- if (action == 'approve') {
- widget.onApprove();
- } else {
- widget.onReject();
- }
- }
- }
- @override
- Widget build(BuildContext context) {
- final l10n = AppLocalizations.of(context);
- final isPending = widget.status == 'pending';
- final isDraft = widget.status == 'draft';
- final canApprove =
- isPending &&
- (widget.userRole == UserRole.approver ||
- widget.userRole == UserRole.finance ||
- widget.userRole == UserRole.admin);
- return Container(
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- color: Colors.white,
- boxShadow: [
- BoxShadow(
- color: Colors.black.withValues(alpha: 0.05),
- blurRadius: 4,
- offset: const Offset(0, -1),
- ),
- ],
- ),
- child: canApprove
- ? Row(
- children: [
- Expanded(
- child: OutlinedButton(
- onPressed: widget.isSubmitting
- ? null
- : () => _showOpinionDialog('reject'),
- style: OutlinedButton.styleFrom(
- foregroundColor: AppColors.danger,
- side: const BorderSide(color: AppColors.danger),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(8),
- ),
- minimumSize: const Size(double.infinity, 48),
- ),
- child: Text(l10n.get('reject')),
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- flex: 2,
- child: ElevatedButton(
- onPressed: widget.isSubmitting
- ? null
- : () => _showOpinionDialog('approve'),
- style: ElevatedButton.styleFrom(
- backgroundColor: AppColors.primary,
- foregroundColor: Colors.white,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(8),
- ),
- minimumSize: const Size(double.infinity, 48),
- ),
- child: widget.isSubmitting
- ? const SizedBox(
- width: 20,
- height: 20,
- child: CircularProgressIndicator(
- strokeWidth: 2,
- color: Colors.white,
- ),
- )
- : Text(l10n.get('approve')),
- ),
- ),
- ],
- )
- : Row(
- children: [
- if (isDraft && widget.onEdit != null) ...[
- Expanded(
- child: OutlinedButton(
- onPressed: widget.onEdit,
- child: Text(l10n.get('edit')),
- ),
- ),
- const SizedBox(width: 12),
- ],
- if (isPending && widget.onWithdraw != null)
- Expanded(
- child: OutlinedButton(
- onPressed: widget.onWithdraw,
- style: OutlinedButton.styleFrom(
- foregroundColor: AppColors.warning,
- side: const BorderSide(color: AppColors.warning),
- ),
- child: Text(l10n.get('withdrawAction')),
- ),
- ),
- ],
- ),
- );
- }
- @override
- void dispose() {
- _opinionCtrl.dispose();
- super.dispose();
- }
- }
|