attendence records, extra hours , rewards and punishment funnctionality have been added

This commit is contained in:
Daniah Ayad Al-sultani
2026-02-10 16:27:08 +03:00
parent cd7ba8e9d5
commit 1002937045
25 changed files with 1048 additions and 181 deletions

View File

@@ -1,13 +1,31 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import '../../domain/models/attendance_model.dart';
import '../../domain/models/overtime_model.dart';
import '../../domain/models/extra_payment_model.dart';
import '../../domain/models/finance_record.dart';
import 'gradient_line.dart';
import 'status_circle.dart';
import 'package:intl/intl.dart';
class WorkDayCard extends StatelessWidget {
const WorkDayCard({super.key});
final FinanceRecord record;
const WorkDayCard({super.key, required this.record});
@override
Widget build(BuildContext context) {
final dateFormat = DateFormat('yyyy.MM.dd');
String title = "يوم عمل";
if (record is OvertimeModel) title = "ساعات أضافية";
if (record is ExtraPaymentModel) {
title = (record as ExtraPaymentModel).isPenalty ? "عقوبة" : "مكافئة";
}
final dateStr =
record.date != null ? dateFormat.format(record.date!) : '--.--.--';
return Container(
margin: const EdgeInsets.symmetric(horizontal: 18, vertical: 6),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
@@ -25,87 +43,152 @@ class WorkDayCard extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
"يوم عمل",
textAlign: TextAlign.right,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
/// 🔥 FIXED: CENTERED LINES BETWEEN CIRCLES
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_StatusItem(
color: const Color(0xFFD16400),
icon: SvgPicture.asset('assets/images/money3.svg', width: 20),
label: "سعر كلي\n18,250 د.ع",
Text(
dateStr,
style: const TextStyle(fontSize: 12, color: Colors.grey),
),
/// LINE CENTERED VERTICALLY
Expanded(
child: Center(
child: GradientLine(
start: const Color(0xFFD16400),
end: const Color(0xFF1266A8),
),
Text(
title,
textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
_StatusItem(
color: const Color(0xFF1266A8),
icon: SvgPicture.asset('assets/images/watch.svg', width: 20),
label: "عدد ساعات\n5.50",
),
Expanded(
child: Center(
child: GradientLine(
start: const Color(0xFF1266A8),
end: const Color(0xFFB00000),
),
),
),
_StatusItem(
color: const Color(0xFFB00000),
icon: SvgPicture.asset('assets/images/out.svg', width: 20),
label: "خروج\n1:14pm",
),
Expanded(
child: Center(
child: GradientLine(
start: const Color(0xFFB00000),
end: const Color(0xFF0A8F6B),
),
),
),
_StatusItem(
color: const Color(0xFF0A8F6B),
icon: SvgPicture.asset('assets/images/in.svg', width: 20),
label: "دخول\n1:14pm",
),
],
),
const SizedBox(height: 16),
/// CONTENT
_buildContent(context),
const SizedBox(height: 12),
const Divider(color: Colors.black38),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("2025.12.1", style: TextStyle(fontSize: 12)),
Text("ملاحظات ان وجدت", style: TextStyle(fontSize: 12)),
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
record.reason ??
(record is ExtraPaymentModel
? ((record as ExtraPaymentModel).note ??
"لا يوجد ملاحظات")
: "لا يوجد ملاحظات"),
style: const TextStyle(fontSize: 12),
),
],
),
],
),
);
}
Widget _buildContent(BuildContext context) {
if (record is AttendanceModel) {
return _buildAttendanceContent(record as AttendanceModel);
} else if (record is OvertimeModel) {
return _buildOvertimeContent(record as OvertimeModel);
} else if (record is ExtraPaymentModel) {
return _buildExtraPaymentContent(record as ExtraPaymentModel);
}
return const SizedBox();
}
Widget _buildAttendanceContent(AttendanceModel attendance) {
final timeFormat = DateFormat('h:mm a');
final loginStr =
attendance.loginTime != null
? timeFormat.format(attendance.loginTime!)
: '--:--';
final logoutStr =
attendance.logoutTime != null
? timeFormat.format(attendance.logoutTime!)
: '--:--';
final hoursStr = attendance.workHours?.toString() ?? '0.00';
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_StatusItem(
color: const Color(0xFF1266A8),
icon: SvgPicture.asset('assets/images/watch.svg', width: 20),
label: "عدد ساعات\n$hoursStr",
),
_buildDivider(const Color(0xFF1266A8), const Color(0xFFB00000)),
_StatusItem(
color: const Color(0xFFB00000),
icon: SvgPicture.asset('assets/images/out.svg', width: 20),
label: "خروج\n$logoutStr",
),
_buildDivider(const Color(0xFFB00000), const Color(0xFF0A8F6B)),
_StatusItem(
color: const Color(0xFF0A8F6B),
icon: SvgPicture.asset('assets/images/in.svg', width: 20),
label: "دخول\n$loginStr",
),
],
);
}
Widget _buildOvertimeContent(OvertimeModel overtime) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_StatusItem(
color: const Color(0xFFD16400),
icon: SvgPicture.asset('assets/images/money3.svg', width: 20),
label: "سعر كلي\n${overtime.totalAmount.toStringAsFixed(0)} د.ع",
),
_buildDivider(const Color(0xFFD16400), const Color(0xFF1266A8)),
_StatusItem(
color: const Color(0xFF1266A8),
icon: SvgPicture.asset('assets/images/watch.svg', width: 20),
label: "ساعات إضافية\n${overtime.hours.toStringAsFixed(2)}",
),
],
);
}
Widget _buildExtraPaymentContent(ExtraPaymentModel payment) {
// Reason goes in the middle column.
// Note goes next to the amount (as part of the amount label).
final reasonText = payment.reason ?? "لا يوجد سبب";
final noteText = payment.note != null ? "\n(${payment.note})" : "";
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_StatusItem(
color: const Color(0xFFD16400),
icon: SvgPicture.asset('assets/images/money3.svg', width: 20),
label: "المبلغ\n${payment.amount.toStringAsFixed(0)} د.ع$noteText",
),
_buildDivider(const Color(0xFFD16400), const Color(0xFF1266A8)),
Expanded(
flex: 2,
child: Column(
children: [
Text(
reasonText,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const Text("السبب", style: TextStyle(fontSize: 12)),
],
),
),
],
);
}
Widget _buildDivider(Color start, Color end) {
return Expanded(child: Center(child: GradientLine(start: start, end: end)));
}
}
class _StatusItem extends StatelessWidget {
@@ -125,7 +208,7 @@ class _StatusItem extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
StatusCircle(color: color, icon: icon),
// const SizedBox(height: 3),
const SizedBox(height: 3),
Text(
label,
textAlign: TextAlign.center,