diff --git a/assets/item/empty.png b/assets/item/empty.png new file mode 100644 index 0000000..993c023 Binary files /dev/null and b/assets/item/empty.png differ diff --git a/lib/main.dart b/lib/main.dart index 414d8e8..9d9fcfa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:siopas/migrations/databasehelper.dart'; +import 'package:siopas/pages/peminjaman_barang/create-finish.dart'; import 'package:siopas/pages/transfer_peti/edit.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter/material.dart'; diff --git a/lib/migrations/databasehelper.dart b/lib/migrations/databasehelper.dart index 570c706..666fbd6 100644 --- a/lib/migrations/databasehelper.dart +++ b/lib/migrations/databasehelper.dart @@ -24,6 +24,8 @@ class SqfliteDatabaseHelper { // static final assetLocalTable = 'asset_statuses_local'; static final peminjamanTable = 'peminjamans'; + static final temporaryPeminjamanTable = 'temporary_peminjamans'; + static final pengembalianTable = 'pengembalians'; static final _version = 1; // Versi database ditingkatkan @@ -73,7 +75,6 @@ class SqfliteDatabaseHelper { exit_at DATETIME NULL, est_pengembalian DATETIME NULL, exit_pic TEXT NULL, - exit_warehouse INTEGER NULL, enter_at DATETIME NULL, enter_pic TEXT NULL, enter_warehouse INTEGER NULL, @@ -97,7 +98,6 @@ class SqfliteDatabaseHelper { exit_at DATETIME NULL, est_pengembalian DATETIME NULL, exit_pic TEXT NULL, - exit_warehouse INTEGER NULL, enter_at DATETIME NULL, enter_pic TEXT NULL, enter_warehouse INTEGER NULL, @@ -121,7 +121,6 @@ class SqfliteDatabaseHelper { exit_at DATETIME NULL, est_pengembalian DATETIME NULL, exit_pic TEXT NULL, - exit_warehouse INTEGER NULL, enter_at DATETIME NULL, enter_pic TEXT NULL, enter_warehouse INTEGER NULL, diff --git a/lib/models/asset_status_model.dart b/lib/models/asset_status_model.dart index bbc82a4..706b5e2 100644 --- a/lib/models/asset_status_model.dart +++ b/lib/models/asset_status_model.dart @@ -9,7 +9,7 @@ class AssetStatusModel { int? warehouse_id; DateTime? exit_at; String? exit_pic; - int? exit_warehouse; + // int? exit_warehouse; DateTime? enter_at; String? enter_pic; int? enter_warehouse; @@ -33,7 +33,7 @@ class AssetStatusModel { this.warehouse_id, this.exit_at, this.exit_pic, - this.exit_warehouse, + // this.exit_warehouse, this.enter_at, this.enter_pic, this.enter_warehouse, @@ -64,9 +64,9 @@ class AssetStatusModel { : 0, exit_at: parseDateTime(json['exit_at']), exit_pic: json['exit_pic'], - exit_warehouse: json['exit_warehouse'] != null - ? int.parse(json['exit_warehouse'].toString()) - : 0, + // exit_warehouse: json['exit_warehouse'] != null + // ? int.parse(json['exit_warehouse'].toString()) + // : 0, enter_at: parseDateTime(json['enter_at']), enter_pic: json['enter_pic'], enter_warehouse: json['enter_warehouse'] != null @@ -92,7 +92,7 @@ class AssetStatusModel { 'warehouse_id': warehouse_id, 'exit_at': exit_at?.toIso8601String(), 'exit_pic': exit_pic.toString(), - 'exit_warehouse': exit_warehouse, + // 'exit_warehouse': exit_warehouse, 'enter_at': enter_at?.toIso8601String(), 'enter_pic': enter_pic, 'enter_warehouse': enter_warehouse?.toString(), diff --git a/lib/models/m_asset_status_model.dart b/lib/models/m_asset_status_model.dart index 79440e5..ebb602a 100644 --- a/lib/models/m_asset_status_model.dart +++ b/lib/models/m_asset_status_model.dart @@ -6,7 +6,7 @@ class PetiAssetModel { int? id; int? tipe_peti_id; String? warna; - final String fix_lot; + String? fix_lot; int? packing_no; int? customer_id; int? jumlah; @@ -47,7 +47,7 @@ class PetiAssetModel { ? int.parse(json['tipe_peti_id'].toString()) : null, warna: json['warna'] != null ? json['warna'].toString() : null, - fix_lot: json['fix_lot'], + fix_lot: json['fix_lot'] != null ? json['fix_lot'].toString() : null, packing_no: json['packing_no'] != null ? int.parse(json['packing_no'].toString()) : null, @@ -95,7 +95,8 @@ class PetiAssetModel { 'kondisipeti_id': kondisipeti_id, 'status': status, 'jumlah': jumlah, - 'date_pembuatan': date_pembuatan!.toIso8601String(), + 'date_pembuatan': + date_pembuatan != null ? date_pembuatan.toString() : null, 'created_by': created_by, 'updated_by': updated_by, 'created_at': created_at!.toIso8601String(), diff --git a/lib/pages/home/conn_home_page.dart/syncronize.dart b/lib/pages/home/conn_home_page.dart/syncronize.dart index 5d69e06..5609971 100644 --- a/lib/pages/home/conn_home_page.dart/syncronize.dart +++ b/lib/pages/home/conn_home_page.dart/syncronize.dart @@ -148,11 +148,12 @@ class SyncronizationGlobalData { Map data = { "mobile_id": assetStatusesLocalList[i].mobile_id.toString(), "peti_id": assetStatusesLocalList[i].peti_id.toString(), + "warehouse_id": assetStatusesLocalList[i].warehouse_id.toString(), "exit_at": assetStatusesLocalList[i].exit_at.toString(), "est_pengembalian": assetStatusesLocalList[i].est_pengembalian.toString(), "exit_pic": assetStatusesLocalList[i].exit_pic.toString(), - "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), + // "exit_warehouse": assetStatusesLocalList[i].exit_warehouse.toString(), // "status": assetStatusesLocalList[i].status.toString(), "created_by": assetStatusesLocalList[i].created_by.toString(), "created_at": formattedCreatedAt, @@ -216,12 +217,13 @@ class SyncronizationGlobalData { Map data = { "mobile_id": assetStatusesLocalList[i]['mobile_id'].toString(), "peti_id": assetStatusesLocalList[i]['peti_id'].toString(), + "warehouse_id": assetStatusesLocalList[i]['warehouse_id'].toString(), "exit_at": assetStatusesLocalList[i]['exit_at'].toString(), "est_pengembalian": assetStatusesLocalList[i]['est_pengembalian'].toString(), "exit_pic": assetStatusesLocalList[i]['exit_pic'].toString(), - "exit_warehouse": - assetStatusesLocalList[i]['exit_warehouse'].toString(), + // "exit_warehouse": + // assetStatusesLocalList[i]['exit_warehouse'].toString(), "status": assetStatusesLocalList[i]['status'].toString(), "created_by": assetStatusesLocalList[i]['created_by'].toString(), "created_at": formattedCreatedAt, diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index 0383451..9a5d4eb 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -28,6 +28,8 @@ import 'conn_home_page.dart/syncronize.dart'; import 'controller/home_controller.dart'; class HomePage extends StatefulWidget { + final ControllerHome controllerHome = ControllerHome(); // Declare here + @override State createState() => _HomePageState(); } @@ -55,13 +57,17 @@ class _HomePageState extends State { List? _warehouseData; Timer? _timer; + int _peminjamanCount = 0; + int _pengembalianCount = 0; + int _transferCount = 0; + bool _isLoading = true; @override void initState() { super.initState(); _getUserToken(); - + _initData(); // Menerapkan Future untuk menangani tugas asinkronus Future.wait([ warehouseListAPI(), @@ -75,15 +81,35 @@ class _HomePageState extends State { datatablesWarehouseList(), ]).then((_) { // Selesaikan loading setelah semua tugas selesai - setState(() { - _isLoading = false; - }); + if (mounted) { + setState(() { + _isLoading = false; + }); + } }); // Inisialisasi _data di sini jika diperlukan _data = []; } + @override + void setState(fn) { + if (mounted) { + super.setState(fn); + } + } + + Future _initData() async { + try { + _peminjamanCount = await widget.controllerHome.getPeminjamanCount(); + _pengembalianCount = await widget.controllerHome.getPengembalianCount(); + _transferCount = await widget.controllerHome.getTransferCount(); + } catch (error) { + print(error); + } + // ... tambahkan inisialisasi lainnya + } + void _getUserToken() async { SharedPreferences prefs = await SharedPreferences.getInstance(); if (mounted) { @@ -286,63 +312,73 @@ class _HomePageState extends State { // Datatables ------------------------------------------------------------------------ Future datatablesAssetStatusList() async { - await Controller().fetchAssetStatusLocalController().then((value) { - setState(() { - _data = (value as List) - .map((e) => AssetStatusModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesPetiList() async { - await Controller().fetchPetiData().then((value) { - setState(() { - _petiData = (value as List) - .map((e) => PetiAssetModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesTipePetiList() async { - await Controller().fetchTipePetiData().then((value) { - setState(() { - _tipePetiData = (value as List) - .map((e) => TypePetiModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesCustomerList() async { - await Controller().fetchCustomerData().then((value) { - setState(() { - _customerData = (value as List) - .map((e) => CustomerModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesWarehouseList() async { - await Controller().fetchWarehouseData().then((value) { - setState(() { - _warehouseData = (value as List) - .map((e) => WarehouseModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } @override void dispose() { - // Memastikan untuk membatalkan timer saat widget di-dispose + _timer?.cancel(); super.dispose(); } @@ -354,31 +390,31 @@ class _HomePageState extends State { Widget cardMenuPeminjaman() { return Container( - margin: EdgeInsets.all(10), + height: 125, child: Card( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), + borderRadius: BorderRadius.circular(10.0), ), - elevation: 5, + elevation: 3, child: InkWell( onTap: () { // Aksi ketika card diklik Navigator.pushNamed(context, '/peminjaman-barang'); }, child: Container( - padding: EdgeInsets.all(16.0), + // padding: EdgeInsets.only(top: 8.0, bottom: 8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.vertical_align_top, - size: 50, + size: 30, color: Colors.greenAccent[700], ), - SizedBox(height: 10), + SizedBox(height: 5), Text( 'Peminjaman', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), ), ], ), @@ -390,31 +426,66 @@ class _HomePageState extends State { Widget cardMenuPengembalian() { return Container( - margin: EdgeInsets.all(10), + height: 125, child: Card( shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), + borderRadius: BorderRadius.circular(10.0), ), - elevation: 5, + elevation: 3, child: InkWell( onTap: () { // Aksi ketika card diklik Navigator.pushNamed(context, '/pengembalian-barang'); }, child: Container( - padding: EdgeInsets.all(16.0), + // padding: EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.vertical_align_bottom, - size: 50, + size: 30, color: Colors.blueAccent[700], ), - SizedBox(height: 10), + SizedBox(height: 5), Text( 'Pengembalian', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + ), + ], + ), + ), + ), + ), + ); + } + + Widget cardMenuTransfer() { + return Container( + height: 125, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + elevation: 3, + child: InkWell( + onTap: () { + // Aksi ketika card diklik + Navigator.pushNamed(context, '/transfer-peti'); + }, + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.input_outlined, + size: 30, + color: Colors.yellow[700], + ), + SizedBox(height: 5), + Text( + 'Transfer Peti', + style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), ), ], ), @@ -463,42 +534,6 @@ class _HomePageState extends State { ); } - Widget cardMenuTransfer() { - return Container( - margin: EdgeInsets.all(10), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), - elevation: 5, - child: InkWell( - onTap: () { - // Aksi ketika card diklik - Navigator.pushNamed(context, '/transfer-peti'); - }, - child: Container( - padding: EdgeInsets.all(16.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.input_outlined, - size: 50, - color: Colors.yellow[700], - ), - SizedBox(height: 10), - Text( - 'Transfer Peti', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - ], - ), - ), - ), - ), - ); - } - Widget _buildCountTile(IconData icon, int count, Color color, String text) { return Column( children: [ @@ -622,34 +657,6 @@ class _HomePageState extends State { ), ), ), - - // Divider - // Divider( - // height: 1, - // thickness: 1, - // color: Colors.black, // Black divider - // ), - - // Upload Only Button - // Container( - // width: double.infinity, - // child: TextButton( - // onPressed: () { - // Navigator.pop(context); // Close dialog - // syncToGlobal('Peminjaman'); - // syncToGlobal('Pengembalian'); - // syncToGlobal('Transfer'); - // }, - // child: Text( - // "Upload Only", - // style: TextStyle( - // color: Colors.black, - // fontSize: 16.0, - // fontFamily: 'Poppins', - // ), - // ), - // ), - // ), ], ), ); @@ -657,30 +664,196 @@ class _HomePageState extends State { ); } + Widget cardMenuSync() { + return Card( + elevation: 3, + margin: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + color: Color.fromARGB(255, 50, 39, 122), + padding: EdgeInsets.all(16.0), + child: Text( + "Sync Data Global", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 20.0, + ), + ), + ), + SizedBox(height: 10), + // Display counts for each table + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildCountTile( + Icons.vertical_align_top, + _peminjamanCount, + Colors.green[700]!, + 'Peminjaman', + ), + _buildCountTile( + Icons.vertical_align_bottom, + _pengembalianCount, + Colors.blue[700]!, + 'Pengembalian', + ), + _buildCountTile( + Icons.input_outlined, + _transferCount, + Colors.yellow[700]!, + 'Transfer', + ), + ], + ), + SizedBox(height: 10), + + // Re-init Button + ElevatedButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return Dialog( + backgroundColor: + Colors.grey[100], // Set the background color + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + elevation: 0, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Dialog title with close button + Container( + width: double.infinity, + color: Colors.indigo[700], // Indigo background + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + "Konfirmasi Sync", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontSize: 16.0, + ), + ), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.white, + ), + onPressed: () { + Navigator.pop(context); // Close dialog + }, + ), + ], + ), + ), + + // Divider + Divider( + height: 1, + thickness: 1, + color: Colors.black, // Black divider + ), + + // Description text + Container( + padding: EdgeInsets.all(16.0), + child: Text( + "Apakah Anda yakin ingin mengunggah dan mengunduh data?", + style: TextStyle( + fontSize: 16.0, + ), + ), + ), + + // Re-init Button with blue background + + ElevatedButton( + onPressed: () { + Navigator.pop(context); // Close dialog + fetchDataFromApiAndSync(); + }, + style: TextButton.styleFrom( + backgroundColor: Colors.blue[700], + ), + child: Text( + "Upload + Download", + style: TextStyle( + color: Colors.white, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), + ), + ], + ), + ); + }, + ); + }, + style: ElevatedButton.styleFrom( + primary: Colors.blue[700], + ), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Upload + Download", + style: TextStyle( + color: Colors.white, + fontSize: 16.0, + fontFamily: 'Poppins', + ), + ), + Icon( + Icons.cloud_upload, + color: Colors.white, + ), + ], + ), + ), + ) + ], + ), + ); + } + return Scaffold( backgroundColor: Colors.grey[200], appBar: AppBar( elevation: 0, automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], - actions: [ - IconButton( - icon: Icon( - Icons.cloud_sync, - size: 30, - ), - onPressed: () async { - if (await SyncronizationGlobalData.isInternet()) { - // Display custom dialog when the IconButton is pressed - showSyncDialog(context); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("No internet connection")), - ); - } - }, - ), - ], + // actions: [ + // IconButton( + // icon: Icon( + // Icons.cloud_sync, + // size: 30, + // ), + // onPressed: () async { + // if (await SyncronizationGlobalData.isInternet()) { + // // Display custom dialog when the IconButton is pressed + // showSyncDialog(context); + // } else { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar(content: Text("No internet connection")), + // ); + // } + // }, + // ), + // ], + centerTitle: true, title: Row( children: [ SizedBox(width: 10), @@ -707,14 +880,39 @@ class _HomePageState extends State { ), body: ListView( children: [ - GridView.count( - crossAxisCount: 2, - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), + cardMenuSync(), + SizedBox(height: 10), + Container( + padding: EdgeInsets.all(10), + child: Text( + 'Menu Aplikasi', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - cardMenuPeminjaman(), - cardMenuPengembalian(), - cardMenuTransfer(), + Expanded( + child: cardMenuPeminjaman(), + ), + Expanded( + child: cardMenuPengembalian(), + ), + ], + ), + SizedBox(height: 10), // Add some space between rows + Row( + children: [ + Expanded( + child: cardMenuTransfer(), + ), + Expanded( + child: Container(), + // child: cardMenuPengembalian(), + ), ], ), ], diff --git a/lib/pages/home/main_page.dart b/lib/pages/home/main_page.dart index 9386ac7..1831fa1 100644 --- a/lib/pages/home/main_page.dart +++ b/lib/pages/home/main_page.dart @@ -28,9 +28,11 @@ class _MainPageState extends State { currentIndex: currentIndex, selectedItemColor: Colors.indigoAccent, // Warna saat dipilih onTap: (index) { - setState(() { - currentIndex = index; - }); + if (mounted) { + setState(() { + currentIndex = index; + }); + } }, items: [ BottomNavigationBarItem( diff --git a/lib/pages/home/setting_page.dart b/lib/pages/home/setting_page.dart index 045090e..52f3cf2 100644 --- a/lib/pages/home/setting_page.dart +++ b/lib/pages/home/setting_page.dart @@ -27,9 +27,11 @@ class SettingPageState extends State { void _getUserToken() async { try { SharedPreferences prefs = await SharedPreferences.getInstance(); - setState(() { - token = prefs.getString('token'); - }); + if (mounted) { + setState(() { + token = prefs.getString('token'); + }); + } } catch (e) { print("Error: $e"); } diff --git a/lib/pages/peminjaman_barang/conn/syncronize.dart b/lib/pages/peminjaman_barang/conn/syncronize.dart index 46f95b1..9318c66 100644 --- a/lib/pages/peminjaman_barang/conn/syncronize.dart +++ b/lib/pages/peminjaman_barang/conn/syncronize.dart @@ -173,7 +173,7 @@ class SyncronizationPeminjamanData { "exit_at": assetStatus.exit_at.toString(), "est_pengembalian": assetStatus.est_pengembalian.toString(), "exit_pic": assetStatus.exit_pic.toString(), - "exit_warehouse": assetStatus.exit_warehouse.toString(), + // "exit_warehouse": assetStatus.exit_warehouse.toString(), "created_by": assetStatus.created_by.toString(), "created_at": formattedCreatedAt, }; @@ -248,8 +248,8 @@ class SyncronizationPeminjamanData { "est_pengembalian": assetStatusesLocalList[i]['est_pengembalian'].toString(), "exit_pic": assetStatusesLocalList[i]['exit_pic'].toString(), - "exit_warehouse": - assetStatusesLocalList[i]['exit_warehouse'].toString(), + // "exit_warehouse": + // assetStatusesLocalList[i]['exit_warehouse'].toString(), "status": assetStatusesLocalList[i]['status'].toString(), "created_by": assetStatusesLocalList[i]['created_by'].toString(), "created_at": formattedCreatedAt, diff --git a/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart index 00a8d47..2d0ce2d 100644 --- a/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart +++ b/lib/pages/peminjaman_barang/controller/peminjaman_controller.dart @@ -127,11 +127,11 @@ class Controller { await dbClient!.delete(SqfliteDatabaseHelper.peminjamanTable); } - Future addAllData(List contactList) async { + Future addAllData(List peminjamanList) async { var dbclient = await conn.db; Batch batch = dbclient!.batch(); - for (var contact in contactList) { + for (var contact in peminjamanList) { batch.insert( SqfliteDatabaseHelper.peminjamanTable, contact.toJson(), diff --git a/lib/pages/peminjaman_barang/create-finish.dart b/lib/pages/peminjaman_barang/create-finish.dart new file mode 100644 index 0000000..ab92fe8 --- /dev/null +++ b/lib/pages/peminjaman_barang/create-finish.dart @@ -0,0 +1,873 @@ +import 'dart:convert'; + +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/intl.dart'; +import 'package:loading_animation_widget/loading_animation_widget.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:collection/collection.dart'; +import 'package:uuid/uuid.dart'; + +import '../../models/asset_status_model.dart'; +import '../../models/customer_model.dart'; +import '../../models/disposal_model.dart'; +import '../../models/m_asset_status_model.dart'; +import '../../models/type_peti_model.dart'; +import '../../models/user_model.dart'; +import '../../models/warehouse_mode.dart'; +import '../../providers/auth_provider.dart'; +import '../../services/controllerApi.dart'; +import 'conn/syncronize.dart'; +import 'controller/peminjaman_controller.dart'; + +class InformasiDataEntryPage extends StatefulWidget { + final List temporaryDataList; + + InformasiDataEntryPage({required this.temporaryDataList}); + + @override + _InformasiDataEntryPageState createState() => _InformasiDataEntryPageState(); +} + +class _InformasiDataEntryPageState extends State { + String? token; + // List? customerSqfliteApi; + PetiAssetModel? petiSqfliteApi; + WarehouseModel? warehouseSqfliteApi; + WarehouseModel? warehouseTujuanSqfliteApi; + DisposalPetiModel? disposalSqfliteApi; + CustomerModel? customerSqfliteApi; + List? _valpeti; // Change this line + List? _valwarehouse; + List? _valwarehouseTujuan; + List? _valcustomer; + List? _valdisposal; + List _allPetiList = []; + List _unrestrictedPetiList = []; + List _filteredPetiList = []; + bool isQRCodeScanned = false; + String searchText = ''; + PetiAssetModel? selectedPeti; + TextEditingController searchBoxController = TextEditingController(); + TextEditingController _exit_atController = TextEditingController(); + TextEditingController _est_pengembalianController = TextEditingController(); + TextEditingController _penanggungJawabController = TextEditingController(); + TextEditingController _warehouseController = TextEditingController(); + + List selectedPetiList = []; + List? _data; + List temporaryDataList = []; + + final _formKey = GlobalKey(); + bool loading = true; + late Future _dataFuture; + // bool _isLoading = false; + + @override + void initState() { + super.initState(); + // Set loading ke true pada awalnya + if (mounted) { + if (mounted) { + setState(() { + loading = false; + }); + } + } + + _dataFuture = fetchData(); + } + + Future fetchData() async { + await _getUserToken(); + await warehouseListAPI(); + await petiListAPI(); + await disposalListAPI(); + await customerListAPI(); + initializeDateFormatting('id_ID', null); + + // Tandai bahwa proses loading telah selesai + if (mounted) { + setState(() { + loading = false; + }); + } + } + + Future _getUserToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + token = prefs.getString('token'); + loading = false; + }); + } + } + + void addDataToDropdown(PetiAssetModel peti) { + if (mounted) { + setState(() { + selectedPetiList.add(peti); + }); + } + } + + Future disposalListAPI() async { + if (mounted) { + await ControllerApi().fetchDisposalDataAPI().then((value) { + setState(() { + _valdisposal = (value as List) + .map((item) => DisposalPetiModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future customerListAPI() async { + if (mounted) { + await ControllerApi().fetchCustomerDataAPI().then((value) { + setState(() { + _valcustomer = (value as List) + .map((item) => CustomerModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future warehouseListAPI() async { + if (mounted) { + await ControllerApi().fetchWarehouseDataAPI().then((value) { + setState(() { + _valwarehouse = (value as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } + + Future isInteret() async { + await SyncronizationPeminjamanData.isInternet().then((connection) { + if (connection) { + print("Internet connection available"); + } else { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("No Internet"))); + } + }); + } + + @override + Widget build(BuildContext context) { + AuthProvider authProvider = + Provider.of(context, listen: false); + UserModel user = authProvider.user; + + // WarehouseModel? warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( + // (warehouse) => warehouse.id == _valwarehouse?.first.id, + // ); + + var uuid = Uuid(); + + DateTime? parseDateTime(String? dateTimeString) { + if (dateTimeString == null || dateTimeString.isEmpty) { + return null; + } + try { + return DateTime.parse(dateTimeString); + } catch (e) { + print('Error parsing DateTime: $e'); + return null; + } + } + + Future removePetiFromSharedPreferences( + PetiAssetModel removedPeti) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + // Retrieve existing data from SharedPreferences + List? petiListJson = prefs.getStringList('selectedPetiList'); + + if (petiListJson != null) { + // Convert JSON strings to PetiAssetModel objects + List existingPetiList = petiListJson + .map((petiJson) => PetiAssetModel.fromJson(json.decode(petiJson))) + .toList(); + + // Remove the specified peti from the list + existingPetiList.removeWhere((peti) => peti.id == removedPeti.id); + + // Save the updated list back to SharedPreferences + List updatedPetiListJson = + existingPetiList.map((peti) => json.encode(peti.toJson())).toList(); + + prefs.setStringList('selectedPetiList', updatedPetiListJson); + } + } + + void removePeti(int index) async { + PetiAssetModel? selectedPeti = + selectedPetiList != null ? selectedPetiList[index] : null; + + print('Before Remove: ${selectedPeti?.fix_lot}'); + + if (index >= 0 && index < selectedPetiList.length) { + if (mounted) { + PetiAssetModel removedPeti = selectedPetiList[index]; + + // Remove the data with the specified peti_id from temporaryDataList + temporaryDataList + .removeWhere((data) => data.peti_id == removedPeti.id); + + selectedPetiList.removeAt(index); + + await removePetiFromSharedPreferences(removedPeti); + + print('After Remove: ${selectedPeti?.fix_lot}'); + } + } else { + print('Invalid index: $index. No removal performed.'); + } + } + + List selectedPetis = widget.temporaryDataList + .map((data) { + PetiAssetModel? peti = + _valpeti?.firstWhereOrNull((peti) => peti.id == data.peti_id); + print("Checking conditions for Peti ID: ${data.peti_id}"); + print("Exit_atController: ${_exit_atController.text.isNotEmpty}"); + print("petiSqfliteApi: ${peti != null}"); + print("warehouseSqfliteApi: ${warehouseSqfliteApi != null}"); + if (peti != null) { + return peti; + } else { + print("Peti not found for ID: ${data.peti_id}"); + return PetiAssetModel( + id: -1, + fix_lot: '', /* other default values */ + ); + } + }) + .where((peti) => peti != null && peti.id != -1) + .cast() + .toList(); + + Future saveAssetData(List selectedPetis) async { + DateTime now = DateTime.now().toLocal(); + String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); + + List savedPetiIds = []; + + for (PetiAssetModel selectedPeti in selectedPetis) { + // print("Checking conditions for Peti ID: ${selectedPeti.id}"); + // print("Exit_atController: ${_exit_atController.text.isNotEmpty}"); + // print("petiSqfliteApi: ${petiSqfliteApi != null}"); + // print("warehouseSqfliteApi: ${warehouseSqfliteApi != null}"); + + if (selectedPeti == null) { + print("Selected Peti is null"); + continue; + } + + // Ensure that _valpeti is not null before trying to find the PetiAssetModel + if (_valpeti == null) { + print("_valpeti is null"); + continue; + } + + petiSqfliteApi = + _valpeti?.firstWhereOrNull((peti) => peti.id == selectedPeti.id); + + if (petiSqfliteApi == null) { + print("Peti not found for ID: ${selectedPeti.id}"); + continue; + } + + if (_exit_atController.text.isNotEmpty && + petiSqfliteApi != null && + warehouseSqfliteApi != null) { + print("All conditions met. Saving data..."); + + AssetStatusModel assetAddModel = AssetStatusModel( + id: null, + peti_id: selectedPeti.id, + customer_id: customerSqfliteApi?.id, + warehouse_id: warehouseSqfliteApi?.id, + exit_at: parseDateTime(_exit_atController.text), + exit_pic: _penanggungJawabController.text, + est_pengembalian: parseDateTime(_est_pengembalianController.text), + created_by: user.fullname, + created_at: parseDateTime(formattedDate), + mobile_id: uuid.v4(), + ); + + // Call addData function + int result = await Controller().addPeminjamanData(assetAddModel); + + if (result > 0) { + savedPetiIds.add(selectedPeti.id!); + if (mounted) { + setState(() { + _exit_atController.text = ''; + _penanggungJawabController.text = ''; + _est_pengembalianController.text = ''; + warehouseSqfliteApi?.id = null; + customerSqfliteApi?.id = null; + }); + } + print("Success Tambah data untuk Peti ID: ${selectedPeti.id}"); + EasyLoading.showSuccess("Data Berhasil Disimpan"); + // Reset controllers and make fields nullable + } else { + print("Failed untuk Peti ID: ${selectedPeti.id}"); + } + } else { + print("Conditions not met. Unable to save data."); + if (_exit_atController.text.isEmpty) { + print("Exit_atController is empty"); + } + if (petiSqfliteApi == null) { + print("petiSqfliteApi is null"); + } + if (warehouseSqfliteApi == null) { + print("warehouseSqfliteApi is null"); + } + } + } + + // Hapus peti-peti yang baru saja disimpan dari SharedPreferences + for (PetiAssetModel selectedPeti in selectedPetis) { + if (selectedPeti != null) { + await removePetiFromSharedPreferences(selectedPeti); + } + } + +// Jika Anda ingin pindah ke halaman setelah menyimpan data untuk semua peti + Navigator.pushNamed(context, '/peminjaman-barang'); + } + + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: true, + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Isikan Data Peminjaman Peti', + style: TextStyle( + fontSize: 16, + )), + ), + body: Form( + key: _formKey, + child: FutureBuilder( + future: _dataFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center( + child: LoadingAnimationWidget.staggeredDotsWave( + color: Colors.indigo, + size: 40, + ), + ); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 8), + Text( + 'List Peti:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + Container( + height: 250, + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey.withOpacity(0.5), + width: 1, + ), + borderRadius: BorderRadius.circular(8), + color: Colors.grey[100], + ), + padding: EdgeInsets.all(8), + child: Expanded( + child: ListView.builder( + itemCount: widget.temporaryDataList.length, + itemBuilder: (context, index) { + int? petiId = + widget.temporaryDataList[index].peti_id; + PetiAssetModel? petiSqfliteApi = + _valpeti?.firstWhereOrNull( + (peti) => peti.id == petiId, + ); + + return ConstrainedBox( + constraints: BoxConstraints( + maxHeight: + 100, // Set your desired height here + ), + child: Card( + elevation: 1, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Colors.grey.withOpacity(0.5), + width: 1, + ), + ), + margin: EdgeInsets.symmetric(vertical: 4), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: SingleChildScrollView( + child: Row( + children: [ + Text( + '${index + 1}.', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 16), + Text( + ' ${petiSqfliteApi?.fix_lot ?? ''}', + style: TextStyle(fontSize: 13), + ), + // Tambahkan properti lainnya sesuai kebutuhan + ], + ), + ), + ), + ), + ); + }, + ), + ), + ), + SizedBox(height: 16), + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Pilih Customer:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + DropdownSearch( + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + hintText: 'Pilih Customer', + border: OutlineInputBorder( + borderRadius: BorderRadius.all( + Radius.circular(5.0), + ), + ), + ), + ), + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, CustomerModel? customer, + bool? isSelected) { + if (customer == null) { + return SizedBox.shrink(); + } + return Container( + child: Column( + children: [ + ListTile( + title: Text( + customer.name.toString(), + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + ), + ), + leading: Icon( + Icons.person_pin, + size: 24, + color: customer.id == + customerSqfliteApi?.id + ? Colors.indigo[700] + : Colors.grey, + ), + ), + Divider( + height: 1, + color: Colors + .grey, // Warna pembatas (divider) + ), + ], + ), + color: customer.id == customerSqfliteApi?.id + ? Colors.grey.withOpacity(0.7) + : Colors.white, + ); + }, + fit: FlexFit.loose, + title: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Pilih Customer', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.red, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ], + ), + Divider(), + ], + ), + ), + ), + items: (_valcustomer ?? []) + .where((customer) => + customer.deleted_at != true) + .where((customer) => customer.name! + .toLowerCase() + .contains(searchBoxController.text + .toLowerCase())) + .toList() ?? + [], + itemAsString: (CustomerModel customer) => + customer.name ?? + "", // Ganti dengan properti yang sesuai + selectedItem: customerSqfliteApi, + onChanged: (CustomerModel? value) { + setState(() { + customerSqfliteApi = value; + }); + }, + validator: (CustomerModel? value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + ), + ], + ), + ), + SizedBox(height: 16), + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tanggal Peminjaman:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + FormBuilderDateTimePicker( + validator: (value) { + if (_exit_atController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text( + 'Tanggal Peminjaman harus diisi'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + return null; // Return null jika ada kesalahan + } + return null; // Return null jika tidak ada kesalahan + }, + controller: _exit_atController, + name: 'tanggal_peminjaman', + inputType: InputType.date, + format: DateFormat('yyyy-MM-dd', 'id_ID'), + decoration: InputDecoration( + hintText: 'Tanggal Peminjaman', + border: OutlineInputBorder(), + suffixIcon: Icon(Icons.calendar_today), + ), + onChanged: (DateTime? selectedDate) { + if (selectedDate != null) { + // Mengisi tanggal estimasi 7 hari ke depan + DateTime estimasiPengembalian = + selectedDate.add(Duration(days: 7)); + _est_pengembalianController.text = + DateFormat('yyyy-MM-dd') + .format(estimasiPengembalian); + } + }, + ), + ], + ), + ), + SizedBox(height: 16), + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Estimasi Pengembalian:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 4), + Text( + '* Terisi otomatis 7 hari setelah tanggal peminjaman', + style: TextStyle( + fontSize: 12, + color: Colors.red, + fontStyle: FontStyle.italic), + ), + SizedBox(height: 8), + FormBuilderDateTimePicker( + validator: (value) { + if (_est_pengembalianController.text.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text('Tanggal Estimasi Pengembalian'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + return null; // Return null jika ada kesalahan + } + return null; // Return null jika tidak ada kesalahan + }, + controller: _est_pengembalianController, + name: 'estimasi_pengembalian', + inputType: InputType.date, + format: DateFormat('yyyy-MM-dd', 'id_ID'), + decoration: InputDecoration( + hintText: 'Estimasi Tanggal Pengembalian', + border: OutlineInputBorder(), + suffixIcon: Icon(Icons.calendar_today), + ), + ), + ], + ), + ), + SizedBox(height: 16), + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Penanggung Jawab:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + TextFormField( + controller: _penanggungJawabController = + TextEditingController(text: user.fullname), + decoration: InputDecoration( + border: OutlineInputBorder(), + hintText: 'Penanggung Jawab', + ), + validator: (value) { + if (value == null || value.isEmpty) { + return 'Harus diisi'; + } + return null; // Return null jika tidak ada kesalahan + }, + ), + ], + ), + ), + SizedBox(height: 16), + Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Gudang:', + style: TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), + ), + SizedBox(height: 8), + DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + hintText: 'Gudang', + border: OutlineInputBorder(), + ), + hint: Text("Gudang"), + value: warehouseSqfliteApi, + items: (_valwarehouse ?? []) + .where((warehouse) => + warehouse.deleted_at != true) + .map((WarehouseModel warehouse) + // _valwarehouse?.map((WarehouseModel warehouse) + { + return DropdownMenuItem( + child: Row( + children: [ + Icon( + Icons.warehouse, + color: warehouseSqfliteApi?.id == + warehouse.id + ? Colors.indigo[700] + : Colors.grey, + ), + + SizedBox( + width: + 8), // Jarak antara ikon dan teks + Text( + '${warehouse.name}', + style: TextStyle( + fontSize: 16, + fontFamily: 'OpenSansCondensed', + fontWeight: + warehouseSqfliteApi?.id == + warehouse.id + ? FontWeight.bold + : FontWeight.normal, + ), + ), + ], + ), + value: warehouse, + ); + }).toList() ?? + [], + onChanged: (value) { + setState(() { + warehouseSqfliteApi = value; + }); + }, + ), + ], + ), + ), + ], + ), + ), + ); + } + }, + ), + ), + bottomNavigationBar: BottomAppBar( + height: MediaQuery.of(context).size.height / 10, + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: MediaQuery.of(context).size.width / 3, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + height: 50, // Lebar dan tinggi sesuai kebutuhan + width: 50, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.green, // Warna hijau untuk save + ), + child: IconButton( + onPressed: () async { + if (_formKey.currentState!.validate()) { + try { + if (_exit_atController.text.isNotEmpty && + warehouseSqfliteApi != null) { + await saveAssetData(selectedPetis); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text('Data belum lengkap'), + ], + ), + duration: Duration(seconds: 2), + ), + ); + } + } catch (e) { + print('Error storing data: $e'); + } + } + }, + icon: Icon(Icons.check, color: Colors.white), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/peminjaman_barang/create.dart b/lib/pages/peminjaman_barang/create.dart index de56968..d5491fb 100644 --- a/lib/pages/peminjaman_barang/create.dart +++ b/lib/pages/peminjaman_barang/create.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:core'; import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:siopas/models/asset_status_model.dart'; @@ -20,19 +19,18 @@ import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import 'package:uuid/uuid.dart'; import 'package:dropdown_search/dropdown_search.dart'; - import '../../connection/connection.dart'; import 'package:http/http.dart' as http; - import '../../models/user_model.dart'; import '../../providers/auth_provider.dart'; import '../../services/syncronizeAPI.dart'; import 'controller/peminjaman_controller.dart'; import 'package:collection/collection.dart'; +import 'create-finish.dart'; + class CreatePeminjamanBarang extends StatefulWidget { const CreatePeminjamanBarang({Key? key}) : super(key: key); - @override State createState() => _CreatePeminjamanBarangState(); } @@ -43,49 +41,41 @@ class _CreatePeminjamanBarangState extends State { // List? customerSqfliteApi; PetiAssetModel? petiSqfliteApi; WarehouseModel? warehouseSqfliteApi; - WarehouseModel? warehouseTujuanSqfliteApi; - DisposalPetiModel? disposalSqfliteApi; - CustomerModel? customerSqfliteApi; - List? _valpeti; // Change this line List? _valwarehouse; - List? _valwarehouseTujuan; - List? _valcustomer; List? _valdisposal; - List _allPetiList = []; - List _unrestrictedPetiList = []; List _filteredPetiList = []; bool isQRCodeScanned = false; - String searchText = ''; PetiAssetModel? selectedPeti; - TextEditingController searchBoxController = TextEditingController(); - TextEditingController _exit_atController = TextEditingController(); - TextEditingController _est_pengembalianController = TextEditingController(); - TextEditingController _penanggungJawabController = TextEditingController(); - final _formKey = GlobalKey(); + List? selectedPetiList = []; + List scannedPetiList = []; + List temporaryDataList = []; + List? _data; + List localSelectedPetiList = []; + final _formKey = GlobalKey(); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); Barcode? result; QRViewController? controller; - bool loading = true; @override void initState() { super.initState(); _getUserToken(); - warehouseListAPI(); petiListAPI(); - disposalListAPI(); - customerListAPI(); initializeDateFormatting('id_ID', null); - - setState(() { - loading = false; // Mengatur loading ke false setelah tugas selesai + assetStatusListSqflite(); + getSelectedPetiListFromSharedPreferences().then((retrievedPetiList) { + setState(() { + // Update the state with the retrieved list + selectedPetiList = retrievedPetiList; + loading = false; + }); }); } @@ -99,441 +89,487 @@ class _CreatePeminjamanBarangState extends State { } } - Future disposalListAPI() async { - if (mounted) { - await ControllerApi().fetchDisposalDataAPI().then((value) { - setState(() { - _valdisposal = (value as List) - .map((item) => DisposalPetiModel.fromJson(item)) - .toList(); - loading = false; - }); - }); - } + // Function to save selectedPetiList to SharedPreferences + void saveSelectedPetiListToSharedPreferences( + List selectedPetiList) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List> petiListJson = + selectedPetiList.map((peti) => peti.toJson()).toList(); + prefs.setStringList('selectedPetiList', + petiListJson.map((petiJson) => json.encode(petiJson)).toList()); } - Future customerListAPI() async { - if (mounted) { - await ControllerApi().fetchCustomerDataAPI().then((value) { - setState(() { - _valcustomer = (value as List) - .map((item) => CustomerModel.fromJson(item)) - .toList(); - loading = false; - }); - }); + // Function to retrieve selectedPetiList from SharedPreferences + Future> + getSelectedPetiListFromSharedPreferences() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + List? petiListJson = prefs.getStringList('selectedPetiList'); + if (petiListJson != null) { + List selectedPetiList = petiListJson + .map((petiJson) => PetiAssetModel.fromJson(json.decode(petiJson))) + .toList(); + return selectedPetiList; + } else { + return []; } } - Future warehouseListAPI() async { - if (mounted) { - await ControllerApi().fetchWarehouseDataAPI().then((value) { + void _handlePetiScanResult(int petiId) { + bool isPetiInAssetStatusList = + _data?.any((assetStatus) => assetStatus.peti_id == petiId) ?? false; + + bool isPetiInSelectedPetiList = + selectedPetiList!.any((peti) => peti.id == petiId); + + PetiAssetModel? petiSqfliteApi = _valpeti?.firstWhereOrNull( + (peti) => peti.id == petiId, + ); + + String fixLot = petiSqfliteApi?.fix_lot ?? + ''; // Menyimpan nilai fix_lot jika petiSqfliteApi tidak null + + if (isPetiInAssetStatusList) { + showErrorMessage( + 'Peti dengan $fixLot sudah terdaftar dalam daftar menu peminjaman. Harap periksa kembali.', + Colors.yellow[700]!, + ); + } else if (!isPetiInSelectedPetiList) { + PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + (peti) => + peti.id == petiId && + peti.deleted_at != true && + peti.status == 'AKTIF', + ); + + if (allowedPeti != null) { setState(() { - _valwarehouse = (value as List) - .map((item) => WarehouseModel.fromJson(item)) - .toList(); - loading = false; + isQRCodeScanned = true; + _filteredPetiList = [allowedPeti]; + petiSqfliteApi = allowedPeti; + selectedPetiList!.add(allowedPeti); + saveSelectedPetiListToSharedPreferences(selectedPetiList!); }); - }); - } - } - - Future petiListAPI() async { - if (mounted) { - await ControllerApi().fetchPetiDataAPI().then((value) { + } else { + showErrorMessage( + 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', + Colors.red[700]!, + ); setState(() { - _valpeti = (value as List) - .map((item) => PetiAssetModel.fromJson(item)) - .toList(); - loading = false; + isQRCodeScanned = false; + petiSqfliteApi = null; }); - }); + } + } else { + showErrorMessage( + 'Peti dengan $fixLot sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', + Colors.yellow[700]!, + ); } } - Future isInteret() async { - await SyncronizationPeminjamanData.isInternet().then((connection) { - if (connection) { - print("Internet connection available"); - } else { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("No Internet"))); - } - }); + void _onQRViewCreated(QRViewController controller) async { + this.controller = controller; + bool scanned = false; + + // Code to auto-focus the back camera + controller.flipCamera(); + await Future.delayed(const Duration(milliseconds: 400)); + controller.flipCamera(); + + controller.scannedDataStream.listen( + (scanData) async { + if (!scanned) { + try { + result = scanData; + List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + for (String line in lines) { + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; + } + } + } + int? petiId = int.tryParse(idPeti); + + if (petiId != null) { + _handlePetiScanResult(petiId); + } else { + showErrorMessage( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + Colors.yellow[700]!, + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + }); + } + + scanned = true; + } catch (e) { + controller.stopCamera(); + setState(() { + petiSqfliteApi = null; + }); + print('Error scanning QR Code: $e'); + showErrorMessage(e.toString(), Colors.red[700]!); + } finally { + controller.stopCamera(); + await Future.delayed(Duration(milliseconds: 500)); + if (mounted) { + Navigator.of(context).pop(); + } + } + } + }, + ); } - // Future _onQRViewCreated(QRViewController controller) async { + void showErrorMessage(String message, Color backgroundColor) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + message, + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), + ), + backgroundColor: backgroundColor, + ), + ); + } + + // void _onQRViewCreated(QRViewController controller) async { // this.controller = controller; // bool scanned = false; - // // code to auto focus kamera belakang + // // Code to auto-focus the back camera // controller.flipCamera(); // await Future.delayed(const Duration(milliseconds: 400)); // controller.flipCamera(); // controller.scannedDataStream.listen( - // (scanData) { + // (scanData) async { // if (!scanned) { // try { - // setState(() { - // result = scanData; - // List lines = result!.code!.split('\n'); - // String idPeti = ''; - // String idWarehouse = ''; - - // for (String line in lines) { - // if (line.contains(';')) { - // List values = line.split(';'); - // if (values.length >= 3) { - // idPeti = values[1]; - // idWarehouse = values[2]; - // break; - // } + // result = scanData; + // List lines = result!.code!.split('\n'); + // String idPeti = ''; + // String idWarehouse = ''; + // for (String line in lines) { + // if (line.contains(';')) { + // List values = line.split(';'); + // if (values.length >= 3) { + // idPeti = values[1]; + // idWarehouse = values[2]; + // break; // } // } - - // int? petiId = int.tryParse(idPeti); - // int? warehouseId = int.tryParse(idWarehouse); - // // AuthProvider authProvider = - // // Provider.of(context, listen: false); - // // UserModel user = authProvider.user; - - // if (petiId != null && warehouseId != null) { - // // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan - // PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( - // (peti) => - // peti.id == petiId && - // peti.deleted_at != true && - // // peti.warehouse_id == user.warehouse_id && - // peti.status == 'AKTIF', - // ); - - // if (allowedPeti != null) { - // petiSqfliteApi = allowedPeti; - - // warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( - // // warehouseSqfliteApi = _valwarehouse?.firstWhere( - // (warehouse) => warehouse.id == allowedPeti.warehouse_id, - // ); + // } + // int? petiId = int.tryParse(idPeti); + + // if (petiId != null) { + // // Memeriksa apakah peti_id sudah ada dalam _data (assetStatusListSqflite()) + // bool isPetiInAssetStatusList = + // _data?.any((assetStatus) => assetStatus.peti_id == petiId) ?? + // false; + + // PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + // (peti) => + // peti.id == petiId && + // peti.deleted_at != true && + // peti.status == 'AKTIF', + // ); + + // if (allowedPeti != null) { + // // Mengecek apakah peti sudah ada dalam daftar selectedPetiList + // bool isPetiInList = + // selectedPetiList.any((peti) => peti.id == allowedPeti!.id); + + // if (!isPetiInList) { + // // Peti belum ada dalam daftar, tambahkan + // setState(() { + // isQRCodeScanned = true; + // _filteredPetiList = [allowedPeti]; + // petiSqfliteApi = allowedPeti; + // selectedPetiList.add(allowedPeti); + // saveSelectedPetiListToSharedPreferences(selectedPetiList); + // }); // } else { - // // Tampilkan pesan error jika data tidak sesuai dengan hak akses - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Text( - // 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', - // style: TextStyle( - // color: Colors.white, - // fontSize: 12, - // ), - // ), - // backgroundColor: Colors.red[700], - // action: SnackBarAction( - // label: 'Tutup', - // onPressed: () { - // ScaffoldMessenger.of(context).hideCurrentSnackBar(); - // }, - // ), - // ), + // // Peti sudah ada dalam daftar, tampilkan pesan peringatan + // showErrorMessage( + // 'Peti ${allowedPeti.fix_lot} sudah ada dalam daftar.', + // Colors.yellow[700]!, // ); - // petiSqfliteApi = null; - // warehouseSqfliteApi = null; // } // } else { - // // Tampilkan pesan error jika nilai yang dipindai tidak sesuai - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Row( - // children: [ - // Icon( - // Icons.warning, - // color: Colors.black, - // ), - // SizedBox(width: 8), - // Text( - // 'Nilai QR Code tidak sesuai dengan yang diharapkan.', - // style: TextStyle( - // color: Colors.black, - // fontSize: 12, - // ), - // ), - // ], - // ), - // backgroundColor: Colors.yellow[700], - // ), + // // Peti tidak ditemukan atau tidak sesuai dengan hak akses + // showErrorMessage( + // 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', + // Colors.red[700]!, // ); - // petiSqfliteApi = null; - // warehouseSqfliteApi = null; + // setState(() { + // isQRCodeScanned = false; + // petiSqfliteApi = null; + // }); // } + // } else { + // // Nilai QR Code tidak sesuai dengan yang diharapkan + // showErrorMessage( + // 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + // Colors.yellow[700]!, + // ); + // setState(() { + // isQRCodeScanned = false; + // petiSqfliteApi = null; + // }); + // } - // scanned = true; - // }); - - // controller.stopCamera(); - - // Future.delayed(Duration(milliseconds: 500), () { - // if (mounted) { - // Navigator.of(context).pop(); - // } - // }); + // scanned = true; // } catch (e) { // controller.stopCamera(); - - // // Reset nilai dropdown Peti dan Warehouse // setState(() { // petiSqfliteApi = null; - // warehouseSqfliteApi = null; // }); // print('Error scanning QR Code: $e'); - - // ScaffoldMessenger.of(context).showSnackBar( - // SnackBar( - // content: Row( - // children: [ - // Icon( - // Icons.error, - // color: Colors.red[400], - // ), - // SizedBox(width: 8), - // Flexible( - // child: Text( - // e.toString(), - // style: TextStyle( - // color: Colors.white, - // fontSize: 12, - // ), - // ), - // ), - // ], - // ), - // backgroundColor: Colors.red[700], - // ), - // ); + // showErrorMessage(e.toString(), Colors.red[700]!); + // } finally { + // controller.stopCamera(); + // await Future.delayed(Duration(milliseconds: 500)); + // if (mounted) { + // Navigator.of(context).pop(); + // } // } // } // }, // ); // } - Future _onQRViewCreated(QRViewController controller) async { - this.controller = controller; - bool scanned = false; - - // code to auto focus kamera belakang - controller.flipCamera(); - await Future.delayed(const Duration(milliseconds: 400)); - controller.flipCamera(); - - controller.scannedDataStream.listen( - (scanData) { - if (!scanned) { - try { - setState(() { - result = scanData; - List lines = result!.code!.split('\n'); - String idPeti = ''; - String idWarehouse = ''; - - for (String line in lines) { - if (line.contains(';')) { - List values = line.split(';'); - if (values.length >= 3) { - idPeti = values[1]; - idWarehouse = values[2]; - break; - } - } - } - - int? petiId = int.tryParse(idPeti); - int? warehouseId = int.tryParse(idWarehouse); - // AuthProvider authProvider = Provider.of(context, listen: false); - // UserModel user = authProvider.user; - - // Dalam fungsi yang menangani pemindaian QR code - // Dalam fungsi yang menangani pemindaian QR code - if (petiId != null && warehouseId != null) { - // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan - PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( - (peti) => - peti.id == petiId && - peti.deleted_at != true && - peti.status == 'AKTIF', - ); - - if (allowedPeti != null) { - setState(() { - isQRCodeScanned = true; - // Mengisi _filteredPetiList untuk dropdown hasil QR Code - _filteredPetiList = [ - _valpeti!.firstWhere((peti) => peti.id == allowedPeti.id) - ]; - - petiSqfliteApi = allowedPeti; - - warehouseSqfliteApi = _valwarehouse?.firstWhereOrNull( - (warehouse) => warehouse.id == allowedPeti.warehouse_id, - ); - - customerSqfliteApi = _valcustomer?.firstWhereOrNull( - (customer) => customer.id == allowedPeti.customer_id, - ); - }); - } else { - // Tampilkan pesan error jika data tidak sesuai dengan hak akses - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - backgroundColor: Colors.red[700], - action: SnackBarAction( - label: 'Tutup', - onPressed: () { - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - }, - ), - ), - ); - setState(() { - isQRCodeScanned = false; - petiSqfliteApi = null; - warehouseSqfliteApi = null; - }); - } - } else { - // Tampilkan pesan error jika nilai yang dipindai tidak sesuai - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.warning, - color: Colors.black, - ), - SizedBox(width: 8), - Text( - 'Nilai QR Code tidak sesuai dengan yang diharapkan.', - style: TextStyle( - color: Colors.black, - fontSize: 12, - ), - ), - ], - ), - backgroundColor: Colors.yellow[700], - ), - ); - setState(() { - isQRCodeScanned = false; - petiSqfliteApi = null; - warehouseSqfliteApi = null; - }); - } - - scanned = true; - }); - - controller.stopCamera(); - - Future.delayed(Duration(milliseconds: 500), () { - if (mounted) { - Navigator.of(context).pop(); - } - }); - } catch (e) { - controller.stopCamera(); + Future assetStatusListSqflite() async { + if (mounted) { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); + }); + } + } - // Reset nilai dropdown Peti dan Warehouse - setState(() { - petiSqfliteApi = null; - warehouseSqfliteApi = null; - }); - print('Error scanning QR Code: $e'); + Future petiListAPI() async { + if (mounted) { + await ControllerApi().fetchPetiDataAPI().then((value) { + setState(() { + _valpeti = (value as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + loading = false; + }); + }); + } + } - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.error, - color: Colors.red[400], - ), - SizedBox(width: 8), - Flexible( - child: Text( - e.toString(), - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - ), - ], - ), - backgroundColor: Colors.red[700], - ), - ); - } - } - }, - ); + Future> _petiListAPI() async { + List petiList = await ControllerApi().fetchPetiDataAPI(); + return petiList.map((item) => PetiAssetModel.fromJson(item)).toList(); } + // Future> _petiListAPI() async { + // // Fetch data from the API + // dynamic apiPetiList = await ControllerApi().fetchPetiDataAPI(); + + // // Ensure apiPetiList is of type List + // List petiList = []; + + // if (apiPetiList is List) { + // petiList = + // apiPetiList.map((item) => PetiAssetModel.fromJson(item)).toList(); + // } + + // // Fetch data from SharedPreferences + // List sharedPreferencesPetiList = + // await getSelectedPetiListFromSharedPreferences(); + + // // Merge the lists, ensuring no duplicates + // List mergedPetiList = []; + // Set petiIds = Set(); + + // for (PetiAssetModel peti in petiList) { + // if (!petiIds.contains(peti.id)) { + // mergedPetiList.add(peti); + // petiIds.add(int.parse(peti.id.toString())); + // } + // } + + // for (PetiAssetModel peti in sharedPreferencesPetiList) { + // if (!petiIds.contains(peti.id)) { + // mergedPetiList.add(peti); + // petiIds.add(int.parse(peti.id.toString())); + // } + // } + + // return mergedPetiList; + // } + @override Widget build(BuildContext context) { AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; - var uuid = Uuid(); - - DateTime? parseDateTime(String? dateTimeString) { - if (dateTimeString == null || dateTimeString.isEmpty) { - return null; - } - - try { - return DateTime.parse(dateTimeString); - } catch (e) { - print('Error parsing DateTime: $e'); - return null; - } - } - Future saveAssetData() async { + print('Entering saveAssetData'); DateTime now = DateTime.now().toLocal(); String formattedDate = DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(now); - if (_exit_atController.text.isNotEmpty) { + // Cek apakah ada item yang dipilih di dalam selectedPetiList + if (selectedPetiList!.any((peti) => peti == null)) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text("Pilih setidaknya satu peti"), + backgroundColor: Colors.red, + )); + print('Exiting saveAssetData - No peti selected'); + return; + } + + // Iterasi melalui selectedPetiList + for (var peti in selectedPetiList!) { + // Buat model baru AssetStatusModel assetAddModel = AssetStatusModel( id: null, - peti_id: petiSqfliteApi!.id, - customer_id: customerSqfliteApi!.id, - warehouse_id: warehouseSqfliteApi!.id, - exit_at: parseDateTime(_exit_atController.text), - exit_pic: _penanggungJawabController.text, - exit_warehouse: warehouseTujuanSqfliteApi!.id, - est_pengembalian: parseDateTime(_est_pengembalianController.text), - created_by: user.fullname, - created_at: parseDateTime(formattedDate), - mobile_id: uuid.v4(), + peti_id: peti!.id, + // Tambahkan properti lainnya sesuai kebutuhan ); - // Call addData function - int result = await Controller().addPeminjamanData(assetAddModel); - if (result > 0) { - print("Success Tambah data"); - // print(result); - Navigator.pushNamed(context, '/peminjaman-barang'); - EasyLoading.showSuccess("Data Berhasil Disimpan"); + int index = + temporaryDataList.indexWhere((data) => data.peti_id == peti.id); + + if (index != -1) { + // Jika peti_id sudah ada, ganti entri yang sudah ada + temporaryDataList[index] = assetAddModel; } else { - print("Failed"); + // Jika peti_id belum ada, tambahkan ke dalam list + temporaryDataList.add(assetAddModel); } } + + print('Temporary data added. Length: ${temporaryDataList.length}'); + // Navigasi ke halaman selanjutnya dengan membawa data temporaryDataList + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => InformasiDataEntryPage( + temporaryDataList: temporaryDataList, + ), + ), + ); + print('Exiting saveAssetData'); + } + + Future checkAndAddPeti(PetiAssetModel value) async { + // print('Checking and adding Peti: ${value.fix_lot}'); + List assetStatusList = + await Controller().fetchAssetStatusLocalController(); + + // Ensure assetStatusList is of type List + if (assetStatusList is List) { + // Convert JSON strings to AssetStatusModel objects + assetStatusList = assetStatusList + .map((item) => + AssetStatusModel.fromJson(item as Map)) + .toList(); + } + + bool isPetiInSqflite = + assetStatusList.any((assetStatus) => assetStatus.peti_id == value.id); + + bool isPetiInLocalList = localSelectedPetiList.contains(value); + + bool isPetiInSelectedPetiList = + selectedPetiList!.any((peti) => peti.id == value.id); + + if (isPetiInSqflite) { + // print('Peti is already in Sqflite.'); + showErrorMessage( + 'Peti dengan ${value.fix_lot} sudah ada dalam daftar menu peminjaman. Harap periksa kembali.', + Colors.yellow[700]!, + ); + } else if (isPetiInSelectedPetiList || isPetiInLocalList) { + // print('Peti is already in selectedPetiList.'); + showErrorMessage( + 'Peti dengan ${value.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', + Colors.yellow[700]!, + ); + } else { + // If the item passes all conditions, add it to the list + print('Adding Peti to the list.'); + setState(() { + selectedPetiList!.add(value); + saveSelectedPetiListToSharedPreferences(selectedPetiList!); + }); + } + } + +// Function to remove peti data from SharedPreferences + Future removePetiFromSharedPreferences( + PetiAssetModel removedPeti) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + + // Retrieve existing data from SharedPreferences + List? petiListJson = prefs.getStringList('selectedPetiList'); + + if (petiListJson != null) { + // Convert JSON strings to PetiAssetModel objects + List existingPetiList = petiListJson + .map((petiJson) => PetiAssetModel.fromJson(json.decode(petiJson))) + .toList(); + + // Remove the specified peti from the list + existingPetiList.removeWhere((peti) => peti.id == removedPeti.id); + + // Save the updated list back to SharedPreferences + List updatedPetiListJson = + existingPetiList.map((peti) => json.encode(peti.toJson())).toList(); + + prefs.setStringList('selectedPetiList', updatedPetiListJson); + } + } + + void removePeti(int index) async { + PetiAssetModel? selectedPeti = + selectedPetiList != null ? selectedPetiList![index] : null; + + print( + 'Before Remove: ${selectedPeti?.fix_lot}'); // Cetak atribut tertentu sebelum penghapusan + + if (index >= 0 && index < selectedPetiList!.length) { + if (mounted) { + // Simpan peti yang akan dihapus + PetiAssetModel removedPeti = selectedPetiList![index]; + + // Hapus item dari selectedPetiList + selectedPetiList!.removeAt(index); + + // Hapus entri yang sesuai dari temporaryDataList berdasarkan peti_id + temporaryDataList + .removeWhere((data) => data.peti_id == removedPeti.id); + + // Hapus data dari SharedPreferences + await removePetiFromSharedPreferences(removedPeti); + + print( + 'After Remove: ${selectedPeti?.fix_lot}'); // Cetak daftar setelah penghapusan + } + } else { + print('Invalid index: $index. Tidak ada penghapusan yang dilakukan.'); + } } var scanArea = (MediaQuery.of(context).size.width < 400 || @@ -542,6 +578,7 @@ class _CreatePeminjamanBarangState extends State { : 300.0; return Scaffold( + backgroundColor: Colors.grey[100], appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.indigo[700], @@ -559,602 +596,448 @@ class _CreatePeminjamanBarangState extends State { child: Form( key: _formKey, child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Row( - children: [ - Expanded( - child: Card( - elevation: 2, - child: Container( - margin: EdgeInsets.all(8), - child: DropdownSearch( - popupProps: PopupProps.bottomSheet( - showSearchBox: true, - itemBuilder: (context, PetiAssetModel? peti, - bool? isSelected) { - if (peti == null) { - return SizedBox.shrink(); - } - // Tentukan warna dan ikon berdasarkan kondisi status - Color bulletColor = peti.status == 'AKTIF' - ? Colors.green - : Colors.red; - IconData bulletIcon = - peti.status == 'AKTIF' - ? Icons.circle - : Icons.circle; - - return Container( - child: Column( - children: [ - ListTile( - title: Text( - peti.fix_lot.toString(), - style: TextStyle( - fontSize: 16, - fontFamily: - 'OpenSansCondensed', + Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + color: Colors.grey.withOpacity(0.8), + width: + 1), // Tambahkan ini untuk menambahkan border + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: + EdgeInsets.only(left: 8, right: 8, top: 13), + child: Text( + 'Add List Peti / Scan Peti:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + ), + Row( + children: [ + Expanded( + child: Container( + margin: EdgeInsets.only(left: 8), + child: FutureBuilder>( + future: _petiListAPI(), + builder: (context, + AsyncSnapshot> + snapshot) { + if (snapshot.connectionState == + ConnectionState.waiting) { + return Center( + child: CircularProgressIndicator(), + ); + } else if (snapshot.hasError) { + return Text( + 'Error: ${snapshot.error}'); + } else { + List filteredItems = + snapshot.data?.where((peti) { + // Replace the condition with your logic + return !localSelectedPetiList + .contains( + peti.id) && + !scannedPetiList + .contains(peti.id); + }).toList() ?? + []; + return DropdownSearch( + popupProps: PopupProps.bottomSheet( + showSearchBox: true, + itemBuilder: (context, + PetiAssetModel? peti, + bool? isSelected) { + if (peti == null) { + return SizedBox.shrink(); + } + String itemAsString( + PetiAssetModel item) { + return item.fix_lot ?? ''; + } + + // Convert the item to a string for comparison + String petiAsString = + itemAsString(peti); + + // Check if the selected item is already in the list obtained from SharedPreferences + bool isPetiInSharedPreferences = + localSelectedPetiList.any( + (selectedPeti) => + itemAsString( + selectedPeti) == + petiAsString); + + // Check if the selected item is already in the list of scanned peti IDs + bool isPetiInScannedList = + scannedPetiList.any( + (scannedPeti) => + itemAsString( + scannedPeti) == + petiAsString); + + // Include the item only if it's not in either list + if (!isPetiInSharedPreferences && + !isPetiInScannedList) { + // Tentukan warna dan ikon berdasarkan kondisi status + Color bulletColor = + peti.status == 'AKTIF' + ? Colors.green + : Colors.red; + IconData bulletIcon = + peti.status == 'AKTIF' + ? Icons.circle + : Icons.circle; + + return Container( + child: Column( + children: [ + ListTile( + title: Text( + peti.fix_lot + .toString(), + style: TextStyle( + fontSize: 16, + fontFamily: + 'OpenSansCondensed', + ), + ), + leading: Icon( + bulletIcon, + color: bulletColor, + size: 24, + ), + ), + Divider( + height: 1, + color: Colors + .grey, // Warna pembatas (divider) + ), + ], + ), + color: peti.id == + petiSqfliteApi?.id + ? Colors.grey + .withOpacity(0.7) + : Colors.white, + ); + } else { + // Return an empty container for items that should be hidden + return SizedBox.shrink(); + } + }, + fit: FlexFit.loose, + title: Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment + .spaceBetween, + children: [ + Text( + 'Pilih Peti', + style: TextStyle( + fontSize: 18, + fontWeight: + FontWeight + .bold), + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.red, + ), + onPressed: () { + Future.delayed( + Duration.zero, + () { + Navigator.pop( + context); + }); + }, + ), + ], + ), + Divider(), + ], ), ), - leading: Icon( - bulletIcon, - color: bulletColor, - size: 24, - ), - ), - Divider( - height: 1, - color: Colors - .grey, // Warna pembatas (divider) ), - ], - ), - color: peti.id == petiSqfliteApi?.id - ? Colors.grey.withOpacity(0.7) - : Colors.white, - ); - }, - fit: FlexFit.loose, - title: Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Pilih Peti', - style: TextStyle( - fontSize: 18, - fontWeight: - FontWeight.bold), - ), - IconButton( - icon: Icon( - Icons.close, - color: Colors.red, + dropdownDecoratorProps: + DropDownDecoratorProps( + dropdownSearchDecoration: + InputDecoration( + hintText: 'Pilih Peti', + border: OutlineInputBorder( + borderRadius: + BorderRadius.all( + Radius.circular(5.0), + ), ), - onPressed: () { - Navigator.pop(context); - }, ), - ], - ), - Divider(), - ], - ), + ), + items: filteredItems, + itemAsString: + (PetiAssetModel item) => + item.fix_lot ?? '', + onBeforeChange: + (PetiAssetModel? from, + PetiAssetModel? to) async { + // The logic here should remain the same + bool isPetiInSharedPreferences = + localSelectedPetiList + .contains(to); + bool isPetiInScannedList = + scannedPetiList + .contains(to?.id); + + if (isPetiInSharedPreferences || + isPetiInScannedList) { + showErrorMessage( + 'Peti dengan ${to?.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', + Colors.yellow[700]!, + ); + + // Wait for a short time to display the error message before returning false + await Future.delayed(Duration( + milliseconds: 500)); + return false; // Cancel the change + } + + return true; // Allow the change + }, + onChanged: + (PetiAssetModel? value) async { + if (value != null) { + bool isPetiInSharedPreferences = + localSelectedPetiList + .contains(value); + bool isPetiInScannedList = + scannedPetiList + .contains(value.id); + + if (isPetiInSharedPreferences || + isPetiInScannedList) { + print( + 'Peti is already in SharedPreferences or Scanned List.'); + showErrorMessage( + 'Peti dengan ${value.fix_lot} sudah ada dalam daftar pilihan List Peti. Harap periksa kembali.', + Colors.yellow[700]!, + ); + } else { + // Move the asynchronous work outside the setState + await checkAndAddPeti(value); + } + } + }, + ); + } + }, ), ), - - dropdownDecoratorProps: - DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: 'Pilih Peti', - border: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(5.0), - ), - ), + ), + SizedBox(width: 8), // Spacer antara dua card + Container( + margin: EdgeInsets.all(8), + height: + MediaQuery.of(context).size.height / 10, + decoration: BoxDecoration( + color: Colors.indigoAccent, + borderRadius: BorderRadius.circular(15), + border: Border.all( + color: Colors.white, + width: 3, ), ), - - items: (isQRCodeScanned - ? _filteredPetiList - : (_valpeti ?? []).where((peti) => - peti.deleted_at != true && - (peti.warehouse_id == - user.warehouse_id) && - (peti.status == 'AKTIF'))) - .where((peti) => peti.fix_lot! - .toLowerCase() - .contains(searchBoxController.text - .toLowerCase())) - .toList() ?? - [], - // searchBoxController: searchBoxController, - itemAsString: (PetiAssetModel item) => - item.fix_lot ?? - "", // Ganti dengan properti yang sesuai - - selectedItem: petiSqfliteApi, - - onChanged: (PetiAssetModel? value) { - setState(() { - petiSqfliteApi = value; - if (value != null) { - warehouseSqfliteApi = _valwarehouse - ?.firstWhere((warehouse) => - warehouse.id == - value.warehouse_id); - customerSqfliteApi = _valcustomer - ?.firstWhereOrNull((customer) => - customer.id == - value.customer_id); - - // Perbarui _unrestrictedPetiList sesuai pemilihan manual - _unrestrictedPetiList = [ - _valpeti!.firstWhere( - (peti) => peti.id == value.id) - ]; - } - }); - }, - validator: (PetiAssetModel? value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - ), - ), - ), - ), - SizedBox(width: 8), // Spacer antara dua card - Card( - elevation: 2, - child: Container( - margin: EdgeInsets.all(8), - height: MediaQuery.of(context).size.height / 10, - decoration: BoxDecoration( - color: Colors.indigoAccent, - borderRadius: BorderRadius.circular(5), - ), - child: IconButton( - onPressed: () { - showModalBottomSheet( - context: context, - isScrollControlled: - true, // Set modal menjadi fullscreen - builder: (BuildContext context) { - return Stack( - alignment: Alignment.center, - children: [ - Container( - height: double.infinity, - width: double.infinity, - child: QRView( - key: qrKey, - onQRViewCreated: _onQRViewCreated, - overlay: QrScannerOverlayShape( - borderColor: Colors.red, - borderRadius: 10, - borderLength: 30, - borderWidth: 10, - cutOutSize: scanArea, - ), - ), - ), - Positioned( - bottom: 30, - height: 60, - child: Container( - height: - 60, // Lebar dan tinggi sesuai kebutuhan - width: 60, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors - .red, // Warna merah untuk close + child: IconButton( + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: + true, // Set modal menjadi fullscreen + builder: (BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + Container( + height: double.infinity, + width: double.infinity, + child: QRView( + key: qrKey, + onQRViewCreated: + _onQRViewCreated, + overlay: + QrScannerOverlayShape( + borderColor: Colors.red, + borderRadius: 10, + borderLength: 30, + borderWidth: 10, + cutOutSize: scanArea, + ), + ), ), - - child: IconButton( - onPressed: () { - Navigator.of(context).pop(); - }, - icon: Icon( - Icons.close, - size: 40, + Positioned( + bottom: 30, + height: 60, + child: Container( + height: + 60, // Lebar dan tinggi sesuai kebutuhan + width: 60, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors + .red, // Warna merah untuk close + ), + child: IconButton( + onPressed: () { + Navigator.of(context) + .pop(); + }, + icon: Icon( + Icons.close, + size: 40, + ), + color: Colors.white, + ), ), - color: Colors.white, ), - ), - ), - ], + ], + ); + }, ); }, - ); - }, - icon: Icon( - Icons.qr_code, - size: 30, - ), - color: Colors.white, // Warna ikon - ), - ), - ), - ], - ), - SizedBox(height: 16), - Card( - elevation: 2, - child: Padding( - padding: const EdgeInsets.all(8), - child: DropdownSearch( - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: 'Pilih Customer', - border: OutlineInputBorder( - borderRadius: BorderRadius.all( - Radius.circular(5.0), - ), - ), - ), - ), - popupProps: PopupProps.bottomSheet( - showSearchBox: true, - itemBuilder: (context, CustomerModel? customer, - bool? isSelected) { - if (customer == null) { - return SizedBox.shrink(); - } - - return Container( - child: Column( - children: [ - ListTile( - title: Text( - customer.name.toString(), - style: TextStyle( - fontSize: 16, - fontFamily: 'OpenSansCondensed', - ), - ), - leading: Icon( - Icons.person_pin, - size: 24, - color: customer.id == - customerSqfliteApi?.id - ? Colors.indigo[700] - : Colors.grey, - ), - ), - Divider( - height: 1, - color: Colors - .grey, // Warna pembatas (divider) - ), - ], - ), - color: customer.id == customerSqfliteApi?.id - ? Colors.grey.withOpacity(0.7) - : Colors.white, - ); - }, - fit: FlexFit.loose, - title: Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Pilih Customer', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold), - ), - IconButton( - icon: Icon( - Icons.close, - color: Colors.red, - ), - onPressed: () { - Navigator.pop(context); - }, - ), - ], + icon: Icon( + Icons.qr_code, + size: 30, ), - Divider(), - ], - ), - ), - ), - - items: (_valcustomer ?? []) - .where((customer) => - customer.deleted_at != true) - .where((customer) => customer.name! - .toLowerCase() - .contains(searchBoxController.text - .toLowerCase())) - .toList() ?? - [], - itemAsString: (CustomerModel customer) => - customer.name ?? - "", // Ganti dengan properti yang sesuai - selectedItem: customerSqfliteApi, - onChanged: (CustomerModel? value) { - setState(() { - customerSqfliteApi = value; - }); - }, - validator: (CustomerModel? value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - ), - ), - ), - SizedBox(height: 16), - Card( - elevation: 2, - child: Padding( - padding: const EdgeInsets.all(8), - child: FormBuilderDateTimePicker( - validator: (value) { - if (_exit_atController.text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, - ), - SizedBox(width: 5), - Text('Tanggal Peminjaman harus diisi'), - ], - ), - duration: Duration(seconds: 2), + color: Colors.white, // Warna ikon ), - ); - return null; // Return null jika ada kesalahan - } - return null; // Return null jika tidak ada kesalahan - }, - controller: _exit_atController, - name: 'tanggal_peminjaman', - inputType: InputType.date, - format: DateFormat('yyyy-MM-dd', 'id_ID'), - decoration: InputDecoration( - labelText: 'Tanggal Peminjaman', - border: OutlineInputBorder(), - suffixIcon: Icon(Icons.calendar_today), + ), + ], ), - onChanged: (DateTime? selectedDate) { - if (selectedDate != null) { - // Mengisi tanggal estimasi 7 hari ke depan - DateTime estimasiPengembalian = - selectedDate.add(Duration(days: 7)); - _est_pengembalianController.text = - DateFormat('yyyy-MM-dd') - .format(estimasiPengembalian); - } - }, - ), + ], ), ), - SizedBox(height: 16), - Card( - elevation: 2, + Divider(), + SizedBox(height: 8), + Visibility( + visible: selectedPetiList!.isEmpty == false, child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox(height: 8), Container( - margin: EdgeInsets.only( - left: 8), // Atur nilai left sesuai kebutuhan - child: Align( - alignment: Alignment.centerLeft, - child: Text( - '* Terisi otomatis 7 hari setelah tanggal peminjaman', - style: TextStyle( - fontSize: 12, - color: Colors.red, - fontStyle: FontStyle.italic), + margin: EdgeInsets.only(left: 8, bottom: 8), + child: Text( + 'List Peti:', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, ), ), ), - SizedBox(height: 8), - Padding( - padding: const EdgeInsets.all(8), - child: FormBuilderDateTimePicker( - validator: (value) { - if (_est_pengembalianController - .text.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - backgroundColor: Colors.redAccent[700], - content: Row( - children: [ - Icon( - Icons.error_outline, - color: Colors.white, + Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + side: BorderSide( + color: Colors.grey.withOpacity(0.8), + width: + 1), // Tambahkan ini untuk menambahkan border + ), + child: Container( + margin: EdgeInsets.all(8), + child: ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: selectedPetiList!.length, + itemBuilder: (BuildContext context, int i) { + return Container( + margin: EdgeInsets.only(bottom: 8), + padding: EdgeInsets.all(8), + child: Row( + children: [ + Text( + '${i + 1}.', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(width: 8), + Expanded( + child: Container( + padding: EdgeInsets.all(8.0), + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(5.0), + border: Border.all( + color: Colors.grey), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + selectedPetiList![i] + ?.fix_lot ?? + 'Belum dipilih', + style: TextStyle( + fontSize: 16, + fontFamily: + 'OpenSansCondensed'), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(left: 8), + width: 30, + height: 30, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.red, + ), + child: InkWell( + onTap: () { + setState(() { + removePeti(i); + }); + }, + child: Center( + child: Icon( + Icons.delete, + color: Colors.white, + ), + ), ), - SizedBox(width: 5), - Text( - 'Tanggal Estimasi Pengembalian harus diisi'), - ], - ), - duration: Duration(seconds: 2), + ), + ], ), ); - return null; // Return null jika ada kesalahan - } - return null; // Return null jika tidak ada kesalahan - }, - controller: _est_pengembalianController, - name: 'estimasi_pengembalian', - inputType: InputType.date, - format: DateFormat('yyyy-MM-dd', 'id_ID'), - decoration: InputDecoration( - labelText: 'Estimasi Tanggal Pengembalian', - border: OutlineInputBorder(), - suffixIcon: Icon(Icons.calendar_today), + }, ), ), ), ], ), ), - SizedBox(height: 16), - Card( - elevation: 2, - child: Padding( - padding: const EdgeInsets.all(8), - child: TextFormField( - controller: _penanggungJawabController = - TextEditingController(text: user.fullname), - decoration: InputDecoration( - labelText: 'Penanggung Jawab', - border: OutlineInputBorder(), - ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Harus diisi'; - } - return null; // Return null jika tidak ada kesalahan - }, - ), - ), - ), - SizedBox(height: 13), - Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Asal Gudang', - border: OutlineInputBorder(), - ), - hint: Text("Asal Gudang"), - value: warehouseSqfliteApi, - items: (_valwarehouse ?? []) - .where((warehouse) => - warehouse.deleted_at != true) - .map((WarehouseModel warehouse) - // _valwarehouse?.map((WarehouseModel warehouse) - { - return DropdownMenuItem( - child: Row( - children: [ - Icon( - Icons.warehouse, - color: warehouse.id == - warehouseSqfliteApi?.id - ? Colors.indigo[700] - : Colors.grey, - ), - SizedBox( - width: - 8), // Jarak antara ikon dan teks - Text( - '${warehouse.name}', - style: TextStyle( - fontSize: 16, - fontFamily: 'OpenSansCondensed', - ), - ), - ], - ), - value: warehouse, - ); - }).toList() ?? - [], - onChanged: (WarehouseModel? value) { - setState(() { - warehouseSqfliteApi = value; - }); - }, - ), - ), - ), - SizedBox(height: 13), - Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: DropdownButtonFormField( - validator: (value) { - if (value == null) { - return 'Harus diisi'; - } - return null; - }, - decoration: InputDecoration( - labelText: 'Tujuan Gudang', - border: OutlineInputBorder(), - ), - hint: Text("Tujuan Gudang"), - value: warehouseTujuanSqfliteApi, - items: (_valwarehouse ?? []) - .where((warehouseTujuan) => - warehouseTujuan.deleted_at != true) - .map((WarehouseModel warehouseTujuan) - // _valwarehouse?.map((WarehouseModel warehouse) - { - return DropdownMenuItem( - child: Row( - children: [ - Icon( - Icons.local_shipping, - color: warehouseTujuan.id == - warehouseTujuanSqfliteApi?.id - ? Colors.green[700] - : Colors.grey, - ), - SizedBox( - width: - 8), // Jarak antara ikon dan teks - Text( - '${warehouseTujuan.name}', - style: TextStyle( - fontSize: 16, - fontFamily: 'OpenSansCondensed', - ), - ), - ], - ), - value: warehouseTujuan, - ); - }).toList() ?? - [], - onChanged: (WarehouseModel? value) { - setState(() { - warehouseTujuanSqfliteApi = value; - }); - }, - ), - ), - ), ], ), ), ), ), bottomNavigationBar: BottomAppBar( - height: MediaQuery.of(context).size.height / 8, - color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + height: MediaQuery.of(context).size.height / 10, + color: Color.fromARGB(255, 5, 28, 158), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -1172,7 +1055,7 @@ class _CreatePeminjamanBarangState extends State { ), child: IconButton( onPressed: () { - Navigator.pushNamed(context, '/peminjaman-barang'); + Navigator.pop(context); }, icon: Icon(Icons.close, color: Colors.white), ), @@ -1186,25 +1069,31 @@ class _CreatePeminjamanBarangState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Container( - height: 50, // Lebar dan tinggi sesuai kebutuhan + height: 50, width: 50, decoration: BoxDecoration( shape: BoxShape.circle, - color: Colors.green, // Warna hijau untuk save + color: Colors.blue, ), child: IconButton( onPressed: () async { - if (_formKey.currentState!.validate()) { - try { - if (_exit_atController.text.isNotEmpty && - petiSqfliteApi != null && - warehouseSqfliteApi != null) { - await saveAssetData(); - } - } catch (e) { - print('Error storing data: $e'); - } + // Cek apakah ada setidaknya satu peti terpilih + if (selectedPetiList!.isEmpty || + selectedPetiList!.any((peti) => peti == null)) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + "Tidak ada peti yang dipilih", + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + backgroundColor: Colors.yellow[700], + )); + return; } + + await saveAssetData(); }, icon: Icon(Icons.save, color: Colors.white), ), diff --git a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart index 852a539..d582380 100644 --- a/lib/pages/peminjaman_barang/peminjaman_stock_page.dart +++ b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart @@ -5,6 +5,8 @@ import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:shimmer/shimmer.dart'; import 'package:siopas/models/customer_model.dart'; import 'package:siopas/models/disposal_model.dart'; import 'package:siopas/models/m_asset_status_model.dart'; @@ -20,12 +22,16 @@ import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/providers/asset_status_provider.dart'; import 'package:collection/collection.dart'; import 'package:loading_animation_widget/loading_animation_widget.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; import '../../models/condition_peti_model.dart'; +import '../../widget/loading_shimmer_show.dart'; +import '../home/controller/home_controller.dart'; import 'show.dart'; class AssetStatusPage extends StatefulWidget { - const AssetStatusPage({super.key}); + AssetStatusPage({super.key}); + final ControllerHome controllerHome = ControllerHome(); // Declare here @override State createState() => AssetStatusPageState(); @@ -57,6 +63,8 @@ class AssetStatusPageState extends State { Timer? _timer; + String _searchQuery = ''; + int _peminjamanCount = 0; bool _isLoading = false; @override @@ -65,9 +73,11 @@ class AssetStatusPageState extends State { _getUserToken(); // Mengatur _isLoading ke true sebelum tugas dimulai - setState(() { - _isLoading = true; - }); + if (mounted) { + setState(() { + _isLoading = true; + }); + } Future.wait([ warehouseListAPI(), @@ -79,11 +89,15 @@ class AssetStatusPageState extends State { datatablesTipePetiList(), datatablesCustomerList(), datatablesWarehouseList(), + _initData(), + initializeDateFormatting('id_ID', null), ]).then((_) { // Mengatur _isLoading ke false setelah semua tugas selesai - setState(() { - _isLoading = false; - }); + if (mounted) { + setState(() { + _isLoading = false; + }); + } }); // Inisialisasi _data di sini jika diperlukan @@ -99,6 +113,15 @@ class AssetStatusPageState extends State { } } + Future _initData() async { + try { + _peminjamanCount = await widget.controllerHome.getPeminjamanCount(); + } catch (error) { + print('Error fetching peminjamanCount: $error'); + } + // ... tambahkan inisialisasi lainnya + } + // Reinit atau Upload Only ------------------------------------------------------------------------ Future warehouseListAPI() async { if (mounted) { @@ -113,19 +136,6 @@ class AssetStatusPageState extends State { } } - // Future disposalListAPI() async { - // if (mounted) { - // await ControllerApi().fetchDisposalDataAPI().then((value) { - // setState(() { - // _valdisposal = (value as List) - // .map((item) => DisposalPetiModel.fromJson(item)) - // .toList(); - // loading = false; - // }); - // }); - // } - // } - Future typePetiListAPI() async { if (mounted) { await ControllerApi().fetchTipePetiDataAPI().then((value) { @@ -165,17 +175,6 @@ class AssetStatusPageState extends State { } } - // Future reinitAssetStatusApi() async { - // EasyLoading.show(status: 'Mengambil data Asset Status...'); - // List assetStatusApiData = - // await SyncronizationDataAPI().fetchAssetStatusFromApi(); - // await ControllerApi() - // .deleteAllAssetStatusDataAPI(); // Clear existing data in SQLite - // await ControllerApi() - // .addAllAssetStatusDataAPI(assetStatusApiData); // Add new data to SQLite - // EasyLoading.dismiss(); - // } - Future reinitWarehouseApi() async { EasyLoading.show(status: 'Mengambil data Warehouse...'); List warehouseApiData = @@ -237,15 +236,6 @@ class AssetStatusPageState extends State { EasyLoading.dismiss(); } - // Future reinitDisposalApi() async { - // List disposalApiData = - // await SyncronizationDataAPI().fetchDisposalFromApi(); - // await ControllerApi() - // .deleteAllDisposalDataAPI(); // Clear existing data in SQLite - // await ControllerApi() - // .addAllDisposalDataAPI(disposalApiData); // Add new data to SQLite - // } - Future fetchDataFromApiAndSync() async { EasyLoading.show(status: 'Mengambil data dari Server...'); await Future.delayed(Duration(seconds: 3)); @@ -253,13 +243,10 @@ class AssetStatusPageState extends State { try { await syncToMysql(); - // await reinitAssetStatusApi(); await reinitWarehouseApi(); await reinitPetiApi(); await reinitCustomerApi(); - // await reinitTypePetiApi(); await reinitConditionPetiApi(); - // await reinitDisposalApi(); await datatablesAssetStatusList(); EasyLoading.showSuccess('Data berhasil diperbarui'); @@ -309,502 +296,772 @@ class AssetStatusPageState extends State { if (connection) { print("Internet connection available"); } else { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("No Internet"))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Tidak ada koneksi internet"))); } }); } // Datatables ------------------------------------------------------------------------ Future datatablesAssetStatusList() async { - await Controller().fetchAssetStatusLocalController().then((value) { - setState(() { - _data = (value as List) - .map((e) => AssetStatusModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchAssetStatusLocalController().then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesPetiList() async { - await Controller().fetchPetiData().then((value) { - setState(() { - _petiData = (value as List) - .map((e) => PetiAssetModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesTipePetiList() async { - await Controller().fetchTipePetiData().then((value) { - setState(() { - _tipePetiData = (value as List) - .map((e) => TypePetiModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesCustomerList() async { - await Controller().fetchCustomerData().then((value) { - setState(() { - _customerData = (value as List) - .map((e) => CustomerModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesWarehouseList() async { - await Controller().fetchWarehouseData().then((value) { - setState(() { - _warehouseData = (value as List) - .map((e) => WarehouseModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await Controller().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } - void _loadMoreData() { - if (mounted && !_isLoading) { - setState(() { - _currentPage++; - }); - datatablesAssetStatusList(); + String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } else { + return ''; } } + List get _filteredData { + return _data != null + ? _data!.where((item) { + // Sesuaikan dengan properti yang ingin Anda cari + return item.exit_pic! + .toLowerCase() + .contains(_searchQuery.toLowerCase()) || + _formatDate(item.exit_at.toString()) + .toLowerCase() + .contains(_searchQuery.toLowerCase()) || + _formatDate(item.est_pengembalian.toString()) + .toLowerCase() + .contains(_searchQuery.toLowerCase()) || + (_petiData?.firstWhere((peti) => peti.id == item.peti_id, orElse: () => PetiAssetModel(fix_lot: ''))?.fix_lot ?? '') + .toLowerCase() + .contains(_searchQuery.toLowerCase()) || + (_customerData + ?.firstWhere( + (customer) => customer.id == item.customer_id, + orElse: () => CustomerModel(name: '')) + ?.name ?? + '') + .toLowerCase() + .contains(_searchQuery.toLowerCase()) || + (_warehouseData + ?.firstWhere( + (warehouse) => warehouse.id == item.warehouse_id, + orElse: () => WarehouseModel(name: '')) + ?.name ?? + '') + .toLowerCase() + .contains(_searchQuery.toLowerCase()); + }).toList() + : []; + } + @override Widget build(BuildContext context) { // Add this function outside the build method - void showSyncDialog(BuildContext context) { - showDialog( - context: context, - builder: (BuildContext context) { - return Dialog( - // Dialog shape and style - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - backgroundColor: Colors.grey[100], - elevation: 0, - - // Dialog content - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - // Dialog title with close button - Container( - width: double.infinity, - color: Colors.indigo[700], // Indigo background - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - "Sync Server Peminjaman", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 16.0, - ), - ), - ), - IconButton( - icon: Icon( - Icons.close, - color: Colors.white, - ), - onPressed: () { - Navigator.pop(context); // Close dialog - }, - ), - ], - ), - ), - - // Divider - Divider( - height: 1, - thickness: 1, - color: Colors.black, // Black divider - ), - - // Re-init Button - Container( - width: double.infinity, - child: TextButton( - onPressed: () { - Navigator.pop(context); // Close dialog - fetchDataFromApiAndSync(); - }, - child: Text( - "Upload + Download", - style: TextStyle( - color: Colors.black, - fontSize: 16.0, - fontFamily: 'Poppins', - ), - ), - ), - ), - - // Divider - // Divider( - // height: 1, - // thickness: 1, - // color: Colors.black, // Black divider - // ), - - // Upload Only Button - // Container( - // width: double.infinity, - // child: TextButton( - // onPressed: () { - // Navigator.pop(context); // Close dialog - // syncToMysql(); - // }, - // child: Text( - // "Upload Only", - // style: TextStyle( - // color: Colors.black, - // fontSize: 16.0, - // fontFamily: 'Poppins', - // ), - // ), - // ), - // ), - ], - ), - ); - }, - ); - } + // void showSyncDialog(BuildContext context) { + // showDialog( + // context: context, + // builder: (BuildContext context) { + // return Dialog( + // // Dialog shape and style + // shape: RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(16), + // ), + // backgroundColor: Colors.grey[100], + // elevation: 0, + + // // Dialog content + // child: Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // // Dialog title with close button + // Container( + // width: double.infinity, + // color: Colors.indigo[700], // Indigo background + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Padding( + // padding: const EdgeInsets.all(16.0), + // child: Text( + // "Sync Server Peminjaman", + // style: TextStyle( + // color: Colors.white, + // fontWeight: FontWeight.bold, + // fontSize: 16.0, + // ), + // ), + // ), + // IconButton( + // icon: Icon( + // Icons.close, + // color: Colors.white, + // ), + // onPressed: () { + // Navigator.pop(context); // Close dialog + // }, + // ), + // ], + // ), + // ), + + // // Divider + // Divider( + // height: 1, + // thickness: 1, + // color: Colors.black, // Black divider + // ), + + // // Re-init Button + // Container( + // width: double.infinity, + // child: TextButton( + // onPressed: () { + // Navigator.pop(context); // Close dialog + // fetchDataFromApiAndSync(); + // }, + // child: Text( + // "Upload + Download", + // style: TextStyle( + // color: Colors.black, + // fontSize: 16.0, + // fontFamily: 'Poppins', + // ), + // ), + // ), + // ), + // ], + // ), + // ); + // }, + // ); + // } return DefaultTabController( length: 1, child: Scaffold( - appBar: AppBar( - backgroundColor: Colors.indigo[700], - elevation: 0, - title: Text('Data Peminjaman Peti', - style: TextStyle( - fontSize: 16, - )), - actions: [ - IconButton( - icon: Icon(Icons.backup), - onPressed: () async { - if (await SyncronizationPeminjamanData.isInternet()) { - // Display custom dialog when the IconButton is pressed - showSyncDialog(context); - } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("No internet connection")), - ); - } + appBar: appBarPeminjaman(context), + body: _isLoading + ? Column( + children: [ + // shimmerSearch(), + Expanded( + child: ListView.builder( + itemCount: + 4, // Set the number of shimmer cards based on your data count + itemBuilder: (context, index) { + return ShimmerLoadingAssetStatusCard(); + }, + ), + ), + ], + ) + : bodyPeminjaman(), + bottomNavigationBar: bottomAppBar(context), + ), + ); + } + + BottomAppBar bottomAppBar(BuildContext context) { + return BottomAppBar( + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Container( + height: 65.0, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + customBorder: CircleBorder(), + onTap: () { + // Aksi ketika ikon diklik + Navigator.pushNamed(context, '/peminjaman-barang/create'); }, + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.greenAccent[700], + ), + child: Icon( + Icons.add, + size: 30, + color: Colors.white, + ), + ), ), ], - leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushNamed(context, '/home'); - }, - ), - bottom: TabBar( - indicator: BoxDecoration(color: Color.fromARGB(255, 50, 39, 122)), - tabs: [ - Tab(text: 'Peminjaman Hari ini'), + ), + ), + ); + } + + Column bodyPeminjaman() { + return Column( + children: [ + // Container( + // margin: EdgeInsets.only(top: 7, bottom: 7), + // child: Padding( + // padding: const EdgeInsets.symmetric(horizontal: 16), + // child: TextField( + // style: TextStyle(fontSize: 16), + // decoration: InputDecoration( + // hintText: 'Masukkan data pencarian...', + // prefixIcon: Icon(Icons.search), + // border: InputBorder.none, + // enabledBorder: OutlineInputBorder( + // borderRadius: BorderRadius.circular(12), + // borderSide: BorderSide(color: Colors.grey, width: 1.0), + // ), + // focusedBorder: OutlineInputBorder( + // borderRadius: BorderRadius.circular(12), + // borderSide: BorderSide(color: Colors.indigo, width: 1.0), + // ), + // contentPadding: EdgeInsets.all(16), + // labelStyle: TextStyle( + // color: Colors.grey, + // fontSize: 16, + // ), + // hintStyle: TextStyle( + // color: Colors.grey, + // fontSize: 16, + // ), + // prefixIconConstraints: BoxConstraints( + // minWidth: 40, + // ), + // suffixIcon: _searchQuery.isNotEmpty + // ? IconButton( + // icon: Icon(Icons.clear), + // onPressed: () { + // setState(() { + // _searchQuery = ''; + // }); + // }, + // ) + // : null, + // ), + // onChanged: (value) { + // setState(() { + // _searchQuery = value; + // }); + // }, + // ), + // ), + // ), + Expanded( + child: TabBarView( + children: [ + SingleChildScrollView( + child: Column( + children: _filteredData.isNotEmpty + ? _filteredData.asMap().entries.map((entry) { + final index = entry.key + 1; + final item = entry.value; + + return AssetStatusCard( + assetStatus: item, + petiData: _petiData ?? [], + tipePetiData: _tipePetiData ?? [], + customerData: _customerData ?? [], + warehouseData: _warehouseData ?? [], + index: index, + ); + }).toList() + // : [Text('No results')], + : [ + Center( + child: Column( + children: [ + Image.asset( + 'assets/item/empty.png', + width: 250, // Set the width as needed + height: 250, // Set the height as needed + ), + Text( + 'Tidak ada data ditemukan', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ), ], ), ), - body: _isLoading - ? Center( - child: LoadingAnimationWidget.staggeredDotsWave( - color: Colors.indigo, - size: 40, - ), - ) - : TabBarView( + ], + ); + } + + AppBar appBarPeminjaman(BuildContext context) { + Future peminjamanCount = widget.controllerHome.getPeminjamanCount(); + + return AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Data Peminjaman Peti', + style: TextStyle( + fontSize: 16, + )), + // actions: [ + // IconButton( + // icon: Icon(Icons.backup), + // onPressed: () async { + // if (await SyncronizationPeminjamanData.isInternet()) { + // // Display custom dialog when the IconButton is pressed + // showSyncDialog(context); + // } else { + // ScaffoldMessenger.of(context).showSnackBar( + // SnackBar(content: Text("Tidak ada koneksi internet")), + // ); + // } + // }, + // ), + // ], + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + ), + bottom: TabBar( + indicator: BoxDecoration( + color: Color.fromARGB(255, 255, 165, 9), + ), + tabs: [ + Tab( + height: 65, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(0), + border: Border.all(color: Colors.grey, width: 1.0), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - SingleChildScrollView( - child: Column( - children: [ - SizedBox( - width: double.infinity, - child: PaginatedDataTable( - // header: Text('Searching'), // Removed const - rowsPerPage: _pageSize, - availableRowsPerPage: [10, 25, 50], // Removed const - onRowsPerPageChanged: (value) { - setState(() { - _pageSize = value!; - }); - }, - columns: [ - DataColumn(label: Text('No')), - DataColumn(label: Text('')), - DataColumn(label: Text('Kode Peti')), - DataColumn(label: Text('Nama Customer')), - DataColumn(label: Text('Tgl Peminjaman')), - DataColumn(label: Text('Est Peminjaman')), - DataColumn(label: Text('PJ Peminjaman')), - DataColumn(label: Text('Asal Gudang')), - DataColumn(label: Text('Tujuan Gudang')), - ], - source: _DataSourceLokal( - data: _data!, - context: context, - petiData: _petiData != null ? _petiData : [], - tipePetiData: - _tipePetiData != null ? _tipePetiData : [], - customerData: - _customerData != null ? _customerData : [], - warehouseData: - _warehouseData != null ? _warehouseData : [], - ), - ), + Expanded( + child: TextField( + style: TextStyle(fontSize: 18), + decoration: InputDecoration( + hintText: 'Masukkan data pencarian...', + prefixIcon: Icon(Icons.search), + border: InputBorder.none, + contentPadding: EdgeInsets.all(10), + labelStyle: TextStyle( + color: Colors.grey, + fontSize: 12, ), - ], + hintStyle: TextStyle( + color: Colors.grey, + fontSize: 12, + ), + // suffixIcon: _searchQuery.isNotEmpty + // ? IconButton( + // icon: Icon(Icons.clear), + // onPressed: () { + // setState(() { + // // _searchQuery = null; // Mengganti dengan null + // }); + // }, + // ) + // : null, + ), + onChanged: (value) { + setState(() { + _searchQuery = value.isNotEmpty + ? value + : ''; // Memperbarui dengan null jika value kosong + }); + }, ), ), + Text( + 'Total: $_peminjamanCount', + style: TextStyle(color: Colors.black), + ), ], ), - bottomNavigationBar: BottomAppBar( - color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang - child: Container( - height: 65.0, - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - InkWell( - customBorder: CircleBorder(), - onTap: () { - // Aksi ketika ikon diklik - Navigator.pushNamed(context, '/peminjaman-barang/create'); - }, - child: Container( - width: 45, - height: 45, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Colors.greenAccent[700], - ), - child: Icon( - Icons.add, - size: 30, - color: Colors.white, - ), - ), - ), - ], ), ), - ), + ], ), ); } } -class _DataSourceLokal extends DataTableSource { - final List data; - List? petiData; - List? tipePetiData; - List? customerData; - List? warehouseData; - final BuildContext context; +class AssetStatusCard extends StatelessWidget { + final AssetStatusModel assetStatus; + final List petiData; + final List tipePetiData; + final List customerData; + final List warehouseData; + final int index; // Tambahkan parameter nomor urutan - _DataSourceLokal({ - required this.data, + AssetStatusCard({ + required this.assetStatus, required this.petiData, required this.tipePetiData, required this.customerData, required this.warehouseData, - required this.context, + required this.index, // Inisialisasi parameter nomor urutan }); + @override - DataRow? getRow(int index) { - if (index >= data.length) { - return null; - } + Widget build(BuildContext context) { + PetiAssetModel? petiSqfliteApi = petiData.firstWhereOrNull( + (peti) => peti.id == assetStatus.peti_id, + ); + + TypePetiModel? tipePetiSqfliteApi = tipePetiData.firstWhereOrNull( + (tipePeti) => tipePeti.id == petiSqfliteApi?.tipe_peti_id, + ); + + CustomerModel? customerSqfliteApi = customerData.firstWhereOrNull( + (customer) => customer.id == assetStatus.customer_id, + ); + + WarehouseModel? warehouseSqfliteApi = warehouseData.firstWhereOrNull( + (warehouse) => warehouse.id == assetStatus.warehouse_id, + ); - data.sort((a, b) { - if (a.created_at == null && b.created_at == null) { - return 0; // Both dates are null, consider them equal - } else if (a.created_at == null) { - return 1; // Null is considered greater than non-null - } else if (b.created_at == null) { - return -1; // Non-null is considered smaller than null + // WarehouseModel? warehouseTujuanSqfliteApi = warehouseData.firstWhereOrNull( + // (warehouse) => warehouse.id == assetStatus.exit_warehouse, + // ); + + String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; } else { - return b.created_at!.compareTo(a.created_at!); // Compare non-null dates + return ''; } - }); - - final item = data[index]; - - // Menemukan data peti yang sesuai dengan asset - PetiAssetModel? petiSqfliteApi; - if (item.peti_id != null) { - petiSqfliteApi = petiData!.firstWhere( - (peti) => peti.id == item.peti_id, - orElse: () => PetiAssetModel( - id: null, - tipe_peti_id: null, - warna: 'null', - packing_no: null, - customer_id: null, - warehouse_id: null, - kondisipeti_id: null, - jumlah: null, - date_pembuatan: DateTime.now(), - created_by: 'null', - updated_by: 'null', - fix_lot: '', - ), - ); } - TypePetiModel? tipePetiSqfliteApi; - if (petiSqfliteApi != null && petiSqfliteApi.tipe_peti_id != null) { - tipePetiSqfliteApi = tipePetiData?.firstWhere( - (tipePeti) => tipePeti.id == petiSqfliteApi?.tipe_peti_id, - orElse: () => TypePetiModel( - id: null, - type: 'null', - size_peti: 'null', - description: 'null', - created_by: 'null', - updated_by: 'null', - ), - ); + Future _deletePeminjaman() async { + try { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + await Controller().deletePeminjamanById(assetStatus.id.toString()); + // Navigasi kembali ke halaman sebelumnya atau halaman yang sesuai + Navigator.pushReplacementNamed(context, '/peminjaman-barang'); + } catch (e) { + // Tangani kesalahan jika terjadi + print('Gagal menghapus peminjaman: $e'); + } } - CustomerModel? customerSqfliteApi; - if (petiSqfliteApi != null && petiSqfliteApi.customer_id != null) { - customerSqfliteApi = customerData?.firstWhere( - (customer) => customer.id == item.customer_id, - orElse: () => CustomerModel( - id: null, - name: 'null', - code_customer: 'null', - lot_no: 'null', - created_by: 'null', - updated_by: 'null', - ), + Future _showDeleteConfirmationDialog() async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon( + Icons.info, + color: Colors.blue, + ), + SizedBox(width: 8), + Text( + 'Konfirmasi Hapus', + style: TextStyle( + fontSize: 18, + ), + ), + ], + ), + IconButton( + icon: Icon( + Icons.close, + color: Colors.black54, + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ), + content: SingleChildScrollView( + child: ListBody( + children: [ + Text( + 'Anda yakin ingin menghapus peminjaman ini? ${petiSqfliteApi!.fix_lot.toString()}', + style: TextStyle( + fontSize: 16, + ), + ), + ], + ), + ), + actions: [ + Container( + margin: EdgeInsets.only(right: 3.0), + child: ElevatedButton( + child: Text('Hapus'), + onPressed: () { + // Panggil fungsi untuk menghapus peminjaman berdasarkan ID + _deletePeminjaman(); + // Navigator.pushNamed(context, '/peminjaman-barang'); + EasyLoading.showSuccess( + 'Berhasil menghapus data peminjaman'); + }, + style: ElevatedButton.styleFrom( + primary: Colors.red, + ), + ), + ), + ], + ); + }, ); } - WarehouseModel? warehouseSqfliteApi; - if (item.warehouse_id != null) { - warehouseSqfliteApi = warehouseData?.firstWhere( - (warehouse) => warehouse.id == item.warehouse_id, - orElse: () => WarehouseModel( - id: null, - name: 'null', - created_by: 'null', - updated_by: 'null', + return Slidable( + key: Key(assetStatus.id.toString()), + endActionPane: ActionPane( + motion: ScrollMotion(), + children: [ + SlidableAction( + onPressed: (context) { + _showDeleteConfirmationDialog(); + }, + backgroundColor: Color(0xFFFE4A49), + foregroundColor: Colors.white, + icon: Icons.delete, + label: 'Hapus', + ), + ], + ), + child: GestureDetector( + onTap: () { + // Tindakan yang dilakukan saat card diklik + if (assetStatus != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailPeminjamanBarangPage( + peminjamanId: assetStatus.id.toString(), + ), + ), + ); + } + }, + child: Card( + color: Colors.white60, + elevation: 0.0, + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 1.0), + ), + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + bottom: 8.0, + left: 16.0, + right: 16.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAvatarAndIndex(index), + Divider(), + _buildInfoRow( + 'Nama Peminjam:', + '${customerSqfliteApi?.name ?? '-'}', + 'PIC:', + '${assetStatus.exit_pic ?? '-'}', + 13), + _buildInfoRow( + 'Tanggal Peminjaman:', + '${_formatDate(assetStatus.exit_at.toString())}', + 'Estimasi Pengembalian:', + '${_formatDate(assetStatus.est_pengembalian.toString())}', + 13), + _buildInfoRow('Tujuan Gudang:', + '${warehouseSqfliteApi?.name ?? '-'}', '', '', 13), + ], + ), + ), ), - ); - } - - WarehouseModel? warehouseTujuanSqfliteApi; - warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( - (warehouse) => warehouse.id == item.exit_warehouse, + ), ); + } - return DataRow(cells: [ - DataCell( - Text( - (index + 1).toString(), - ), - ), - DataCell( - GestureDetector( - onTap: () { - if (item.id != null) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => DetailPeminjamanBarangPage( - peminjamanId: item.id.toString(), + Widget _buildAvatarAndIndex(int index) { + PetiAssetModel? petiSqfliteApi = petiData.firstWhereOrNull( + (peti) => peti.id == assetStatus.peti_id, + ); + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAvatar(index), + Expanded( + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + top: 8.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '${petiSqfliteApi?.fix_lot ?? '-'}', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 14.5, ), ), - ); - - print('asset id: ${item.id}'); - } - }, - child: Icon(Icons.article, - size: 40, - color: Colors.indigo[700]), // Ganti ikon sesuai kebutuhan - ), - ), - DataCell( - Text( - petiSqfliteApi != null && petiSqfliteApi.fix_lot != null - ? petiSqfliteApi!.fix_lot.toString() - : '-', - ), - ), - DataCell( - Text( - customerSqfliteApi != null && customerSqfliteApi.name != null - ? customerSqfliteApi!.name.toString() - : '-', - ), - ), - DataCell( - Text( - item.exit_at != null - ? DateFormat('dd-MM-yyyy').format(item.exit_at!) - : '-', - ), - ), - DataCell( - Text( - item.est_pengembalian != null - ? DateFormat('dd-MM-yyyy').format(item.est_pengembalian!) - : '-', + ], + ), + ), ), - ), - DataCell( - Text( - item.exit_pic != null ? item.exit_pic.toString() : '-', + ], + ); + } + + Widget _buildAvatar(int index) { + return Container( + child: CircleAvatar( + radius: 11, + backgroundColor: Colors.indigo[700], + child: Text( + '$index', + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 13, + color: Colors.white, + ), ), ), - DataCell( - Text( - warehouseSqfliteApi != null && warehouseSqfliteApi.name != null - ? warehouseSqfliteApi.name.toString() - : '-', + ); + } + + Widget _buildInfoRow(String title1, String content1, String title2, + String content2, double fontSize) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title1, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: fontSize, + ), + ), + SizedBox(height: 3), + Text( + content1, + style: TextStyle( + fontSize: fontSize - + 0.5, // Mengurangkan ukuran font agar cocok dengan judul + ), + ), + ], + ), ), - ), - DataCell( - Text( - warehouseTujuanSqfliteApi != null && - warehouseTujuanSqfliteApi.name != null - ? warehouseTujuanSqfliteApi.name.toString() - : '-', + SizedBox(width: 10), // Memberi jarak antara dua kolom + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title2, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: fontSize, + ), + ), + SizedBox(height: 3), + Text( + content2, + style: TextStyle( + fontSize: fontSize - + 0.5, // Mengurangkan ukuran font agar cocok dengan judul + ), + ), + ], + ), ), - ), - ]); + ], + ); } - - @override - bool get isRowCountApproximate => false; - - @override - int get rowCount => data.length; - - @override - int get selectedRowCount => 0; } diff --git a/lib/pages/peminjaman_barang/show.dart b/lib/pages/peminjaman_barang/show.dart index d391e85..00f2691 100644 --- a/lib/pages/peminjaman_barang/show.dart +++ b/lib/pages/peminjaman_barang/show.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; +import 'package:shimmer/shimmer.dart'; import 'package:siopas/models/asset_status_model.dart'; import 'package:siopas/models/customer_model.dart'; import 'package:siopas/models/m_asset_status_model.dart'; @@ -10,6 +11,7 @@ import 'package:collection/collection.dart'; import '../../models/warehouse_mode.dart'; import '../../services/controllerApi.dart'; +import '../../widget/loading_shimmer_show.dart'; class DetailPeminjamanBarangPage extends StatefulWidget { final String peminjamanId; @@ -31,19 +33,38 @@ class _DetailPeminjamanBarangPageState List? customerData; List? warehouseData; - bool loading = true; + late Future _dataFuture; + bool loading = true; // Atur loading ke true pada awalnya @override void initState() { super.initState(); - getPeminjamanIdData(); - customerListAPI(); - petiListAPI(); - warehouseListAPI(); + + // Set loading ke true pada awalnya + if (mounted) { + if (mounted) { + setState(() { + loading = false; + }); + } + } + + _dataFuture = fetchData(); + } + + Future fetchData() async { + await getPeminjamanIdData(); + await customerListAPI(); + await petiListAPI(); + await warehouseListAPI(); initializeDateFormatting('id_ID', null); - setState(() { - loading = false; - }); + + // Tandai bahwa proses loading telah selesai + if (mounted) { + setState(() { + loading = false; + }); + } } Future customerListAPI() async { @@ -91,8 +112,9 @@ class _DetailPeminjamanBarangPageState peminjamanInfo = peminjamans.firstWhereOrNull( (peminjaman) => peminjaman.id.toString() == widget.peminjamanId, ); - - setState(() {}); + if (mounted) { + setState(() {}); + } } String _formatDate(String? date) { @@ -134,10 +156,10 @@ class _DetailPeminjamanBarangPageState warehouseSqfliteApi = warehouseData?.firstWhereOrNull( (warehouse) => warehouse.id == peminjamanInfo!.warehouse_id, ); - WarehouseModel? warehouseTujuanSqfliteApi; - warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( - (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, - ); + // WarehouseModel? warehouseTujuanSqfliteApi; + // warehouseTujuanSqfliteApi = warehouseData?.firstWhereOrNull( + // (warehouse) => warehouse.id == peminjamanInfo!.exit_warehouse, + // ); Future _showDeleteConfirmationDialog() async { return showDialog( @@ -224,10 +246,10 @@ class _DetailPeminjamanBarangPageState ), ), leading: IconButton( - icon: Icon(Icons.arrow_back, color: Colors.white), onPressed: () { - Navigator.pushNamed(context, '/peminjaman-barang'); + Navigator.pop(context); }, + icon: Icon(Icons.arrow_back), ), actions: [ IconButton( @@ -238,109 +260,123 @@ class _DetailPeminjamanBarangPageState ), ], ), - body: Padding( - padding: EdgeInsets.all(16.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), - elevation: 5, - child: Column( - children: [ - Card( + body: FutureBuilder( + future: _dataFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return ShimmerShow(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return Padding( + padding: EdgeInsets.all(16.0), + child: Card( shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.vertical(top: Radius.circular(15.0)), + borderRadius: BorderRadius.circular(15.0), ), - elevation: 0, - margin: EdgeInsets.all(0), - color: Colors.indigo[700], - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.article, size: 30, color: Colors.white), - SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'ID:', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - SizedBox(height: 5), - Text( - petiSqfliteApi != null && - petiSqfliteApi.fix_lot != null - ? petiSqfliteApi!.fix_lot.toString() - : '-', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.white, + elevation: 5, + child: Column( + children: [ + Card( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.vertical(top: Radius.circular(15.0)), + ), + elevation: 0, + margin: EdgeInsets.all(0), + color: Colors.indigo[700], + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.article, + size: 30, color: Colors.white), + SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ID:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + SizedBox(height: 5), + Text( + petiSqfliteApi != null && + petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], ), - ), - ], - ), - ], + ], + ), + ], + ), + ), + ), + SizedBox(height: 10), + if (peminjamanInfo != null) ...[ + _buildDetailItem( + 'Kode Peti', + petiSqfliteApi != null && petiSqfliteApi.fix_lot != null + ? petiSqfliteApi!.fix_lot.toString() + : '-', ), + Divider(thickness: 1), + _buildDetailItem( + 'Nama Customer', + customerSqfliteApi != null && + customerSqfliteApi.name != null + ? customerSqfliteApi!.name.toString() + : '-', + ), + Divider(thickness: 1), + _buildDetailItem('Tgl Peminjaman', + _formatDate(peminjamanInfo!.exit_at.toString())), + Divider(thickness: 1), + _buildDetailItem( + 'Est Peminjaman', + _formatDate( + peminjamanInfo!.est_pengembalian.toString())), + Divider(thickness: 1), + _buildDetailItem( + 'PJ Peminjaman', peminjamanInfo!.exit_pic.toString()), + Divider(thickness: 1), + _buildDetailItem( + ' Gudang', + warehouseSqfliteApi != null && + warehouseSqfliteApi.name != null + ? warehouseSqfliteApi!.name.toString() + : '-'), + + Divider(thickness: 1), + _buildDetailItem( + 'PIC', + peminjamanInfo!.exit_pic != null + ? peminjamanInfo!.exit_pic.toString() + : '-'), + + Divider(thickness: 1), + // ... tambahkan data lainnya sesuai kebutuhan ], - ), + ], ), ), - SizedBox(height: 10), - if (peminjamanInfo != null) ...[ - _buildDetailItem( - 'Kode Peti', - petiSqfliteApi != null && petiSqfliteApi.fix_lot != null - ? petiSqfliteApi!.fix_lot.toString() - : '-', - ), - Divider(thickness: 1), - _buildDetailItem( - 'Nama Customer', - customerSqfliteApi != null && customerSqfliteApi.name != null - ? customerSqfliteApi!.name.toString() - : '-', - ), - Divider(thickness: 1), - _buildDetailItem('Tgl Peminjaman', - _formatDate(peminjamanInfo!.exit_at.toString())), - Divider(thickness: 1), - _buildDetailItem('Est Peminjaman', - _formatDate(peminjamanInfo!.est_pengembalian.toString())), - Divider(thickness: 1), - _buildDetailItem( - 'PJ Peminjaman', peminjamanInfo!.exit_pic.toString()), - Divider(thickness: 1), - _buildDetailItem( - 'Asal Gudang', - // peminjamanInfo!.exit_warehouse.toString()), - warehouseSqfliteApi != null && - warehouseSqfliteApi.name != null - ? warehouseSqfliteApi!.name.toString() - : '-'), - Divider(thickness: 1), - _buildDetailItem( - 'Tujuan Gudang', - // peminjamanInfo!.exit_warehouse.toString()), - warehouseTujuanSqfliteApi != null && - warehouseTujuanSqfliteApi.name != null - ? warehouseTujuanSqfliteApi!.name.toString() - : '-'), - Divider(thickness: 1), - // ... tambahkan data lainnya sesuai kebutuhan - ], - ], - ), - ), + ); + } + }, ), ); } diff --git a/lib/pages/pengembalian_barang/edit.dart b/lib/pages/pengembalian_barang/edit.dart index 68e4130..eb5100c 100644 --- a/lib/pages/pengembalian_barang/edit.dart +++ b/lib/pages/pengembalian_barang/edit.dart @@ -90,9 +90,11 @@ class _CreatePengembalianBarangPageState kondisiPetiListAPI(); initializeDateFormatting('id_ID', null); - setState(() { - loading = false; // Mengatur loading ke false setelah tugas selesai - }); + if (mounted) { + setState(() { + loading = false; // Mengatur loading ke false setelah tugas selesai + }); + } } void _getUserToken() async { @@ -179,67 +181,98 @@ class _CreatePengembalianBarangPageState (scanData) { if (!scanned) { try { - setState(() { - result = scanData; - List lines = result!.code!.split('\n'); - String idPeti = ''; - String idWarehouse = ''; - - for (String line in lines) { - if (line.contains(';')) { - List values = line.split(';'); - if (values.length >= 3) { - idPeti = values[1]; - idWarehouse = values[2]; - break; + if (mounted) { + setState(() { + result = scanData; + List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + + for (String line in lines) { + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; + } } } - } - int? petiId = int.tryParse(idPeti); - int? warehouseId = int.tryParse(idWarehouse); - // AuthProvider authProvider = Provider.of(context, listen: false); - // UserModel user = authProvider.user; - - // Dalam fungsi yang menangani pemindaian QR code - // Dalam fungsi yang menangani pemindaian QR code - if (petiId != null && warehouseId != null) { - // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan - PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( - (peti) => - peti.id == petiId && - peti.deleted_at != true && - peti.status == 'AKTIF', - ); - - if (allowedPeti != null) { - setState(() { - isQRCodeScanned = true; - // Mengisi _filteredPetiList untuk dropdown hasil QR Code - _filteredPetiList = [ - _valpeti!.firstWhere((peti) => peti.id == allowedPeti.id) - ]; + int? petiId = int.tryParse(idPeti); + int? warehouseId = int.tryParse(idWarehouse); + // AuthProvider authProvider = Provider.of(context, listen: false); + // UserModel user = authProvider.user; + + // Dalam fungsi yang menangani pemindaian QR code + // Dalam fungsi yang menangani pemindaian QR code + if (petiId != null && warehouseId != null) { + // Check apakah peti dengan warehouse_id yang sesuai ada dalam daftar yang diizinkan + PetiAssetModel? allowedPeti = _valpeti?.firstWhereOrNull( + (peti) => + peti.id == petiId && + peti.deleted_at != true && + peti.status == 'AKTIF', + ); - petiSqfliteApi = allowedPeti; - }); + if (allowedPeti != null) { + setState(() { + isQRCodeScanned = true; + // Mengisi _filteredPetiList untuk dropdown hasil QR Code + _filteredPetiList = [ + _valpeti! + .firstWhere((peti) => peti.id == allowedPeti.id) + ]; + + petiSqfliteApi = allowedPeti; + }); + } else { + // Tampilkan pesan error jika data tidak sesuai dengan hak akses + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), + ), + backgroundColor: Colors.red[700], + action: SnackBarAction( + label: 'Tutup', + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentSnackBar(); + }, + ), + ), + ); + setState(() { + isQRCodeScanned = false; + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } } else { - // Tampilkan pesan error jika data tidak sesuai dengan hak akses + // Tampilkan pesan error jika nilai yang dipindai tidak sesuai ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - 'Data Peti tidak ditemukan atau tidak sesuai dengan hak akses.', - style: TextStyle( - color: Colors.white, - fontSize: 12, - ), - ), - backgroundColor: Colors.red[700], - action: SnackBarAction( - label: 'Tutup', - onPressed: () { - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - }, + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, + ), + SizedBox(width: 8), + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), + ), + ], ), + backgroundColor: Colors.yellow[700], ), ); setState(() { @@ -248,38 +281,10 @@ class _CreatePengembalianBarangPageState warehouseSqfliteApi = null; }); } - } else { - // Tampilkan pesan error jika nilai yang dipindai tidak sesuai - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Row( - children: [ - Icon( - Icons.warning, - color: Colors.black, - ), - SizedBox(width: 8), - Text( - 'Nilai QR Code tidak sesuai dengan yang diharapkan.', - style: TextStyle( - color: Colors.black, - fontSize: 12, - ), - ), - ], - ), - backgroundColor: Colors.yellow[700], - ), - ); - setState(() { - isQRCodeScanned = false; - petiSqfliteApi = null; - warehouseSqfliteApi = null; - }); - } - scanned = true; - }); + scanned = true; + }); + } controller.stopCamera(); @@ -292,10 +297,12 @@ class _CreatePengembalianBarangPageState controller.stopCamera(); // Reset nilai dropdown Peti dan Warehouse - setState(() { - petiSqfliteApi = null; - warehouseSqfliteApi = null; - }); + if (mounted) { + setState(() { + petiSqfliteApi = null; + warehouseSqfliteApi = null; + }); + } print('Error scanning QR Code: $e'); ScaffoldMessenger.of(context).showSnackBar( @@ -521,16 +528,18 @@ class _CreatePengembalianBarangPageState selectedItem: petiSqfliteApi, onChanged: (PetiAssetModel? value) { - setState(() { - petiSqfliteApi = value; - if (value != null) { - // Perbarui _unrestrictedPetiList sesuai pemilihan manual - _unrestrictedPetiList = [ - _valpeti!.firstWhere( - (peti) => peti.id == value.id) - ]; - } - }); + if (mounted) { + setState(() { + petiSqfliteApi = value; + if (value != null) { + // Perbarui _unrestrictedPetiList sesuai pemilihan manual + _unrestrictedPetiList = [ + _valpeti!.firstWhere( + (peti) => peti.id == value.id) + ]; + } + }); + } }, validator: (PetiAssetModel? value) { if (value == null) { @@ -711,9 +720,11 @@ class _CreatePengembalianBarangPageState }).toList() ?? [], onChanged: (WarehouseModel? value) { - setState(() { - warehouseSqfliteApi = value; - }); + if (mounted) { + setState(() { + warehouseSqfliteApi = value; + }); + } }, ), ), @@ -769,9 +780,11 @@ class _CreatePengembalianBarangPageState }).toList() ?? [], onChanged: (ConditionPetiModel? value) { - setState(() { - conditionPetiSqfliteApi = value; - }); + if (mounted) { + setState(() { + conditionPetiSqfliteApi = value; + }); + } }, ), ), diff --git a/lib/pages/pengembalian_barang/index.dart b/lib/pages/pengembalian_barang/index.dart index dc2f2c8..da30bc1 100644 --- a/lib/pages/pengembalian_barang/index.dart +++ b/lib/pages/pengembalian_barang/index.dart @@ -69,9 +69,11 @@ class PengembalianBarangPageState extends State { _getUserToken(); // Set _isLoading ke true sebelum memulai tugas - setState(() { - _isLoading = true; - }); + if (mounted) { + setState(() { + _isLoading = true; + }); + } Future.wait([ warehouseListAPI(), @@ -88,9 +90,11 @@ class PengembalianBarangPageState extends State { datatablesConditionList(), ]).then((_) { // Set _isLoading ke false setelah semua tugas selesai - setState(() { - _isLoading = false; - }); + if (mounted) { + setState(() { + _isLoading = false; + }); + } }); // Inisialisasi _data di sini jika diperlukan @@ -313,79 +317,91 @@ class PengembalianBarangPageState extends State { if (connection) { print("Internet connection available"); } else { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("No Internet"))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Tidak ada koneksi internet"))); } }); } // Datatables ------------------------------------------------------------------------ Future datatablesPengembalianList() async { - await ControllerPengembalian() - .fetchPengembalianLocalController() - .then((value) { - setState(() { - _data = (value as List) - .map((e) => AssetStatusModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian() + .fetchPengembalianLocalController() + .then((value) { + setState(() { + _data = (value as List) + .map((e) => AssetStatusModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesPetiList() async { - await ControllerPengembalian().fetchPetiData().then((value) { - setState(() { - _petiData = (value as List) - .map((e) => PetiAssetModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian().fetchPetiData().then((value) { + setState(() { + _petiData = (value as List) + .map((e) => PetiAssetModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesTipePetiList() async { - await ControllerPengembalian().fetchTipePetiData().then((value) { - setState(() { - _tipePetiData = (value as List) - .map((e) => TypePetiModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian().fetchTipePetiData().then((value) { + setState(() { + _tipePetiData = (value as List) + .map((e) => TypePetiModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesCustomerList() async { - await ControllerPengembalian().fetchCustomerData().then((value) { - setState(() { - _customerData = (value as List) - .map((e) => CustomerModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian().fetchCustomerData().then((value) { + setState(() { + _customerData = (value as List) + .map((e) => CustomerModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesWarehouseList() async { - await ControllerPengembalian().fetchWarehouseData().then((value) { - setState(() { - _warehouseData = (value as List) - .map((e) => WarehouseModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian().fetchWarehouseData().then((value) { + setState(() { + _warehouseData = (value as List) + .map((e) => WarehouseModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } Future datatablesConditionList() async { - await ControllerPengembalian().fetchConditionData().then((value) { - setState(() { - _conditionData = (value as List) - .map((e) => ConditionPetiModel.fromJson(e)) - .toList(); - loading = false; + if (mounted) { + await ControllerPengembalian().fetchConditionData().then((value) { + setState(() { + _conditionData = (value as List) + .map((e) => ConditionPetiModel.fromJson(e)) + .toList(); + loading = false; + }); }); - }); + } } void _loadMoreData() { @@ -524,7 +540,7 @@ class PengembalianBarangPageState extends State { showSyncDialog(context); } else { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("No internet connection")), + SnackBar(content: Text("Tidak ada koneksi internet")), ); } }, @@ -562,9 +578,11 @@ class PengembalianBarangPageState extends State { rowsPerPage: _pageSize, availableRowsPerPage: [10, 25, 50], // Removed const onRowsPerPageChanged: (value) { - setState(() { - _pageSize = value!; - }); + if (mounted) { + setState(() { + _pageSize = value!; + }); + } }, columns: [ DataColumn(label: Text('No')), diff --git a/lib/pages/pengembalian_barang/show.dart b/lib/pages/pengembalian_barang/show.dart index 0dc076f..4366693 100644 --- a/lib/pages/pengembalian_barang/show.dart +++ b/lib/pages/pengembalian_barang/show.dart @@ -48,12 +48,14 @@ class _DetailPengembalianBarangPageState initializeDateFormatting('id_ID', null); // Delay sejenak sebelum memanggil EasyLoading.dismiss() - Future.delayed(Duration(seconds: 1), () { - setState(() { - loading = false; // Mengatur loading ke false setelah tugas selesai + if (mounted) { + Future.delayed(Duration(seconds: 1), () { + setState(() { + loading = false; // Mengatur loading ke false setelah tugas selesai + }); + EasyLoading.dismiss(); }); - EasyLoading.dismiss(); - }); + } } Future customerListAPI() async { @@ -115,7 +117,9 @@ class _DetailPengembalianBarangPageState (pengembalian) => pengembalian.id.toString() == widget.pengembalianId, ); - setState(() {}); + if (mounted) { + setState(() {}); + } } String _formatDate(String? date) { @@ -351,6 +355,12 @@ class _DetailPengembalianBarangPageState : '-', ), Divider(thickness: 1), + _buildDetailItem( + 'PIC', + pengembalianInfo!.enter_pic != null + ? pengembalianInfo!.enter_pic.toString() + : '-'), + Divider(thickness: 1), // ... tambahkan data lainnya sesuai kebutuhan ], ], diff --git a/lib/pages/sign_in_page.dart b/lib/pages/sign_in_page.dart index 4750b03..a0cbcdb 100644 --- a/lib/pages/sign_in_page.dart +++ b/lib/pages/sign_in_page.dart @@ -172,9 +172,13 @@ class __FormContentState extends State<_FormContent> { // final String roleId = 'A5C7B207-1A1C-43B8-89BF-222222222222'; print('token dapat login: ${user.token}'); - if (user.role_id == 2) { + if (user != null && user.role_id == 2) { print('Berhasil login HALAMAN USER'); - Navigator.pushNamed(context, '/home'); + if (context != null) { + Navigator.pushReplacementNamed(context, '/home'); + } else { + print('Context is null'); + } } else { print('Tidak ada informasi peran (roles) yang tersedia'); } @@ -239,6 +243,7 @@ class __FormContentState extends State<_FormContent> { prefixIcon: Icon(Icons.email_outlined), border: OutlineInputBorder(), ), + keyboardType: TextInputType.emailAddress, ), _gap(), TextFormField( diff --git a/lib/pages/transfer_peti/index.dart b/lib/pages/transfer_peti/index.dart index 29ff830..8f83f93 100644 --- a/lib/pages/transfer_peti/index.dart +++ b/lib/pages/transfer_peti/index.dart @@ -299,8 +299,8 @@ class TransferPetiPageState extends State { if (connection) { print("Internet connection available"); } else { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar(content: Text("No Internet"))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Tidak ada koneksi internet"))); } }); } @@ -500,7 +500,7 @@ class TransferPetiPageState extends State { showSyncDialog(context); } else { ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text("No internet connection")), + SnackBar(content: Text("Tidak ada koneksi internet")), ); } }, diff --git a/lib/widget/component_query.dart b/lib/widget/component_query.dart new file mode 100644 index 0000000..53c06f2 --- /dev/null +++ b/lib/widget/component_query.dart @@ -0,0 +1,13 @@ +import 'package:intl/intl.dart'; +import 'package:flutter/material.dart'; + +String _formatDate(String? date) { + if (date != null) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } else { + return ''; + } +} diff --git a/lib/widget/loading_shimmer_show.dart b/lib/widget/loading_shimmer_show.dart new file mode 100644 index 0000000..a34ca62 --- /dev/null +++ b/lib/widget/loading_shimmer_show.dart @@ -0,0 +1,299 @@ +import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; + +class ShimmerShow extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(16.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + elevation: 5, + child: Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Column( + children: [ + Card( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.vertical(top: Radius.circular(15.0)), + ), + elevation: 0, + margin: EdgeInsets.all(0), + color: Colors.grey[300], + child: Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(Icons.article, size: 30, color: Colors.white), + SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'ID:', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + SizedBox(height: 5), + Text( + '-', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ), + SizedBox(height: 10), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + Divider(thickness: 1), + _buildShimmerDetailItem(), + // ... tambahkan shimmer item lainnya sesuai kebutuhan + ], + ), + ), + ), + ); + } + + Widget _buildShimmerDetailItem() { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + width: 80, + height: 12, + color: Colors.grey[300], + ), + Container( + width: 120, + height: 12, + color: Colors.grey[300], + ), + ], + ), + ); + } +} + +class ShimmerLoadingAssetStatusCard extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + children: [ + Card( + elevation: 0.0, + shape: RoundedRectangleBorder( + side: BorderSide(color: Colors.grey, width: 1.0), + // borderRadius: BorderRadius.circular(10), + ), + child: Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Padding( + padding: const EdgeInsets.only( + top: 8.0, + bottom: 8.0, + left: 16.0, + right: 16.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAvatarAndIndex(), + Divider(), + _buildInfoRow('Nama Peminjam:', '', 'PIC:', '', 11.5), + _buildInfoRow('Tanggal Peminjaman:', '', + 'Estimasi Pengembalian:', '', 11.5), + _buildInfoRow('Asal Gudang:', '', 'Tujuan Gudang:', '', 11.5), + ], + ), + ), + ), + ), + ], + ); + } + + Widget _buildAvatarAndIndex() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _buildAvatar(), + Expanded( + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + top: 8.0, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Text( + // '', + // style: TextStyle( + // fontWeight: FontWeight.bold, + // fontSize: 11.5, + // ), + // ), + lineDivider(), + ], + ), + ), + ), + ], + ); + } + + Widget lineDivider() { + return Container( + height: 13, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.grey[500], + borderRadius: BorderRadius.vertical( + top: Radius.circular(6), // Adjust top radius as needed + bottom: Radius.circular(6), // Adjust bottom radius as needed + ), + ), + ); + } + + Widget _buildAvatar() { + return Container( + child: CircleAvatar( + radius: 11, + backgroundColor: Colors.indigo, + ), + ); + } + + Widget _buildInfoRow(String title1, String content1, String title2, + String content2, double fontSize) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title1, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: fontSize, + ), + ), + SizedBox(height: 3), + lineDivider(), + // Text( + // content1, + // style: TextStyle( + // fontSize: fontSize - 0.5, + // ), + // ), + ], + ), + ), + SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // lineDivider(), + Text( + title2, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: fontSize, + ), + ), + SizedBox(height: 3), + lineDivider() + // Text( + // content2, + // style: TextStyle( + // fontSize: fontSize - 0.5, + // ), + // ), + ], + ), + ), + ], + ); + } +} + +Widget shimmerSearch() { + return Container( + margin: EdgeInsets.only(top: 8, bottom: 8), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Shimmer.fromColors( + baseColor: Colors.grey[300]!, + highlightColor: Colors.grey[100]!, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey, width: 1.0), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + children: [ + Icon(Icons.search), + SizedBox(width: 8), + Expanded( + child: Container( + height: 16, // Match the font size in the original search + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ); +} diff --git a/pubspec.lock b/pubspec.lock index 2c58dc7..e82952d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -222,6 +222,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.13.1" + flutter_slidable: + dependency: "direct main" + description: + name: flutter_slidable + sha256: "19ed4813003a6ff4e9c6bcce37e792a2a358919d7603b2b31ff200229191e44c" + url: "https://pub.dev" + source: hosted + version: "3.0.1" flutter_spinkit: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5b3b83d..324933c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: dropdown_search: ^5.0.6 shimmer: ^3.0.0 loading_animation_widget: ^1.2.0+4 + flutter_slidable: ^3.0.1 @@ -95,6 +96,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/img/ + - assets/item/ # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see