diff --git a/.env b/.env index fad3a8f..1e1f0fb 100644 --- a/.env +++ b/.env @@ -2,6 +2,12 @@ # api_url = 'https://panti-asuhan.s-keytech.com/api/' # # url = 'http://172.29.85.181/panti_asuhan2/' # # api_url = 'http://172.29.85.181/panti_asuhan2/api/' -url = 'http://20.20.20.25:3001/' -table_url = 'http://20.20.20.25:3001/table' -api_url = 'http://20.20.20.25:3001/table' \ No newline at end of file +# url = 'http://20.20.20.25:3001/' +# table_url = 'http://20.20.20.25:3001/table' +# api_url = 'http://20.20.20.25:3001/table' +# url = 'http://192.168.20.232:3001/' +# table_url = 'http://192.168.20.232:3001/table' +# api_url = 'http://192.168.20.232:3001/table' +url = 'https://reza_backend.kicap-karan.com/' +table_url = 'https://reza_backend.kicap-karan.com/table' +api_url = 'https://reza_backend.kicap-karan.com/table' \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 61ce643..b62b2b9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,10 +1,12 @@ + + /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -254,6 +339,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + 9D81C40ECFD927F0DCE6AAF9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -361,6 +468,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = F4SG2JTPHZ; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -377,7 +485,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = B8FC2E1A7DB3F10ADFD9BF5B /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -395,7 +503,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 3621C893DBE36C6D8BEDC23F /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,7 +519,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = B3221495538A4944BB75F94E /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -539,6 +647,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = F4SG2JTPHZ; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -561,6 +670,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = F4SG2JTPHZ; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard index f3c2851..08dbc27 100644 --- a/ios/Runner/Base.lproj/Main.storyboard +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -1,8 +1,10 @@ - - + + + - + + @@ -14,13 +16,14 @@ - + - + + diff --git a/lib/app/app.dart b/lib/app/app.dart index 34b4d36..2fe56a2 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -5,6 +5,7 @@ import 'package:stacked/stacked_annotations.dart'; import '../services/http_services.dart'; import '../services/my_easyloading.dart'; +import '../services/my_socket_io_client.dart'; import '../ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart'; import '../ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart'; import '../ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_hp_view.dart'; @@ -54,6 +55,7 @@ import '../ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart'; LazySingleton(classType: MyHttpServices), LazySingleton(classType: OtherFunction), LazySingleton(classType: GlobalVar), + LazySingleton(classType: MySocketIoClient), ], logger: StackedLogger(), ) diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart index 97e55c5..f575214 100644 --- a/lib/app/app.locator.dart +++ b/lib/app/app.locator.dart @@ -15,6 +15,7 @@ import 'package:stacked_shared/stacked_shared.dart'; import '../services/global_var.dart'; import '../services/http_services.dart'; import '../services/my_easyloading.dart'; +import '../services/my_socket_io_client.dart'; import '../services/other_function.dart'; final locator = StackedLocator.instance; @@ -36,4 +37,5 @@ Future setupLocator({ locator.registerLazySingleton(() => MyHttpServices()); locator.registerLazySingleton(() => OtherFunction()); locator.registerLazySingleton(() => GlobalVar()); + locator.registerLazySingleton(() => MySocketIoClient()); } diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart index d577a45..97acab9 100644 --- a/lib/app/app.router.dart +++ b/lib/app/app.router.dart @@ -7,6 +7,7 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:flutter/material.dart' as _i11; import 'package:flutter/material.dart'; +import 'package:reza_app/model/makanan_model.dart' as _i12; import 'package:reza_app/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart' as _i6; import 'package:reza_app/ui/views/daftar_user_ui/masukan_no_hp/masukan_no_hp_view.dart' @@ -17,21 +18,21 @@ import 'package:reza_app/ui/views/login_user/login_user_view.dart' as _i3; import 'package:reza_app/ui/views/meja_detail/meja_detail_view.dart' as _i9; import 'package:reza_app/ui/views/splash_screen/splash_screen_view.dart' as _i2; import 'package:reza_app/ui/views/user_ui/akun_user/akun_user_view.dart' - as _i15; + as _i16; import 'package:reza_app/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart' as _i8; import 'package:reza_app/ui/views/user_ui/makanan_list/makanan_list_view.dart' - as _i13; + as _i14; import 'package:reza_app/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart' as _i10; import 'package:reza_app/ui/views/user_ui/pesanan_list/pesanan_list_view.dart' - as _i14; + as _i15; import 'package:reza_app/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart' - as _i12; + as _i13; import 'package:reza_app/ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart' as _i7; import 'package:stacked/stacked.dart' as _i1; -import 'package:stacked_services/stacked_services.dart' as _i16; +import 'package:stacked_services/stacked_services.dart' as _i17; class Routes { static const splashScreenView = '/'; @@ -146,8 +147,10 @@ class StackedRouter extends _i1.RouterBase { ); }, _i8.DetailMakananView: (data) { + final args = data.getArgs(nullOk: false); return _i11.MaterialPageRoute( - builder: (context) => const _i8.DetailMakananView(), + builder: (context) => _i8.DetailMakananView( + key: args.key, makananModel: args.makananModel), settings: data, ); }, @@ -200,6 +203,33 @@ class InputInformasiDiriViewArguments { } } +class DetailMakananViewArguments { + const DetailMakananViewArguments({ + this.key, + required this.makananModel, + }); + + final _i11.Key? key; + + final _i12.MakananModel makananModel; + + @override + String toString() { + return '{"key": "$key", "makananModel": "$makananModel"}'; + } + + @override + bool operator ==(covariant DetailMakananViewArguments other) { + if (identical(this, other)) return true; + return other.key == key && other.makananModel == makananModel; + } + + @override + int get hashCode { + return key.hashCode ^ makananModel.hashCode; + } +} + class MejaDetailViewArguments { const MejaDetailViewArguments({ this.key, @@ -248,44 +278,44 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase { final _routes = <_i1.RouteDef>[ _i1.RouteDef( UserIndexTrackingViewRoutes.reservasiMejaView, - page: _i12.ReservasiMejaView, + page: _i13.ReservasiMejaView, ), _i1.RouteDef( UserIndexTrackingViewRoutes.makananListView, - page: _i13.MakananListView, + page: _i14.MakananListView, ), _i1.RouteDef( UserIndexTrackingViewRoutes.pesananListView, - page: _i14.PesananListView, + page: _i15.PesananListView, ), _i1.RouteDef( UserIndexTrackingViewRoutes.akunUserView, - page: _i15.AkunUserView, + page: _i16.AkunUserView, ), ]; final _pagesMap = { - _i12.ReservasiMejaView: (data) { + _i13.ReservasiMejaView: (data) { return _i11.MaterialPageRoute( - builder: (context) => const _i12.ReservasiMejaView(), + builder: (context) => const _i13.ReservasiMejaView(), settings: data, ); }, - _i13.MakananListView: (data) { + _i14.MakananListView: (data) { return _i11.MaterialPageRoute( - builder: (context) => const _i13.MakananListView(), + builder: (context) => const _i14.MakananListView(), settings: data, ); }, - _i14.PesananListView: (data) { + _i15.PesananListView: (data) { return _i11.MaterialPageRoute( - builder: (context) => const _i14.PesananListView(), + builder: (context) => const _i15.PesananListView(), settings: data, ); }, - _i15.AkunUserView: (data) { + _i16.AkunUserView: (data) { return _i11.MaterialPageRoute( - builder: (context) => const _i15.AkunUserView(), + builder: (context) => const _i16.AkunUserView(), settings: data, ); }, @@ -297,7 +327,7 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase { Map get pagesMap => _pagesMap; } -extension NavigatorStateExtension on _i16.NavigationService { +extension NavigatorStateExtension on _i17.NavigationService { Future navigateToSplashScreenView([ int? routerId, bool preventDuplicates = true, @@ -385,14 +415,18 @@ extension NavigatorStateExtension on _i16.NavigationService { transition: transition); } - Future navigateToDetailMakananView([ + Future navigateToDetailMakananView({ + _i11.Key? key, + required _i12.MakananModel makananModel, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.detailMakananView, + arguments: + DetailMakananViewArguments(key: key, makananModel: makananModel), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -574,14 +608,18 @@ extension NavigatorStateExtension on _i16.NavigationService { transition: transition); } - Future replaceWithDetailMakananView([ + Future replaceWithDetailMakananView({ + _i11.Key? key, + required _i12.MakananModel makananModel, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.detailMakananView, + arguments: + DetailMakananViewArguments(key: key, makananModel: makananModel), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, diff --git a/lib/main.dart b/lib/main.dart index 1c17cd2..02b6723 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; @@ -9,6 +11,7 @@ import 'app/themes/app_theme.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + HttpOverrides.global = MyHttpOverrides(); await dotenv.load(fileName: ".env"); await setupAllLocator(); runApp(const MyApp()); @@ -37,3 +40,12 @@ Future setupAllLocator() async { // setupBottomsheetUi(); // setupSnackbarUi(); } + +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} diff --git a/lib/model/makanan_model.dart b/lib/model/makanan_model.dart new file mode 100644 index 0000000..7aa740d --- /dev/null +++ b/lib/model/makanan_model.dart @@ -0,0 +1,32 @@ +class MakananModel { + int? idMakanan; + String? namaMakanan; + String? hargaMakanan; + String? deskripsiMakanan; + String? imgUrl; + + MakananModel( + {this.idMakanan, + this.namaMakanan, + this.hargaMakanan, + this.deskripsiMakanan, + this.imgUrl}); + + MakananModel.fromJson(Map json) { + idMakanan = json['id_makanan']; + namaMakanan = json['nama_makanan']; + hargaMakanan = json['harga_makanan']; + deskripsiMakanan = json['deskripsi_makanan']; + imgUrl = json['img_url']; + } + + Map toJson() { + final Map data = {}; + data['id_makanan'] = idMakanan; + data['nama_makanan'] = namaMakanan; + data['harga_makanan'] = hargaMakanan; + data['deskripsi_makanan'] = deskripsiMakanan; + data['img_url'] = imgUrl; + return data; + } +} diff --git a/lib/model/my_model.dart b/lib/model/my_model.dart new file mode 100644 index 0000000..f3a924b --- /dev/null +++ b/lib/model/my_model.dart @@ -0,0 +1,21 @@ +class MyModel { + String? message; + bool? theBool; + dynamic data; + + MyModel({this.message, this.theBool, this.data}); + + MyModel.fromJson(Map json) { + message = json['message']; + theBool = json['bool']; + data = json['data']; + } + + Map toJson() { + final Map data = {}; + data['message'] = message; + data['bool'] = theBool; + data['data'] = this.data; + return data; + } +} diff --git a/lib/model/reservasi_meja_model.dart b/lib/model/reservasi_meja_model.dart new file mode 100644 index 0000000..1ee93ba --- /dev/null +++ b/lib/model/reservasi_meja_model.dart @@ -0,0 +1,36 @@ +class ReservasiMejaModel { + int? idMeja; + int? idUser; + String? status; + String? jamBooking; + String? createdAt; + String? updatedAt; + + ReservasiMejaModel( + {this.idMeja, + this.idUser, + this.status, + this.jamBooking, + this.createdAt, + this.updatedAt}); + + ReservasiMejaModel.fromJson(Map json) { + idMeja = json['id_meja']; + idUser = json['id_user']; + status = json['status']; + jamBooking = json['jam_booking']; + createdAt = json['created_at']; + updatedAt = json['updated_at']; + } + + Map toJson() { + final Map data = {}; + data['id_meja'] = idMeja; + data['id_user'] = idUser; + data['status'] = status; + data['jam_booking'] = jamBooking; + data['created_at'] = createdAt; + data['updated_at'] = updatedAt; + return data; + } +} diff --git a/lib/services/http_services.dart b/lib/services/http_services.dart index f2e4da5..8b4ff7a 100644 --- a/lib/services/http_services.dart +++ b/lib/services/http_services.dart @@ -6,7 +6,7 @@ import '../app/app.logger.dart'; class MyHttpServices { final log = getLogger('MyHttpServices'); final _options = BaseOptions( - baseUrl: dotenv.env['api_url']!, + baseUrl: dotenv.env['url']!, connectTimeout: const Duration(seconds: 120), receiveTimeout: const Duration(seconds: 120), ); diff --git a/lib/services/my_socket_io_client.dart b/lib/services/my_socket_io_client.dart new file mode 100644 index 0000000..8689244 --- /dev/null +++ b/lib/services/my_socket_io_client.dart @@ -0,0 +1,48 @@ +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:socket_io_client/socket_io_client.dart'; + +import '../app/app.logger.dart'; + +class MySocketIoClient { + final log = getLogger('MySocketIoClient'); + final String _url = dotenv.env['url']!; + static final MySocketIoClient _instance = MySocketIoClient._internal(); + factory MySocketIoClient() => _instance; + MySocketIoClient._internal(); + + late Socket _socket; + Socket get socket => _socket; + + Future init() async { + try { + _socket = io(_url, { + 'transports': ['websocket'], + 'autoConnect': false, + }); + _socket.connect(); + log.i('socket connected'); + } catch (e) { + log.e('error : $e'); + } + } + + Future emit(String event, dynamic data) async { + _socket.emit(event, data); + } + + Future on(String event, Function(dynamic) callback) async { + _socket.on(event, callback); + } + + Future off(String event) async { + _socket.off(event); + } + + Future disconnect() async { + _socket.disconnect(); + } + + Future connect() async { + _socket.connect(); + } +} diff --git a/lib/ui/views/meja_detail/meja_detail_view.dart b/lib/ui/views/meja_detail/meja_detail_view.dart index c5efc0a..a8deeb9 100644 --- a/lib/ui/views/meja_detail/meja_detail_view.dart +++ b/lib/ui/views/meja_detail/meja_detail_view.dart @@ -85,9 +85,18 @@ class MejaDetailView extends StatelessWidget { style: regularTextStyle, children: [ TextSpan( - text: 'Tersedia', + text: model.theBool + ? (model.reservasiMejaModel == null + ? 'Loading' + : model.reservasiMejaModel!.status! + .toUpperCase()) + : 'Tersedia', style: regularTextStyle.copyWith( - color: Colors.green, + color: model.theBool + ? (model.reservasiMejaModel == null + ? Colors.grey + : Colors.red) + : Colors.green, fontWeight: FontWeight.bold, ), ), @@ -146,10 +155,14 @@ class MejaDetailView extends StatelessWidget { ), ), floatingActionButton: FloatingActionButton.extended( - onPressed: () {}, + onPressed: () { + if (model.theBool == false) { + model.showReservasiMeja(); + } + }, label: const Text('Pesan'), icon: const Icon(Icons.add_shopping_cart), - backgroundColor: mainColor, + backgroundColor: mainColor.withOpacity(model.theBool ? 0.5 : 1), ), floatingActionButtonAnimator: FloatingActionButtonAnimator.scaling, floatingActionButtonLocation: diff --git a/lib/ui/views/meja_detail/meja_detail_view_model.dart b/lib/ui/views/meja_detail/meja_detail_view_model.dart index 6c87c92..8e783de 100644 --- a/lib/ui/views/meja_detail/meja_detail_view_model.dart +++ b/lib/ui/views/meja_detail/meja_detail_view_model.dart @@ -1,17 +1,24 @@ +import 'package:dio/dio.dart'; +import 'package:reza_app/model/reservasi_meja_model.dart'; + import '../../../app/app.logger.dart'; import '../../../app/core/custom_base_view_model.dart'; +import '../../../model/my_model.dart'; class MejaDetailViewModel extends CustomBaseViewModel { final log = getLogger('MejaDetailViewModel'); late String mejaId; late String namaMeja; + late int idMeja; String? imgAsset; + bool theBool = false; + ReservasiMejaModel? reservasiMejaModel; Future init(String mejaId) async { - log.i('MejaDetailViewModel init'); - log.i('mejaId : $mejaId'); + // log.i('MejaDetailViewModel init'); + // log.i('mejaId : $mejaId'); this.mejaId = mejaId; globalVar.backPressed = 'backNormal'; // seperate the number from the string @@ -27,9 +34,76 @@ class MejaDetailViewModel extends CustomBaseViewModel { namaMeja = 'Meja'; imgAsset = 'assets/reza_meja_2.jpeg'; } + idMeja = number; namaMeja = '$namaMeja $number'; - log.i('imgAsset : $imgAsset'); + // log.i('imgAsset : $imgAsset'); + getData(); + } + + getData() async { + easyLoading.showLoading(); + setBusy(true); + try { + var response = await httpService.get('table/detail/$idMeja'); + log.i('response : $response'); + MyModel myModel = MyModel.fromJson(response.data); + theBool = myModel.theBool!; + + reservasiMejaModel = + theBool ? ReservasiMejaModel.fromJson(myModel.data) : null; + + log.i('reservasiMejaModel : $reservasiMejaModel'); + } catch (e) { + log.e('error : $e'); + } finally { + setBusy(false); + easyLoading.dismissLoading(); + } + } + + showReservasiMeja() async { + await dialogService + .showDialog( + title: 'Reservasi Meja', + description: 'Apakah anda ingin reservasi meja ini?', + buttonTitle: 'Ya', + cancelTitle: 'Tidak', + ) + .then((value) { + log.i('value : $value'); + if (value!.confirmed) { + reservasiMeja(); + log.i('confirmed'); + } else { + log.i('not confirmed'); + } + }); + } + + reservasiMeja() async { + easyLoading.customLoading('Melakukan reservasi meja...'); + setBusy(true); + try { + var formData = FormData.fromMap({'id_user': 1, 'status': 'booking'}); + + String path = 'table/reservation/$idMeja'; + + await httpService.postWithFormData(path, formData); + // log.i('res : $res'); + getData(); + snackbarService.showSnackbar( + message: + 'Reservasi meja berhasil\nSila Bayar Rp. 20 ribu jika tiba di cafe', + title: 'Berhasil', + duration: const Duration(seconds: 2), + ); + } catch (e) { + log.e('error : $e'); + } finally { + setBusy(false); + easyLoading.dismissLoading(); + } } } diff --git a/lib/ui/views/splash_screen/splash_screen_view_model.dart b/lib/ui/views/splash_screen/splash_screen_view_model.dart index 6938079..b91cce8 100644 --- a/lib/ui/views/splash_screen/splash_screen_view_model.dart +++ b/lib/ui/views/splash_screen/splash_screen_view_model.dart @@ -1,9 +1,14 @@ import 'package:reza_app/app/app.router.dart'; import 'package:reza_app/app/core/custom_base_view_model.dart'; +import '../../../app/app.locator.dart'; +import '../../../services/my_socket_io_client.dart'; + class SplashScreenViewModel extends CustomBaseViewModel { + final socketIoClient = locator(); Future init() async { // after 2 second, navigate to login page + socketIoClient.init(); await Future.delayed(const Duration(seconds: 2)); await navigationService.navigateToLoginUserView(); } diff --git a/lib/ui/views/user_ui/akun_user/akun_user_view.dart b/lib/ui/views/user_ui/akun_user/akun_user_view.dart index 742da50..fe97a33 100644 --- a/lib/ui/views/user_ui/akun_user/akun_user_view.dart +++ b/lib/ui/views/user_ui/akun_user/akun_user_view.dart @@ -62,8 +62,8 @@ class AkunUserView extends StatelessWidget { Center( child: ClipRRect( borderRadius: BorderRadius.circular(150), - child: Image.network( - 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium', + child: Image.asset( + 'assets/nasi_goreng.jpg', height: 150, width: 150, fit: BoxFit.fill, diff --git a/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart b/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart index 86bae22..92ab6b9 100644 --- a/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart +++ b/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:reza_app/model/makanan_model.dart'; import 'package:stacked/stacked.dart'; import '../../../../../app/themes/app_colors.dart'; @@ -8,8 +10,12 @@ import '../../../../widgets/my_white_container.dart'; import './detail_makanan_view_model.dart'; class DetailMakananView extends HookWidget { - const DetailMakananView({Key? key}) : super(key: key); + final MakananModel makananModel; + const DetailMakananView({ + Key? key, + required this.makananModel, + }) : super(key: key); @override Widget build(BuildContext context) { final scrollController = useScrollController(); @@ -21,7 +27,7 @@ class DetailMakananView extends HookWidget { return ViewModelBuilder.reactive( viewModelBuilder: () => DetailMakananViewModel(), onViewModelReady: (DetailMakananViewModel model) async { - await model.init(); + await model.init(makananModel); }, builder: ( BuildContext context, @@ -127,7 +133,9 @@ class DetailMakananView extends HookWidget { ), // bikin dummy text tentang nasi goreng Text( - "Nasi goreng adalah makanan yang terbuat dari nasi yang digoreng dan diaduk dalam minyak goreng atau margarin, biasanya ditambah kecap manis, bawang merah, bawang putih, daging ayam, telur, dan bumbu-bumbu lainnya. Nasi goreng sering dianggap sebagai makanan nasional Indonesia. Nasi goreng dapat ditemukan di seluruh Indonesia, dari restoran pinggir jalan, warung, hingga hotel bintang lima dan restoran mewah.", + model.isBusy + ? 'Loading...' + : model.makananModel!.deskripsiMakanan!, style: regularTextStyle.copyWith( fontSize: 13, color: fontGrey, @@ -184,7 +192,9 @@ class DetailMakananView extends HookWidget { height: 5, ), Text( - "Rp. 35.000", + model.isBusy + ? 'Loading...' + : 'Rp. ${int.parse(makananModel.hargaMakanan!) + 10000}', style: boldTextStyle.copyWith( fontSize: 16, color: dangerColor, @@ -342,7 +352,9 @@ class SecondWidget extends ViewModelWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Burger King Handcrafted Burgers ", + viewModel.isBusy + ? 'Loading...' + : viewModel.makananModel!.namaMakanan!, style: regularTextStyle.copyWith( fontSize: 17, ), @@ -351,7 +363,9 @@ class SecondWidget extends ViewModelWidget { height: 10, ), Text( - "Rp. 25.000", + viewModel.isBusy + ? 'Loading...' + : 'Rp .${viewModel.makananModel!.hargaMakanan!}', style: regularTextStyle.copyWith( fontSize: 18, color: dangerColor, @@ -405,37 +419,38 @@ class TopMenuWidget extends ViewModelWidget { return Stack( children: [ SizedBox( - width: double.infinity, - height: MediaQuery.of(context).size.height * 0.35, - child: Image.network( - 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium', - fit: BoxFit.cover, - ), - ), - Positioned( - bottom: 10, - right: 10, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 5, - ), - // width: 20, - height: 20, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - ), - child: const Center( - child: Text( - '1 / 2', - style: TextStyle( - color: fontGrey, - fontSize: 12, - ), - ), - ), - ), - ), + width: double.infinity, + height: MediaQuery.of(context).size.height * 0.35, + child: viewModel.isBusy + ? const Center(child: CircularProgressIndicator()) + : Image.network( + '${dotenv.env['url']}assets/makanan/${viewModel.makananModel!.imgUrl}', + fit: BoxFit.cover, + )), + // Positioned( + // bottom: 10, + // right: 10, + // child: Container( + // padding: const EdgeInsets.symmetric( + // horizontal: 5, + // ), + // // width: 20, + // height: 20, + // decoration: BoxDecoration( + // color: Colors.white, + // borderRadius: BorderRadius.circular(10), + // ), + // child: const Center( + // child: Text( + // '1 / 2', + // style: TextStyle( + // color: fontGrey, + // fontSize: 12, + // ), + // ), + // ), + // ), + // ), ], ); } diff --git a/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view_model.dart b/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view_model.dart index d49cd4b..ed3264a 100644 --- a/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view_model.dart +++ b/lib/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view_model.dart @@ -1,10 +1,16 @@ +import 'package:reza_app/model/makanan_model.dart'; + import '../../../../../app/app.logger.dart'; import '../../../../../app/core/custom_base_view_model.dart'; class DetailMakananViewModel extends CustomBaseViewModel { final log = getLogger('DetailMakananViewModel'); + MakananModel? makananModel; - Future init() async { + Future init(MakananModel makananModel) async { + setBusy(true); globalVar.backPressed = 'backNormal'; + this.makananModel = makananModel; + setBusy(false); } } diff --git a/lib/ui/views/user_ui/makanan_list/makanan_list_view.dart b/lib/ui/views/user_ui/makanan_list/makanan_list_view.dart index e3d4f7f..bf01cff 100644 --- a/lib/ui/views/user_ui/makanan_list/makanan_list_view.dart +++ b/lib/ui/views/user_ui/makanan_list/makanan_list_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:reza_app/ui/widgets/my_textformfield.dart'; import 'package:reza_app/ui/widgets/my_white_container.dart'; import 'package:stacked/stacked.dart'; @@ -147,66 +148,95 @@ class MakananListView extends StatelessWidget { height: 10, ), Expanded( - child: Center( - child: SingleChildScrollView( - child: Wrap( - spacing: 10, - runSpacing: 10, - children: [ - for (var i = 0; i < 10; i++) - GestureDetector( - onTap: () => model.goToDetailMakanan(), - child: Container( - width: MediaQuery.of(context).size.width * 0.46, - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Image.network( - 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium', - height: 150, - width: double.infinity, - fit: BoxFit.fill, - ), - const SizedBox( - height: 5, - ), - const Padding( - padding: EdgeInsets.only( - left: 5, - ), - child: Text( - 'Product Name', - style: TextStyle( - fontWeight: FontWeight.bold, + child: model.isBusy + ? const Center( + child: CircularProgressIndicator(), + ) + : (model.listMakanan.isEmpty + ? const Center( + child: Text('Data Kosong'), + ) + : SingleChildScrollView( + child: Wrap( + spacing: 5, + runSpacing: 10, + // alignment: WrapAlignment.spaceAround, + // crossAxisAlignment: WrapCrossAlignment.center, + children: [ + for (var i = 0; + i < model.listMakanan.length; + i++) + GestureDetector( + onTap: () => model.goToDetailMakanan( + model.listMakanan[i]), + child: Padding( + padding: const EdgeInsets.only( + left: 10, + // right: 5, + ), + child: Container( + width: MediaQuery.of(context) + .size + .width * + 0.46, + color: Colors.white, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Image.network( + '${dotenv.env['url']}assets/makanan/${model.listMakanan[i].imgUrl}', + height: 150, + width: double.infinity, + fit: BoxFit.fill, + ), + // Image.asset( + // 'assets/nasi_goreng.jpg', + // height: 150, + // width: double.infinity, + // fit: BoxFit.fill, + // ), + const SizedBox( + height: 5, + ), + Padding( + padding: const EdgeInsets.only( + left: 5, + ), + child: Text( + model.listMakanan[i] + .namaMakanan!, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox( + height: 5, + ), + Padding( + padding: const EdgeInsets.only( + left: 5, + ), + child: Text( + model.listMakanan[i] + .deskripsiMakanan!, + style: const TextStyle( + color: Colors.grey, + ), + ), + ), + const SizedBox( + height: 5, + ), + ], + ), ), ), ), - const SizedBox( - height: 5, - ), - const Padding( - padding: EdgeInsets.only( - left: 5, - ), - child: Text( - 'Rp. 100.000', - style: TextStyle( - color: Colors.grey, - ), - ), - ), - const SizedBox( - height: 5, - ), - ], - ), + ], ), - ), - ], - ), - ), - ), + )), ), ], ), diff --git a/lib/ui/views/user_ui/makanan_list/makanan_list_view_model.dart b/lib/ui/views/user_ui/makanan_list/makanan_list_view_model.dart index 7c11af3..c5caad7 100644 --- a/lib/ui/views/user_ui/makanan_list/makanan_list_view_model.dart +++ b/lib/ui/views/user_ui/makanan_list/makanan_list_view_model.dart @@ -1,15 +1,50 @@ +import '../../../../app/app.locator.dart'; import '../../../../app/app.logger.dart'; import '../../../../app/app.router.dart'; import '../../../../app/core/custom_base_view_model.dart'; +import '../../../../model/makanan_model.dart'; +import '../../../../model/my_model.dart'; +import '../../../../services/my_socket_io_client.dart'; class MakananListViewModel extends CustomBaseViewModel { final log = getLogger('MakananListViewModel'); + final socketIoClient = locator(); + List listMakanan = []; Future init() async { globalVar.backPressed = 'exitApp'; + getData(); + socketIoClient.on('makanan_user', (data) { + log.i('data : $data'); + listMakanan.clear(); + getData(); + // webViewController!.reload(); + }); } - goToDetailMakanan() { + getData() async { + setBusy(true); + easyLoading.showLoading(); + try { + var res = await httpService.get('table/makanan'); + MyModel myModel = MyModel.fromJson(res.data); + + if (myModel.data.length > 0) { + for (var item in myModel.data) { + listMakanan.add(MakananModel.fromJson(item)); + } + } + log.i(listMakanan); + } catch (e) { + log.e(e.toString()); + } finally { + easyLoading.dismissLoading(); + setBusy(false); + } + } + + goToDetailMakanan(MakananModel makananModel) { log.i('goToDetailMakanan'); - navigationService.navigateTo(Routes.detailMakananView); + navigationService.navigateTo(Routes.detailMakananView, + arguments: DetailMakananViewArguments(makananModel: makananModel)); } } diff --git a/lib/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart b/lib/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart index ee32c5d..e650522 100644 --- a/lib/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart +++ b/lib/ui/views/user_ui/pesanan_list/keranjang_saya/keranjang_saya_view.dart @@ -72,8 +72,8 @@ class KeranjangSayaView extends StatelessWidget { ), child: ClipRRect( borderRadius: BorderRadius.circular(10), - child: Image.network( - 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium', + child: Image.asset( + 'assets/nasi_goreng.jpg', height: 150, width: double.infinity, fit: BoxFit.fill, diff --git a/lib/ui/views/user_ui/pesanan_list/pesanan_list_view.dart b/lib/ui/views/user_ui/pesanan_list/pesanan_list_view.dart index 78f2ef3..e631727 100644 --- a/lib/ui/views/user_ui/pesanan_list/pesanan_list_view.dart +++ b/lib/ui/views/user_ui/pesanan_list/pesanan_list_view.dart @@ -157,8 +157,8 @@ class PesananListView extends StatelessWidget { ), child: ClipRRect( borderRadius: BorderRadius.circular(10), - child: Image.network( - 'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium', + child: Image.asset( + 'assets/nasi_goreng.jpg', height: 100, width: double.infinity, fit: BoxFit.fill, diff --git a/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart b/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart index f8fb427..bcd9c6f 100644 --- a/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart +++ b/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart @@ -104,16 +104,14 @@ class ReservasiMejaView extends StatelessWidget { ), ), Expanded( + // child: SizedBox(), child: WebView( initialUrl: dotenv.env['table_url'], // initialUrl: 'http://172.29.85.181/parkir/user', // initialUrl: 'https://rekam-medis.airlangga-it.com/', javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { - // _controller.complete(webViewController); - // model.controllerCompleter.future - // .then((value) => model.webViewController = value); - // model.controllerCompleter.complete(webViewController); + model.webViewController = webViewController; }, onProgress: (int progress) { // model.log.i('WebView is loading (progress : $progress%)'); @@ -196,19 +194,19 @@ class ReservasiMejaView extends StatelessWidget { ), ), const SizedBox(width: 5), - const Text('Tidak Tersedia'), + const Text('Dibooking'), const SizedBox(width: 10), Container( width: 20, height: 20, decoration: const BoxDecoration( - color: Colors.blue, + color: Colors.grey, shape: BoxShape.circle, ), ), const SizedBox(width: 5), - const Text('Dipesan'), + const Text('Tidak Tersedia'), const SizedBox(width: 10), ], ), diff --git a/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view_model.dart b/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view_model.dart index e69669e..5d4ad87 100644 --- a/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view_model.dart +++ b/lib/ui/views/user_ui/reservasi_meja/reservasi_meja_view_model.dart @@ -1,10 +1,16 @@ import 'dart:async'; +import 'package:webview_flutter/webview_flutter.dart'; + +import '../../../../app/app.locator.dart'; import '../../../../app/app.logger.dart'; import '../../../../app/core/custom_base_view_model.dart'; +import '../../../../services/my_socket_io_client.dart'; class ReservasiMejaViewModel extends CustomBaseViewModel { final log = getLogger('ReservasiMejaViewModel'); + WebViewController? webViewController; + final socketIoClient = locator(); List imagePaths = [ 'assets/reza_gazebo.jpeg', @@ -14,5 +20,10 @@ class ReservasiMejaViewModel extends CustomBaseViewModel { Future init() async { globalVar.backPressed = 'exitApp'; + socketIoClient.on('table_admin', (data) { + log.i('data : $data'); + // getData(); + webViewController!.reload(); + }); } } diff --git a/pubspec.lock b/pubspec.lock index 8c756b3..85531d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.4" file_selector_linux: dependency: transitive description: @@ -773,6 +773,22 @@ packages: description: flutter source: sdk version: "0.0.99" + socket_io_client: + dependency: "direct main" + description: + name: socket_io_client + sha256: ede469f3e4c55e8528b4e023bdedbc20832e8811ab9b61679d1ba3ed5f01f23b + url: "https://pub.dev" + source: hosted + version: "2.0.3+1" + socket_io_common: + dependency: transitive + description: + name: socket_io_common + sha256: "2ab92f8ff3ebbd4b353bf4a98bee45cc157e3255464b2f90f66e09c4472047eb" + url: "https://pub.dev" + source: hosted + version: "2.0.3" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e326879..2519a2b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,6 +55,7 @@ dependencies: flutter_hooks: ^0.19.0 webview_flutter: ^3.0.4 carousel_slider: ^4.2.1 + socket_io_client: dev_dependencies: flutter_test: @@ -88,6 +89,7 @@ flutter: - assets/reza_gazebo.jpeg - assets/reza_meja_1.jpeg - assets/reza_meja_2.jpeg + - assets/nasi_goreng.jpg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see