feat: update

This commit is contained in:
efrilm 2025-08-15 16:49:24 +07:00
parent cc8012354f
commit 79585b253d

View File

@ -28,228 +28,222 @@ class _InventoryReportWidgetState extends State<InventoryReportWidget> {
@override
Widget build(BuildContext context) {
return Expanded(
flex: 4,
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
border: Border.all(color: AppColors.stroke, width: 1),
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Report Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColors.light,
border: Border(
bottom: BorderSide(color: AppColors.stroke, width: 1),
),
return Container(
width: double.infinity,
decoration: BoxDecoration(
color: AppColors.white,
border: Border.all(color: AppColors.stroke, width: 1),
),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Report Header
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppColors.light,
border: Border(
bottom: BorderSide(color: AppColors.stroke, width: 1),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColors.primary,
),
const SizedBox(height: 4),
Text(
widget.searchDateFormatted,
style: TextStyle(
fontSize: 12,
color: AppColors.greyDark,
),
),
const SizedBox(height: 4),
Text(
widget.searchDateFormatted,
style: TextStyle(
fontSize: 12,
color: AppColors.greyDark,
),
],
),
Row(
children: [
// Download Button
GestureDetector(
onTap: () async {
try {
final status =
await PermessionHelper().checkPermission();
if (status) {
final pdfFile =
await InventoryReport.previewPdf(
searchDateFormatted:
widget.searchDateFormatted,
inventory: widget.inventory,
);
log("pdfFile: $pdfFile");
await HelperPdfService.openFile(pdfFile);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'Storage permission is required to save PDF'),
backgroundColor: Colors.red,
),
);
}
} catch (e) {
log("Error generating PDF: $e");
),
],
),
Row(
children: [
// Download Button
GestureDetector(
onTap: () async {
try {
final status =
await PermessionHelper().checkPermission();
if (status) {
final pdfFile = await InventoryReport.previewPdf(
searchDateFormatted: widget.searchDateFormatted,
inventory: widget.inventory,
);
log("pdfFile: $pdfFile");
await HelperPdfService.openFile(pdfFile);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to generate PDF: $e'),
const SnackBar(
content: Text(
'Storage permission is required to save PDF'),
backgroundColor: Colors.red,
),
);
}
},
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColors.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: AppColors.primary, width: 1),
),
child: Icon(
Icons.download_outlined,
size: 18,
color: AppColors.primary,
),
),
),
const SizedBox(width: 12),
// Status Badge
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
} catch (e) {
log("Error generating PDF: $e");
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to generate PDF: $e'),
backgroundColor: Colors.red,
),
);
}
},
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: AppColors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
color: AppColors.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
border:
Border.all(color: AppColors.green, width: 1),
Border.all(color: AppColors.primary, width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.check_circle,
size: 14,
child: Icon(
Icons.download_outlined,
size: 18,
color: AppColors.primary,
),
),
),
const SizedBox(width: 12),
// Status Badge
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: AppColors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: AppColors.green, width: 1),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.check_circle,
size: 14,
color: AppColors.green,
),
const SizedBox(width: 6),
Text(
'Aktif',
style: TextStyle(
fontSize: 12,
color: AppColors.green,
fontWeight: FontWeight.w600,
),
const SizedBox(width: 6),
Text(
'Aktif',
style: TextStyle(
fontSize: 12,
color: AppColors.green,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
],
),
],
),
),
],
),
],
),
),
// Summary Section
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.analytics_outlined,
size: 20,
color: AppColors.primary,
// Summary Section
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
Icons.analytics_outlined,
size: 20,
color: AppColors.primary,
),
const SizedBox(width: 8),
Text(
'Ringkasan Inventori',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColors.black,
),
const SizedBox(width: 8),
Text(
'Ringkasan Inventori',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: AppColors.black,
),
),
],
),
const SizedBox(height: 16),
),
],
),
const SizedBox(height: 16),
// Summary Grid
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
childAspectRatio: 2.2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
children: [
_buildSummaryCard(
'Total Produk',
(widget.inventory.summary.totalProducts).toString(),
AppColors.primary,
Icons.inventory_2_outlined,
),
_buildSummaryCard(
'Total Bahan',
widget.inventory.summary.totalIngredients.toString(),
AppColors.subtitle,
Icons.list_alt_outlined,
),
_buildSummaryCard(
'Total Nilai',
widget.inventory.summary.totalValue
.toString()
.currencyFormatRpV2,
AppColors.green,
Icons.monetization_on_outlined,
),
],
),
],
),
// Summary Grid
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
childAspectRatio: 2.2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
children: [
_buildSummaryCard(
'Total Produk',
(widget.inventory.summary.totalProducts).toString(),
AppColors.primary,
Icons.inventory_2_outlined,
),
_buildSummaryCard(
'Total Bahan',
widget.inventory.summary.totalIngredients.toString(),
AppColors.subtitle,
Icons.list_alt_outlined,
),
_buildSummaryCard(
'Total Nilai',
widget.inventory.summary.totalValue
.toString()
.currencyFormatRpV2,
AppColors.green,
Icons.monetization_on_outlined,
),
],
),
],
),
),
// Divider
Container(
height: 1,
margin: const EdgeInsets.symmetric(horizontal: 20),
color: AppColors.stroke,
// Divider
Container(
height: 1,
margin: const EdgeInsets.symmetric(horizontal: 20),
color: AppColors.stroke,
),
// Tabs
Container(
padding: const EdgeInsets.all(20),
child: Row(
children: [
_buildTab('Produk', 0),
const SizedBox(width: 12),
_buildTab('Bahan Baku', 1),
],
),
),
// Tabs
Container(
padding: const EdgeInsets.all(20),
child: Row(
children: [
_buildTab('Produk', 0),
const SizedBox(width: 12),
_buildTab('Bahan Baku', 1),
],
),
),
// Content based on selected tab
_selectedTabIndex == 0
? _buildProductsContent()
: _buildIngredientsContent(),
],
),
// Content based on selected tab
_selectedTabIndex == 0
? _buildProductsContent()
: _buildIngredientsContent(),
],
),
),
);