From c76ecacb92a57174d8e7831974c79c786be00f23 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 9 Nov 2023 14:21:43 +0700 Subject: [PATCH] Update: Perbaiki Scan QR Code, Alert fungsi Scan QR Code nullable, penambahan fitur Transfer Peti --- lib/connection/connection.dart | 2 - lib/main.dart | 15 +- lib/pages/home/home_page.dart | 37 ++ lib/pages/home/main_page.dart | 2 +- lib/pages/peminjaman_barang/create.dart | 160 ++++- .../peminjaman_stock_page.dart | 2 +- .../{create.dart => edit.dart} | 136 ++-- ...ian-index.dart => pengembalian_index.dart} | 3 +- lib/pages/transfer_peti/edit.dart | 629 ++++++++++++++++++ lib/pages/transfer_peti/show.dart | 175 +++++ .../transfer_peti/transfer_peti_index.dart | 287 ++++++++ 11 files changed, 1366 insertions(+), 82 deletions(-) rename lib/pages/{home => peminjaman_barang}/peminjaman_stock_page.dart (99%) rename lib/pages/pengembalian_barang/{create.dart => edit.dart} (86%) rename lib/pages/pengembalian_barang/{pengembalian-index.dart => pengembalian_index.dart} (98%) create mode 100644 lib/pages/transfer_peti/edit.dart create mode 100644 lib/pages/transfer_peti/show.dart create mode 100644 lib/pages/transfer_peti/transfer_peti_index.dart diff --git a/lib/connection/connection.dart b/lib/connection/connection.dart index 9c017ce..94c8d2f 100644 --- a/lib/connection/connection.dart +++ b/lib/connection/connection.dart @@ -2,5 +2,3 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; String baseUrl = 'http://192.168.0.20:8000/api/v1'; -// String baseUrl = 'http://10.0.0.2:8000/api/v1'; -// String baseUrl = 'https://gps.sap-samara.com/api/v1'; diff --git a/lib/main.dart b/lib/main.dart index 463c2cb..10eeaef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,14 +2,17 @@ import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:siopas/pages/pengembalian_barang/create.dart'; -import 'package:siopas/pages/pengembalian_barang/pengembalian-index.dart'; +import 'package:siopas/pages/pengembalian_barang/edit.dart'; +import 'package:siopas/pages/pengembalian_barang/pengembalian_index.dart'; +import 'package:siopas/pages/transfer_peti/edit.dart'; +import 'package:siopas/pages/transfer_peti/transfer_peti_index.dart'; import 'pages/home/main_page.dart'; -import 'pages/home/peminjaman_stock_page.dart'; +import 'pages/peminjaman_barang/peminjaman_stock_page.dart'; import 'pages/peminjaman_barang/create.dart'; import 'pages/peminjaman_barang/show.dart'; import 'pages/sign_in_page.dart'; import 'pages/splash_page.dart'; +import 'pages/transfer_peti/show.dart'; import 'providers/asset_status_provider.dart'; import 'providers/auth_provider.dart'; import 'providers/m_status_provider.dart'; @@ -57,10 +60,8 @@ class MyApp extends StatelessWidget { '/pengembalian-barang': (context) => PengembalianBarangPage(), '/pengembalian-barang/create': (context) => CreatePengembalianBarangPage(), - // '/peminjaman-barang/show': (context) => - // DetailPeminjamanBarangPage(assetId: 0), - // '/category': (context) => SurveyDetailPage(), - // '/map': (context) => GeoMapPage(), + '/transfer-peti': (context) => TransferPetiPage(), + '/transfer-peti/edit': (context) => EditTransferPetiPage(), }, ), ); diff --git a/lib/pages/home/home_page.dart b/lib/pages/home/home_page.dart index 2baa497..b4216bd 100644 --- a/lib/pages/home/home_page.dart +++ b/lib/pages/home/home_page.dart @@ -316,6 +316,42 @@ 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 cardRow() { return Column( children: [ @@ -479,6 +515,7 @@ class _HomePageState extends State { children: [ cardMenuPeminjaman(), cardMenuPengembalian(), + cardMenuTransfer(), ], ), ], diff --git a/lib/pages/home/main_page.dart b/lib/pages/home/main_page.dart index 81fa66c..fb43b97 100644 --- a/lib/pages/home/main_page.dart +++ b/lib/pages/home/main_page.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../providers/auth_provider.dart'; import 'home_page.dart'; -import 'peminjaman_stock_page.dart'; +import '../peminjaman_barang/peminjaman_stock_page.dart'; import 'setting_page.dart'; class MainPage extends StatefulWidget { diff --git a/lib/pages/peminjaman_barang/create.dart b/lib/pages/peminjaman_barang/create.dart index 4eef83e..0aa0fad 100644 --- a/lib/pages/peminjaman_barang/create.dart +++ b/lib/pages/peminjaman_barang/create.dart @@ -2,24 +2,20 @@ import 'dart:convert'; import 'dart:core'; import 'package:flutter/material.dart'; -// import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:qr_code_scanner/qr_code_scanner.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:siopas/models/m_asset_status_model.dart'; import 'package:siopas/models/warehouse_mode.dart'; -import 'package:siopas/providers/asset_status_provider.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:intl/date_symbol_data_local.dart'; // Import package intl import '../../connection/connection.dart'; import 'package:http/http.dart' as http; -import '../../models/asset_status_model.dart'; import '../../models/user_model.dart'; import '../../providers/auth_provider.dart'; -import '../../theme.dart'; class CreatePeminjamanBarang extends StatefulWidget { const CreatePeminjamanBarang({Key? key}) : super(key: key); @@ -72,7 +68,7 @@ class _CreatePeminjamanBarangState extends State { if (mounted) { // Periksa apakah widget masih "mounted" if (response.statusCode == 200) { - final jsonData = json.decode(response.body)['data']['asset']; + final jsonData = json.decode(response.body)['data']['petis']; final List newDataAsset = (jsonData as List) .map((item) => PetiAssetModel.fromJson(item)) @@ -128,10 +124,15 @@ class _CreatePeminjamanBarangState extends State { } } - void _onQRViewCreated(QRViewController controller) { + 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 { @@ -140,32 +141,59 @@ class _CreatePeminjamanBarangState extends State { List lines = result!.code!.split('\n'); + String idPeti = ''; + String idWarehouse = ''; + for (String line in lines) { - if (line.startsWith('ID Peti')) { - String idPeti = line.split(': ')[1]; - // Isi formulir dropdown asset - _valAsset = _dataAsset - .firstWhere((peti) => peti.id == int.parse(idPeti)); - } else if (line.startsWith('Date:')) { - String datePeminjaman = line.split(': ')[1]; - try { - DateTime parsedDate = - DateFormat('dd-MM-yyyy').parse(datePeminjaman); - String formattedDate = - DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(parsedDate); - _exit_atController.text = formattedDate; - } catch (e) { - print('Error parsing date: $e'); - // Lakukan penanganan jika format tanggal tidak sesuai + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + idWarehouse = values[2]; + break; } - } else if (line.startsWith('ID Warehouse')) { - String idWarehouse = line.split(': ')[1]; - // Isi formulir dropdown gudang - _valWarehouse = _dataWarehouse.firstWhere( - (warehouse) => warehouse.id == int.parse(idWarehouse)); } } + int? petiId = int.tryParse(idPeti); + int? warehouseId = int.tryParse(idWarehouse); + + if (petiId != null && warehouseId != null) { + _valAsset = _dataAsset.firstWhere( + (peti) => peti.id == petiId, + orElse: () => _valAsset!, + ); + + _valWarehouse = _dataWarehouse.firstWhere( + (warehouse) => warehouse.id == warehouseId, + orElse: () => _valWarehouse!, + ); + } else { + // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, // Warna ikon + ), + SizedBox(width: 8), // Jarak antara ikon dan teks + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), // Warna teks + ), + ], + ), + backgroundColor: + Colors.yellow[700], // Warna latar belakang SnackBar + ), + ); + } + scanned = true; }); @@ -178,14 +206,74 @@ class _CreatePeminjamanBarangState extends State { }); } catch (e) { print('Error scanning QR Code: $e'); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text('Error scanning QR Code: $e'), - )); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error scanning QR Code: $e'), + ), + ); } } }); } + // void _onQRViewCreated(QRViewController controller) { + // this.controller = controller; + // bool scanned = false; + + // controller.scannedDataStream.listen((scanData) { + // if (!scanned) { + // try { + // setState(() { + // result = scanData; + + // List lines = result!.code!.split('\n'); + + // for (String line in lines) { + // if (line.startsWith('ID Peti')) { + // String idPeti = line.split(': ')[1]; + // // Isi formulir dropdown asset + // _valAsset = _dataAsset + // .firstWhere((peti) => peti.id == int.parse(idPeti)); + // } else if (line.startsWith('Date:')) { + // String datePeminjaman = line.split(': ')[1]; + // try { + // DateTime parsedDate = + // DateFormat('dd-MM-yyyy').parse(datePeminjaman); + // String formattedDate = + // DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(parsedDate); + // _exit_atController.text = formattedDate; + // } catch (e) { + // print('Error parsing date: $e'); + // // Lakukan penanganan jika format tanggal tidak sesuai + // } + // } else if (line.startsWith('ID Warehouse')) { + // String idWarehouse = line.split(': ')[1]; + // // Isi formulir dropdown gudang + // _valWarehouse = _dataWarehouse.firstWhere( + // (warehouse) => warehouse.id == int.parse(idWarehouse)); + // } + // } + + // scanned = true; + // }); + + // controller.stopCamera(); + + // Future.delayed(Duration(milliseconds: 500), () { + // if (mounted) { + // Navigator.of(context).pop(); + // } + // }); + // } catch (e) { + // print('Error scanning QR Code: $e'); + // ScaffoldMessenger.of(context).showSnackBar(SnackBar( + // content: Text('Error scanning QR Code: $e'), + // )); + // } + // } + // }); + // } + @override void dispose() { super.dispose(); @@ -197,6 +285,10 @@ class _CreatePeminjamanBarangState extends State { AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 150.0 + : 300.0; // var now = DateTime.now(); // var dt = DateTime(DateTime.now().year, DateTime.now().month, @@ -300,6 +392,12 @@ class _CreatePeminjamanBarangState extends State { style: TextStyle( fontSize: 16, )), + leading: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pushNamed(context, '/peminjaman-barang'); + }, + ), ), body: _isLoading ? const Center(child: CircularProgressIndicator()) @@ -386,7 +484,7 @@ class _CreatePeminjamanBarangState extends State { borderRadius: 10, borderLength: 30, borderWidth: 10, - cutOutSize: 300, + cutOutSize: scanArea, ), ), ), diff --git a/lib/pages/home/peminjaman_stock_page.dart b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart similarity index 99% rename from lib/pages/home/peminjaman_stock_page.dart rename to lib/pages/peminjaman_barang/peminjaman_stock_page.dart index 9a0fe30..b991e11 100644 --- a/lib/pages/home/peminjaman_stock_page.dart +++ b/lib/pages/peminjaman_barang/peminjaman_stock_page.dart @@ -11,7 +11,7 @@ import 'package:siopas/providers/asset_status_provider.dart'; import 'package:http/http.dart' as http; import '../../connection/connection.dart'; -import '../peminjaman_barang/show.dart'; +import 'show.dart'; class AssetStatusPage extends StatefulWidget { const AssetStatusPage({super.key}); diff --git a/lib/pages/pengembalian_barang/create.dart b/lib/pages/pengembalian_barang/edit.dart similarity index 86% rename from lib/pages/pengembalian_barang/create.dart rename to lib/pages/pengembalian_barang/edit.dart index d841fc6..868d503 100644 --- a/lib/pages/pengembalian_barang/create.dart +++ b/lib/pages/pengembalian_barang/edit.dart @@ -64,7 +64,7 @@ class _CreatePengembalianBarangPageState }); final response = - await http.get(Uri.parse('$baseUrl/asset-status/pengembalian')); + await http.get(Uri.parse('$baseUrl/asset-status/pengembalian/create')); if (mounted) { // Periksa apakah widget masih "mounted" @@ -125,10 +125,15 @@ class _CreatePengembalianBarangPageState } } - void _onQRViewCreated(QRViewController controller) { + 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 { @@ -137,31 +142,48 @@ class _CreatePengembalianBarangPageState List lines = result!.code!.split('\n'); + String idPeti = ''; + for (String line in lines) { - if (line.startsWith('ID Peti')) { - String idPeti = line.split(': ')[1]; - // Isi formulir dropdown asset - _valAsset = _dataAsset - .firstWhere((peti) => peti.id == int.parse(idPeti)); - } else if (line.startsWith('Date:')) { - String datePeminjaman = line.split(': ')[1]; - try { - DateTime parsedDate = - DateFormat('dd-MM-yyyy').parse(datePeminjaman); - String formattedDate = - DateFormat('yyyy-MM-dd HH:mm:ss.SSS').format(parsedDate); - _enterAtController.text = formattedDate; - } catch (e) { - print('Error parsing date: $e'); - // Lakukan penanganan jika format tanggal tidak sesuai + if (line.contains(';')) { + List values = line.split(';'); + if (values.length >= 3) { + idPeti = values[1]; + break; } } - // else if (line.startsWith('ID Warehouse')) { - // String idWarehouse = line.split(': ')[1]; - // // Isi formulir dropdown gudang - // _valWarehouse = _dataWarehouse.firstWhere( - // (warehouse) => warehouse.id == int.parse(idWarehouse)); - // } + } + + int? petiId = int.tryParse(idPeti); + + if (petiId != null) { + _valAsset = _dataAsset.firstWhere( + (peminjaman) => peminjaman.peti_id == petiId, + orElse: () => _valAsset!, + ); + } else { + // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, // Warna ikon + ), + SizedBox(width: 8), // Jarak antara ikon dan teks + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), // Warna teks + ), + ], + ), + backgroundColor: Colors.yellow[700], + ), + ); } scanned = true; @@ -171,14 +193,40 @@ class _CreatePengembalianBarangPageState Future.delayed(Duration(milliseconds: 500), () { if (mounted) { - Navigator.of(context).pop(); + Navigator.pop(context); } }); } catch (e) { + controller.stopCamera(); + if (mounted) { + Navigator.pushNamed(context, '/pengembalian-barang/create'); + } print('Error scanning QR Code: $e'); - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text('Error scanning QR Code: $e'), - )); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.error, // Icon error + color: Colors.red[400], // Warna merah + ), + SizedBox(width: 8), + Flexible( + // Menggunakan Flexible untuk menghindari overflow + child: Text( + 'Peti ini belum ada di menu pinjaman, silahkan untuk mengecek kembali.', + style: TextStyle( + color: Colors.white, + fontSize: 12, + ), // Warna teks merah + ), + ), + ], + ), + backgroundColor: Colors.red[700], + ), + ); } } }); @@ -195,6 +243,10 @@ class _CreatePengembalianBarangPageState AuthProvider authProvider = Provider.of(context, listen: false); UserModel user = authProvider.user; + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 150.0 + : 300.0; Future _updatePeminjaman() async { setState(() { @@ -235,7 +287,7 @@ class _CreatePengembalianBarangPageState color: Colors.white, ), SizedBox(width: 5), - Text('Data berhasil diperbarui'), + Text('Data berhasil dikembalikan'), ], ), duration: Duration(seconds: 3), // Durasi tampilan snackbar @@ -243,6 +295,7 @@ class _CreatePengembalianBarangPageState ); // Reset form input + _valAsset = null; _enterAtController.text = ''; _enterPicController.text = ''; _kondisiPetiController.text = ''; @@ -279,15 +332,16 @@ class _CreatePengembalianBarangPageState return Scaffold( appBar: AppBar( - elevation: 0, - backgroundColor: Color.fromARGB(255, 5, 28, 158), - title: Text('Pengembalian Barang'), - leading: IconButton( - icon: Icon(Icons.arrow_back), - onPressed: () { - Navigator.pushNamed(context, '/pengembalian-barang'); - }, - )), + elevation: 0, + backgroundColor: Color.fromARGB(255, 5, 28, 158), + title: Text('Pengembalian Barang'), + leading: IconButton( + icon: Icon(Icons.arrow_back), + onPressed: () { + Navigator.pushNamed(context, '/pengembalian-barang'); + }, + ), + ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( @@ -347,6 +401,10 @@ class _CreatePengembalianBarangPageState ), child: IconButton( onPressed: () { + setState(() { + _valAsset = + null; // Mengatur _valAsset menjadi null + }); showModalBottomSheet( context: context, isScrollControlled: @@ -366,7 +424,7 @@ class _CreatePengembalianBarangPageState borderRadius: 10, borderLength: 30, borderWidth: 10, - cutOutSize: 300, + cutOutSize: scanArea, ), ), ), diff --git a/lib/pages/pengembalian_barang/pengembalian-index.dart b/lib/pages/pengembalian_barang/pengembalian_index.dart similarity index 98% rename from lib/pages/pengembalian_barang/pengembalian-index.dart rename to lib/pages/pengembalian_barang/pengembalian_index.dart index 5f72e62..cd2b237 100644 --- a/lib/pages/pengembalian_barang/pengembalian-index.dart +++ b/lib/pages/pengembalian_barang/pengembalian_index.dart @@ -51,7 +51,8 @@ class PengembalianBarangPageState extends State { }); try { - final response = await http.get(Uri.parse('$baseUrl/asset-status')); + final response = + await http.get(Uri.parse('$baseUrl/asset-status/pengembalian')); if (response.statusCode == 200) { final jsonData = json.decode(response.body)['data']['asset_status']; diff --git a/lib/pages/transfer_peti/edit.dart b/lib/pages/transfer_peti/edit.dart new file mode 100644 index 0000000..14a33c7 --- /dev/null +++ b/lib/pages/transfer_peti/edit.dart @@ -0,0 +1,629 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:qr_code_scanner/qr_code_scanner.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:siopas/connection/connection.dart'; +import 'package:http/http.dart' as http; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +// import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/models/user_model.dart'; +import 'package:siopas/models/warehouse_mode.dart'; +import 'package:siopas/providers/auth_provider.dart'; + +class EditTransferPetiPage extends StatefulWidget { + const EditTransferPetiPage({super.key}); + + @override + State createState() => EditTransferPetiPageState(); +} + +class EditTransferPetiPageState extends State { + List _dataAsset = []; + List _dataWarehouse = []; + bool _isLoading = false; + String? token; + PetiAssetModel? _valAsset; + WarehouseModel? _valWarehouse_asal_gudang; + WarehouseModel? _valWarehouse_tujuan_gudang; + // TextEditingController _exit_atController = TextEditingController(); + // TextEditingController _est_pengembalianController = TextEditingController(); + // TextEditingController _penanggungJawabController = TextEditingController(); + final _formKey = GlobalKey(); + + final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); + Barcode? result; + QRViewController? controller; + + @override + void initState() { + super.initState(); + _getUserToken(); + fetchDataWarehouse(); + fetchDataAsset(); + initializeDateFormatting('id_ID'); + } + + void _getUserToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + token = prefs.getString('token'); + }); + } + } + + Future fetchDataAsset() async { + setState(() { + _isLoading = true; + }); + + final response = await http.get(Uri.parse('$baseUrl/peti-asset')); + + if (mounted) { + // Periksa apakah widget masih "mounted" + if (response.statusCode == 200) { + final jsonData = json.decode(response.body)['data']['petis']; + + final List newDataAsset = (jsonData as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + + if (mounted) { + // Periksa lagi sebelum memanggil setState + setState(() { + _dataAsset.addAll(newDataAsset); + _isLoading = false; + }); + } + } else { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + throw Exception('Failed to fetch data Asset Status'); + } + } + } + + Future fetchDataWarehouse() async { + setState(() { + _isLoading = true; + }); + + final response = await http.get(Uri.parse('$baseUrl/m-warehouse')); + + if (mounted) { + if (response.statusCode == 200) { + final jsonData = json.decode(response.body)['data']['warehouse']; + + final List newDataWarehouse = (jsonData as List) + .map((item) => WarehouseModel.fromJson(item)) + .toList(); + + if (mounted) { + setState(() { + _dataWarehouse.addAll(newDataWarehouse); + _isLoading = false; + }); + } + } else { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + throw Exception('Failed to fetch data Warehouse'); + } + } + } + + 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); + + if (petiId != null && warehouseId != null) { + _valAsset = _dataAsset.firstWhere( + (peti) => peti.id == petiId, + orElse: () => _valAsset!, + ); + + _valWarehouse_asal_gudang = _dataWarehouse.firstWhere( + (warehouse) => warehouse.id == warehouseId, + orElse: () => _valWarehouse_asal_gudang!, + ); + } else { + // Jika nilai yang dipindai tidak sesuai, tampilkan pesan kesalahan + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Row( + children: [ + Icon( + Icons.warning, + color: Colors.black, // Warna ikon + ), + SizedBox(width: 8), // Jarak antara ikon dan teks + Text( + 'Nilai QR Code tidak sesuai dengan yang diharapkan.', + style: TextStyle( + color: Colors.black, + fontSize: 12, + ), // Warna teks + ), + ], + ), + backgroundColor: + Colors.yellow[700], // Warna latar belakang SnackBar + ), + ); + } + + scanned = true; + }); + + controller.stopCamera(); + + Future.delayed(Duration(milliseconds: 500), () { + if (mounted) { + Navigator.of(context).pop(); + } + }); + } catch (e) { + print('Error scanning QR Code: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Error scanning QR Code: $e'), + ), + ); + } + } + }); + } + + @override + void dispose() { + super.dispose(); + controller?.dispose(); + } + + @override + Widget build(BuildContext context) { + AuthProvider authProvider = + Provider.of(context, listen: false); + UserModel user = authProvider.user; + var scanArea = (MediaQuery.of(context).size.width < 400 || + MediaQuery.of(context).size.height < 400) + ? 150.0 + : 300.0; + + // var now = DateTime.now(); + // var dt = DateTime(DateTime.now().year, DateTime.now().month, + // DateTime.now().day, DateTime.now().hour, DateTime.now().minute); + + // // _exit_atController.text = DateFormat('yyyy-MM-dd HH:mm:ss').format(dt); + // _exit_atController.text = DateFormat('dd-MM-yyyy').format(dt); + + Future _updateTransferPeti() async { + setState(() { + _isLoading = true; + }); + + try { + final response = await http.put( + Uri.parse('$baseUrl/peti-asset/update/${_valAsset!.id}'), + headers: { + 'Content-Type': 'application/json', + 'Authorization': token!, + }, + body: jsonEncode({ + 'warehouse_id': _valWarehouse_tujuan_gudang!.id, + 'updated_by': user.fullname, + }), + ); + + print(response.body); + + if (response.statusCode == 200) { + final jsonData = json.decode(response.body)['data']['petis']; + + print('Berhasil memperbarui data: $jsonData'); + + // Tampilkan snackbar + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.greenAccent[700], + content: Row( + children: [ + Icon( + Icons.check_circle_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text('Data berhasil ditransferkan'), + ], + ), + duration: Duration(seconds: 3), // Durasi tampilan snackbar + ), + ); + + // Reset form input + _valAsset = null; + _valWarehouse_asal_gudang = null; + _valWarehouse_tujuan_gudang = null; + // _enterAtController.text = ''; + // _enterPicController.text = ''; + // _kondisiPetiController.text = ''; + // _valWarehouse = null; + } else { + _valAsset = null; + _valWarehouse_asal_gudang = null; + _valWarehouse_tujuan_gudang = null; + throw Exception('Gagal memperbarui data Asset Status'); + } + } catch (e) { + print('Error updating data: $e'); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + backgroundColor: Colors.redAccent[700], + content: Row( + children: [ + Icon( + Icons.error_outline, + color: Colors.white, + ), + SizedBox(width: 5), + Text('Gagal memperbarui data'), + ], + ), + duration: Duration(seconds: 2), // Durasi tampilan snackbar + ), + ); + } finally { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + } + } + + return Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Buat Peminjaman Barang', + style: TextStyle( + fontSize: 16, + )), + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(16), + child: Form( + key: _formKey, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Card( + elevation: 2, + child: Container( + margin: EdgeInsets.all(8), + child: DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + labelText: 'Peti', + border: OutlineInputBorder(), + ), + hint: Text("Pilih Peti"), + value: _valAsset, + items: _dataAsset.map((PetiAssetModel item) { + return DropdownMenuItem( + child: Text('${item.fix_lot}'), + value: item, + ); + }).toList(), + onChanged: (PetiAssetModel? value) { + setState(() { + _valAsset = value; + if (value != null) { + // Set _valWarehouse berdasarkan warehouse_id dari PetiAssetModel + _valWarehouse_asal_gudang = + _dataWarehouse.firstWhere( + (warehouse) => + warehouse.id == + int.parse(value.warehouse_id + .toString()), + ); + } + }); + }, + ), + ), + ), + ), + 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: () { + Navigator.of(context).pop(); + }, + icon: Icon( + Icons.close, + size: 40, + ), + 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: DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + labelText: 'Asal Gudang', + border: OutlineInputBorder(), + ), + hint: Text("Asal Gudang"), + value: _valWarehouse_asal_gudang, + items: + _dataWarehouse.map((WarehouseModel warehouse) { + return DropdownMenuItem( + child: Text('${warehouse.name}'), + value: warehouse, + ); + }).toList(), + onChanged: null, + // (WarehouseModel? value) { + // setState(() { + // _valWarehouse_asal_gudang = value; + // }); + // }, + ), + ), + ), + SizedBox(height: 16), + Card( + elevation: 2, + child: Padding( + padding: const EdgeInsets.all(8), + child: DropdownButtonFormField( + validator: (value) { + if (value == null) { + return 'Harus diisi'; + } + return null; + }, + decoration: InputDecoration( + labelText: 'Tujuan Gudang', + border: OutlineInputBorder(), + ), + hint: Text("Tujuan Gudang"), + value: _valWarehouse_tujuan_gudang, + items: + _dataWarehouse.map((WarehouseModel warehouse) { + return DropdownMenuItem( + child: Text('${warehouse.name}'), + value: warehouse, + ); + }).toList(), + onChanged: (WarehouseModel? value) { + setState(() { + _valWarehouse_tujuan_gudang = value; + }); + }, + ), + ), + ), + Visibility( + visible: false, + child: FractionallySizedBox( + widthFactor: 1.0, + child: Card( + elevation: 1, + child: Padding( + padding: const EdgeInsets.all(8), + child: Column( + children: [ + Text( + 'Data dari QR Code:', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 8), + Text( + result != null && result!.code != null + ? result!.code! + : 'Belum ada data QR Code terpindai', + style: TextStyle(fontSize: 14), + ), + ], + ), + ), + ), + ), + ), + ], + ), + ), + ), + ), + bottomNavigationBar: BottomAppBar( + height: MediaQuery.of(context).size.height / 8, + color: Color.fromARGB(255, 5, 28, 158), // Warna latar belakang + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + 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.red, // Warna merah untuk close + ), + child: IconButton( + onPressed: () { + // Navigator.pop(context); + Navigator.pushNamed(context, '/transfer-peti'); + }, + icon: Icon(Icons.close, color: Colors.white), + ), + ), + ], + ), + ), + 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: () { + if (_formKey.currentState!.validate()) { + try { + _updateTransferPeti(); + } catch (e) { + print('Error storing data: $e'); + } + } + }, + icon: Icon(Icons.save, color: Colors.white), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/transfer_peti/show.dart b/lib/pages/transfer_peti/show.dart new file mode 100644 index 0000000..08b4e12 --- /dev/null +++ b/lib/pages/transfer_peti/show.dart @@ -0,0 +1,175 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:siopas/connection/connection.dart'; +import 'package:http/http.dart' as http; + +class DetailTransferPetiPage extends StatefulWidget { + final int petiId; + const DetailTransferPetiPage({Key? key, required this.petiId}) + : super(key: key); + + @override + State createState() => _DetailTransferPetiPageState(); +} + +class _DetailTransferPetiPageState extends State { + Map? petiStatusData; + String _formatDate(String date) { + DateTime parsedDate = DateTime.parse(date); + String formattedDate = + DateFormat('EEEE, dd MMMM yyyy', 'id_ID').format(parsedDate); + return formattedDate; + } + + @override + void initState() { + super.initState(); + _fetchAssetStatusDataPengembalian(); + } + + Future _fetchAssetStatusDataPengembalian() async { + try { + final response = await http.get( + Uri.parse('$baseUrl/peti-asset/show/${widget.petiId}'), + headers: { + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + setState(() { + petiStatusData = json.decode(response.body)['data']['peti']; + }); + } else { + throw Exception('Failed to load data'); + } + } catch (e) { + print('Error fetching data: $e'); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey[200], + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Detail Peti', + style: TextStyle( + color: Colors.white, + fontSize: 16, + )), + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/transfer-peti'); + }, + ), + ), + body: Padding( + padding: EdgeInsets.all(16.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15.0), + ), + 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: Row( + children: [ + Icon(Icons.article, + size: 40, + color: Colors.white), // Ganti ikon sesuai kebutuhan + SizedBox(width: 10), + Text( + 'ID: ${widget.petiId}', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + ), + ], + ), + ), + ), + SizedBox(height: 10), + if (petiStatusData != null) ...[ + _buildDetailItem( + 'Tipe Peti', + petiStatusData!['tipe_peti']['type'], + ), + Divider(thickness: 1), + _buildDetailItem( + 'Warna Peti', + petiStatusData!['warna'] != null + ? petiStatusData!['warna'].toString() + : '-'), + Divider(thickness: 1), + _buildDetailItem( + 'Customer', + petiStatusData!['customer']['name'] != null + ? petiStatusData!['customer']['name'].toString() + : '-'), + Divider(thickness: 1), + _buildDetailItem( + 'Warehouse', + petiStatusData!['warehouse']['name'] != null + ? petiStatusData!['warehouse']['name'].toString() + : '-'), + Divider(thickness: 1), + _buildDetailItem( + 'Status Peti', + petiStatusData!['status_disposal'] != null + ? petiStatusData!['status_disposal'].toString() + : '-'), + Divider(thickness: 1), + _buildDetailItem( + 'Jumlah Peti', + petiStatusData!['jumlah'] != null + ? petiStatusData!['jumlah'].toString() + : '-', + ), + Divider(thickness: 1), + _buildDetailItem( + 'Tgl Pembuatan Peti', + petiStatusData!['created_at'] != null + ? _formatDate(petiStatusData!['created_at']) + : '-'), + ], + ], + ), + ), + ), + ); + } + + Widget _buildDetailItem(String label, String value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + label, + style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.bold), + ), + Text(value), + ], + ), + ); + } +} diff --git a/lib/pages/transfer_peti/transfer_peti_index.dart b/lib/pages/transfer_peti/transfer_peti_index.dart new file mode 100644 index 0000000..f083edf --- /dev/null +++ b/lib/pages/transfer_peti/transfer_peti_index.dart @@ -0,0 +1,287 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:flutter/material.dart'; +import 'package:data_table_2/data_table_2.dart'; +import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:siopas/models/asset_status_model.dart'; +import 'package:siopas/models/m_asset_status_model.dart'; +import 'package:siopas/pages/pengembalian_barang/show.dart'; +import 'package:siopas/pages/transfer_peti/show.dart'; +import 'package:siopas/providers/asset_status_provider.dart'; +import 'package:http/http.dart' as http; + +import '../../connection/connection.dart'; +import '../peminjaman_barang/show.dart'; + +class TransferPetiPage extends StatefulWidget { + const TransferPetiPage({super.key}); + + @override + State createState() => TransferPetiPageState(); +} + +class TransferPetiPageState extends State { + String? token; + int _currentPage = 1; + int _pageSize = 10; + List _data = []; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + _getUserToken(); + fetchData(); + } + + void _getUserToken() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + token = prefs.getString('token'); + }); + } + } + + Future fetchData() async { + if (mounted) { + setState(() { + _isLoading = true; + }); + + try { + final response = await http.get(Uri.parse('$baseUrl/peti-asset')); + + if (response.statusCode == 200) { + final jsonData = json.decode(response.body)['data']['petis']; + + final List newData = (jsonData as List) + .map((item) => PetiAssetModel.fromJson(item)) + .toList(); + + if (mounted) { + setState(() { + _data.addAll(newData); + _isLoading = false; + }); + } + } else { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + throw Exception('Failed to fetch data'); + } + } catch (e) { + if (mounted) { + setState(() { + _isLoading = false; + }); + } + print('Error fetching data: $e'); + } + } + } + + void _loadMoreData() { + if (mounted && !_isLoading) { + setState(() { + _currentPage++; + }); + fetchData(); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Colors.indigo[700], + elevation: 0, + title: Text('Data Peti (Transfer Peti)', + style: TextStyle( + fontSize: 16, + )), + leading: IconButton( + icon: Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + ), + ), + body: _isLoading + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + child: SizedBox( + width: double.infinity, + child: PaginatedDataTable( + header: const Text('Menu Peti'), + rowsPerPage: _pageSize, + availableRowsPerPage: const [10, 25, 50], + onRowsPerPageChanged: (value) { + setState(() { + _pageSize = value!; + }); + }, + columns: const [ + DataColumn(label: Text('No')), + DataColumn(label: Text('')), + DataColumn(label: Text('Customer')), + DataColumn(label: Text('Gudang')), + DataColumn(label: Text('Fix Lot')), + DataColumn(label: Text('Tipe Peti')), + DataColumn(label: Text('Ukuran Peti')), + DataColumn(label: Text('Lot No')), + DataColumn(label: Text('Status Peti')), + DataColumn(label: Text('Packing No')), + ], + source: _DataSource(data: _data, context: context), + ), + ), + ), + 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, '/transfer-peti/edit'); + }, + child: Container( + width: 45, + height: 45, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.yellow[800], + ), + child: Icon( + Icons.local_shipping, + size: 30, + color: Colors.white, + ), + ), + ), + ], + ), + ), + ), + ); + } +} + +class _DataSource extends DataTableSource { + final List data; + final BuildContext context; + + _DataSource({required this.data, required this.context}); + @override + DataRow? getRow(int index) { + if (index >= data.length) { + return null; + } + + final item = data[index]; + + return DataRow(cells: [ + DataCell( + Text( + (index + 1).toString(), + ), + ), + DataCell( + GestureDetector( + onTap: () { + if (item.id != null) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DetailTransferPetiPage( + petiId: item.id!, + ), + ), + ); + + print('asset id: ${item.id}'); + } + }, + child: Icon( + Icons.article_outlined, + size: 30, + color: Colors.indigo[700], + ), + ), + ), + DataCell( + Text( + item.customer!.name!.toString() != 'null' + ? item.customer!.name.toString() + : '-', + ), + ), + DataCell( + Text( + item.warehouse!.name!.toString() != 'null' + ? item.warehouse!.name.toString() + : '-', + ), + ), + DataCell( + Text( + item.fix_lot.toString() != 'null' ? item.fix_lot.toString() : '-', + ), + ), + DataCell( + Text( + item.tipe_peti!.type.toString() != 'null' + ? item.tipe_peti!.type.toString() + : '-', + ), + ), + DataCell( + Text(item.tipe_peti!.size_peti.toString() != 'null' + ? item.tipe_peti!.size_peti.toString() + : '-'), + ), + DataCell( + Text( + item.customer!.lot_no.toString() != 'null' + ? item.customer!.lot_no.toString() + : '-', + ), + ), + DataCell( + Text( + item.status_disposal.toString() != 'null' + ? item.status_disposal.toString() + : '-', + ), + ), + DataCell( + Text( + item.packing_no.toString() != 'null' + ? item.packing_no.toString() + : '-', + ), + ), + ]); + } + + @override + bool get isRowCountApproximate => false; + + @override + int get rowCount => data.length; + + @override + int get selectedRowCount => 0; +}