232 lines
8.4 KiB
Dart
232 lines
8.4 KiB
Dart
import 'package:coda_project/presentation/screens/notifications_screen.dart';
|
|
import 'package:coda_project/presentation/screens/user_settings_screen.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import '../widgets/finance_summary_card.dart';
|
|
import '../widgets/work_day_card.dart';
|
|
import '../widgets/settings_bar.dart';
|
|
import '../bloc/finance_bloc.dart';
|
|
import '../../core/di/injection_container.dart';
|
|
import '../../data/datasources/user_local_data_source.dart';
|
|
import '../../domain/models/finance_category.dart';
|
|
|
|
class FinanceScreen extends StatefulWidget {
|
|
final void Function(bool isScrollingDown)? onScrollEvent;
|
|
|
|
const FinanceScreen({super.key, this.onScrollEvent});
|
|
|
|
@override
|
|
State<FinanceScreen> createState() => _FinanceScreenState();
|
|
}
|
|
|
|
class _FinanceScreenState extends State<FinanceScreen> {
|
|
FinanceCategory currentCategory = FinanceCategory.attendance;
|
|
late ScrollController scrollController;
|
|
late FinanceBloc _financeBloc;
|
|
String? _employeeId;
|
|
DateTime selectedDate = DateTime.now();
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
scrollController = ScrollController();
|
|
_financeBloc = sl<FinanceBloc>();
|
|
_loadInitialData();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
scrollController.dispose();
|
|
_financeBloc.close();
|
|
super.dispose();
|
|
}
|
|
|
|
void _loadInitialData() async {
|
|
_employeeId = await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
if (mounted) {
|
|
setState(() {});
|
|
_triggerLoad();
|
|
}
|
|
}
|
|
|
|
void _triggerLoad() {
|
|
if (_employeeId != null && _employeeId!.isNotEmpty) {
|
|
_financeBloc.add(
|
|
LoadFinanceDataEvent(
|
|
employeeId: _employeeId!,
|
|
category: currentCategory,
|
|
month: selectedDate.month,
|
|
year: selectedDate.year,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> _onRefresh() async {
|
|
_triggerLoad();
|
|
await _financeBloc.stream.firstWhere(
|
|
(state) => state is FinanceLoaded || state is FinanceError,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return BlocProvider.value(
|
|
value: _financeBloc,
|
|
child: Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: SafeArea(
|
|
child: RefreshIndicator(
|
|
onRefresh: _onRefresh,
|
|
color: const Color(0xFF0A6B4A),
|
|
child: CustomScrollView(
|
|
controller: scrollController,
|
|
physics: const AlwaysScrollableScrollPhysics(
|
|
parent: BouncingScrollPhysics(),
|
|
),
|
|
slivers: [
|
|
SliverToBoxAdapter(
|
|
child: SettingsBar(
|
|
selectedIndex: 0,
|
|
showBackButton: false,
|
|
iconPaths: const [
|
|
'assets/images/user.svg',
|
|
'assets/images/ball.svg',
|
|
],
|
|
onTap: (index) {
|
|
if (index == 0) {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => const UserSettingsScreen(),
|
|
),
|
|
);
|
|
} else if (index == 1) {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (context) => const NotificationsScreen(),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
),
|
|
),
|
|
const SliverToBoxAdapter(child: SizedBox(height: 5)),
|
|
|
|
/// SUMMARY CARD
|
|
SliverToBoxAdapter(
|
|
child: BlocBuilder<FinanceBloc, FinanceState>(
|
|
buildWhen: (previous, current) => current is FinanceLoaded,
|
|
builder: (context, state) {
|
|
String amount = "0";
|
|
if (state is FinanceLoaded) {
|
|
amount = state.netSalary.toStringAsFixed(0);
|
|
amount = amount.replaceAllMapped(
|
|
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
|
|
(Match m) => '${m[1]},',
|
|
);
|
|
}
|
|
|
|
return FinanceSummaryCard(
|
|
totalAmount: amount,
|
|
currentCategory: currentCategory,
|
|
onCalendarTap: () async {
|
|
final date = await showDatePicker(
|
|
context: context,
|
|
initialDate: selectedDate,
|
|
firstDate: DateTime(2020),
|
|
lastDate: DateTime(2030),
|
|
);
|
|
if (date != null && mounted) {
|
|
setState(() => selectedDate = date);
|
|
if (_employeeId != null &&
|
|
_employeeId!.isNotEmpty) {
|
|
_financeBloc.add(
|
|
LoadFinanceDataEvent(
|
|
employeeId: _employeeId!,
|
|
category: currentCategory,
|
|
month: selectedDate.month,
|
|
year: selectedDate.year,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
},
|
|
onCategoryChanged: (category) {
|
|
if (category != null) {
|
|
setState(() => currentCategory = category);
|
|
if (_employeeId != null &&
|
|
_employeeId!.isNotEmpty) {
|
|
_financeBloc.add(
|
|
LoadFinanceDataEvent(
|
|
employeeId: _employeeId!,
|
|
category: currentCategory,
|
|
month: selectedDate.month,
|
|
year: selectedDate.year,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
},
|
|
);
|
|
},
|
|
),
|
|
),
|
|
|
|
/// DATA LIST
|
|
BlocBuilder<FinanceBloc, FinanceState>(
|
|
builder: (context, state) {
|
|
if (state is FinanceLoading || state is FinanceInitial) {
|
|
return const SliverToBoxAdapter(
|
|
child: Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(20.0),
|
|
child: CircularProgressIndicator(),
|
|
),
|
|
),
|
|
);
|
|
} else if (state is FinanceLoaded) {
|
|
if (state.records.isEmpty) {
|
|
return const SliverToBoxAdapter(
|
|
child: Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(20.0),
|
|
child: Text("لا توجد سجلات"),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
return SliverList(
|
|
delegate: SliverChildBuilderDelegate((context, index) {
|
|
return WorkDayCard(record: state.records[index]);
|
|
}, childCount: state.records.length),
|
|
);
|
|
} else if (state is FinanceError) {
|
|
return SliverToBoxAdapter(
|
|
child: Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(20.0),
|
|
child: Text(
|
|
state.message,
|
|
style: const TextStyle(color: Colors.red),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
return const SliverToBoxAdapter(child: SizedBox());
|
|
},
|
|
),
|
|
|
|
const SliverToBoxAdapter(child: SizedBox(height: 120)),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|